if_pfsync.c revision 165632
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 165632 2006-12-29 13:59:50Z jhb $	*/
2145836Smlaier/*	$OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $	*/
3126258Smlaier
4126258Smlaier/*
5126258Smlaier * Copyright (c) 2002 Michael Shalayeff
6126258Smlaier * All rights reserved.
7126258Smlaier *
8126258Smlaier * Redistribution and use in source and binary forms, with or without
9126258Smlaier * modification, are permitted provided that the following conditions
10126258Smlaier * are met:
11126258Smlaier * 1. Redistributions of source code must retain the above copyright
12126258Smlaier *    notice, this list of conditions and the following disclaimer.
13126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright
14126258Smlaier *    notice, this list of conditions and the following disclaimer in the
15126258Smlaier *    documentation and/or other materials provided with the distribution.
16126258Smlaier *
17126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE.
28126258Smlaier */
29126258Smlaier
30127145Smlaier#ifdef __FreeBSD__
31126261Smlaier#include "opt_inet.h"
32126261Smlaier#include "opt_inet6.h"
33126261Smlaier#endif
34126261Smlaier
35127145Smlaier#ifndef __FreeBSD__
36126258Smlaier#include "bpfilter.h"
37126258Smlaier#include "pfsync.h"
38126261Smlaier#elif __FreeBSD__ >= 5
39126261Smlaier#include "opt_bpf.h"
40126261Smlaier#include "opt_pf.h"
41153110Sru
42153110Sru#ifdef DEV_BPF
43127145Smlaier#define	NBPFILTER	DEV_BPF
44153110Sru#else
45153110Sru#define	NBPFILTER	0
46153110Sru#endif
47153110Sru
48153110Sru#ifdef DEV_PFSYNC
49127145Smlaier#define	NPFSYNC		DEV_PFSYNC
50153110Sru#else
51153110Sru#define	NPFSYNC		0
52126261Smlaier#endif
53126258Smlaier
54153110Sru#endif
55153110Sru
56126258Smlaier#include <sys/param.h>
57164033Srwatson#ifdef __FreeBSD__
58164033Srwatson#include <sys/priv.h>
59164033Srwatson#endif
60130613Smlaier#include <sys/proc.h>
61126258Smlaier#include <sys/systm.h>
62126258Smlaier#include <sys/time.h>
63126258Smlaier#include <sys/mbuf.h>
64126258Smlaier#include <sys/socket.h>
65145836Smlaier#include <sys/kernel.h>
66127145Smlaier#ifdef __FreeBSD__
67145836Smlaier#include <sys/endian.h>
68126261Smlaier#include <sys/malloc.h>
69129907Smlaier#include <sys/module.h>
70126261Smlaier#include <sys/sockio.h>
71130613Smlaier#include <sys/lock.h>
72130613Smlaier#include <sys/mutex.h>
73148015Smlaier#include <sys/sysctl.h>
74126261Smlaier#else
75126258Smlaier#include <sys/ioctl.h>
76126258Smlaier#include <sys/timeout.h>
77126261Smlaier#endif
78126258Smlaier
79126258Smlaier#include <net/if.h>
80130933Sbrooks#if defined(__FreeBSD__)
81130933Sbrooks#include <net/if_clone.h>
82130933Sbrooks#endif
83126258Smlaier#include <net/if_types.h>
84126258Smlaier#include <net/route.h>
85126258Smlaier#include <net/bpf.h>
86145836Smlaier#include <netinet/tcp.h>
87145836Smlaier#include <netinet/tcp_seq.h>
88126258Smlaier
89126258Smlaier#ifdef	INET
90126258Smlaier#include <netinet/in.h>
91130613Smlaier#include <netinet/in_systm.h>
92126258Smlaier#include <netinet/in_var.h>
93130613Smlaier#include <netinet/ip.h>
94130613Smlaier#include <netinet/ip_var.h>
95126258Smlaier#endif
96126258Smlaier
97126258Smlaier#ifdef INET6
98126258Smlaier#ifndef INET
99126258Smlaier#include <netinet/in.h>
100126258Smlaier#endif
101126258Smlaier#include <netinet6/nd6.h>
102126258Smlaier#endif /* INET6 */
103126258Smlaier
104145836Smlaier#ifdef __FreeBSD__
105145836Smlaier#include "opt_carp.h"
106145836Smlaier#ifdef DEV_CARP
107145836Smlaier#define	NCARP	1
108159656Smlaier#else
109159656Smlaier#define	NCARP	0
110145836Smlaier#endif
111145836Smlaier#else
112145836Smlaier#include "carp.h"
113145836Smlaier#endif
114145836Smlaier#if NCARP > 0
115145836Smlaierextern int carp_suppress_preempt;
116145836Smlaier#endif
117145836Smlaier
118126258Smlaier#include <net/pfvar.h>
119126258Smlaier#include <net/if_pfsync.h>
120126258Smlaier
121127145Smlaier#ifdef __FreeBSD__
122127145Smlaier#define	PFSYNCNAME	"pfsync"
123126261Smlaier#endif
124126261Smlaier
125126258Smlaier#define PFSYNC_MINMTU	\
126126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
127126258Smlaier
128126258Smlaier#ifdef PFSYNCDEBUG
129126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
130126258Smlaierint pfsyncdebug;
131126258Smlaier#else
132126258Smlaier#define DPRINTF(x)
133126258Smlaier#endif
134126258Smlaier
135127145Smlaier#ifndef __FreeBSD__
136130613Smlaierstruct pfsync_softc	pfsyncif;
137126261Smlaier#endif
138130613Smlaierstruct pfsyncstats	pfsyncstats;
139127145Smlaier#ifdef __FreeBSD__
140148015SmlaierSYSCTL_DECL(_net_inet_pfsync);
141148015SmlaierSYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
142148015Smlaier    &pfsyncstats, pfsyncstats,
143148015Smlaier    "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
144130613Smlaier
145130613Smlaier/*
146130613Smlaier * Locking notes:
147130613Smlaier * Whenever we really touch/look at the state table we have to hold the
148130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per
149130613Smlaier * softc lock instead.
150130613Smlaier *
151130613Smlaier */
152130613Smlaier
153128209Sbrooksstatic void	pfsync_clone_destroy(struct ifnet *);
154160195Ssamstatic int	pfsync_clone_create(struct if_clone *, int, caddr_t params);
155147261Smlaierstatic void	pfsync_senddef(void *);
156126261Smlaier#else
157126258Smlaiervoid	pfsyncattach(int);
158126261Smlaier#endif
159130613Smlaiervoid	pfsync_setmtu(struct pfsync_softc *, int);
160130613Smlaierint	pfsync_insert_net_state(struct pfsync_state *);
161126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
162130613Smlaier	    struct rtentry *);
163126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
164126258Smlaiervoid	pfsyncstart(struct ifnet *);
165126258Smlaier
166130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
167130613Smlaierint	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
168130613Smlaierint	pfsync_sendout(struct pfsync_softc *);
169130613Smlaiervoid	pfsync_timeout(void *);
170130613Smlaiervoid	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
171130613Smlaiervoid	pfsync_bulk_update(void *);
172130613Smlaiervoid	pfsync_bulkfail(void *);
173126258Smlaier
174145836Smlaierint	pfsync_sync_ok;
175127145Smlaier#ifndef __FreeBSD__
176126258Smlaierextern int ifqmaxlen;
177130613Smlaierextern struct timeval time;
178130613Smlaierextern struct timeval mono_time;
179130613Smlaierextern int hz;
180126261Smlaier#endif
181126258Smlaier
182127145Smlaier#ifdef __FreeBSD__
183126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
184126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
185147256Sbrooks#define	SCP2IFP(sc)		((sc)->sc_ifp)
186130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1);
187126261Smlaier
188128209Sbrooksstatic void
189126261Smlaierpfsync_clone_destroy(struct ifnet *ifp)
190126261Smlaier{
191126261Smlaier        struct pfsync_softc *sc;
192126261Smlaier
193130613Smlaier	sc = ifp->if_softc;
194126261Smlaier	callout_stop(&sc->sc_tmo);
195130613Smlaier	callout_stop(&sc->sc_bulk_tmo);
196130613Smlaier	callout_stop(&sc->sc_bulkfail_tmo);
197126261Smlaier
198147261Smlaier	callout_stop(&sc->sc_send_tmo);
199147261Smlaier
200126261Smlaier#if NBPFILTER > 0
201126261Smlaier        bpfdetach(ifp);
202126261Smlaier#endif
203126261Smlaier        if_detach(ifp);
204147256Sbrooks	if_free(ifp);
205126261Smlaier        LIST_REMOVE(sc, sc_next);
206160164Smlaier        free(sc->sc_imo.imo_membership, M_PFSYNC);
207126261Smlaier        free(sc, M_PFSYNC);
208126261Smlaier}
209126261Smlaier
210128209Sbrooksstatic int
211160195Ssam#ifdef __FreeBSD__
212160195Ssampfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params)
213160195Ssam#else
214126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
215160195Ssam#endif
216126261Smlaier{
217126261Smlaier	struct pfsync_softc *sc;
218130613Smlaier	struct ifnet *ifp;
219126261Smlaier
220126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
221130613Smlaier	    M_WAITOK|M_ZERO);
222147256Sbrooks	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
223147256Sbrooks	if (ifp == NULL) {
224147256Sbrooks		free(sc, M_PFSYNC);
225147256Sbrooks		return (ENOSPC);
226147256Sbrooks	}
227126261Smlaier
228130613Smlaier	pfsync_sync_ok = 1;
229130613Smlaier	sc->sc_mbuf = NULL;
230130613Smlaier	sc->sc_mbuf_net = NULL;
231130613Smlaier	sc->sc_statep.s = NULL;
232130613Smlaier	sc->sc_statep_net.s = NULL;
233130613Smlaier	sc->sc_maxupdates = 128;
234159603Smlaier	sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
235130613Smlaier	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
236130613Smlaier	sc->sc_ureq_received = 0;
237130613Smlaier	sc->sc_ureq_sent = 0;
238160164Smlaier	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
239160164Smlaier	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC,
240160164Smlaier	    M_WAITOK);
241160164Smlaier	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
242130613Smlaier
243141584Smlaier	ifp = SCP2IFP(sc);
244130613Smlaier	if_initname(ifp, ifc->ifc_name, unit);
245130613Smlaier	ifp->if_ioctl = pfsyncioctl;
246130613Smlaier	ifp->if_output = pfsyncoutput;
247130613Smlaier	ifp->if_start = pfsyncstart;
248130613Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
249130613Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
250130613Smlaier	ifp->if_baudrate = IF_Mbps(100);
251130613Smlaier	ifp->if_softc = sc;
252126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
253147321Smlaier	callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
254147321Smlaier	callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
255147321Smlaier	callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
256147321Smlaier	callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
257147614Smlaier	sc->sc_ifq.ifq_maxlen = ifqmaxlen;
258147261Smlaier	mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
259147261Smlaier	    MTX_DEF);
260141584Smlaier	if_attach(ifp);
261126261Smlaier
262126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
263126261Smlaier#if NBPFILTER > 0
264141584Smlaier	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
265126261Smlaier#endif
266126261Smlaier
267126261Smlaier	return (0);
268126261Smlaier}
269126261Smlaier#else /* !__FreeBSD__ */
270126261Smlaiervoid
271126258Smlaierpfsyncattach(int npfsync)
272126258Smlaier{
273126258Smlaier	struct ifnet *ifp;
274126258Smlaier
275130613Smlaier	pfsync_sync_ok = 1;
276130613Smlaier	bzero(&pfsyncif, sizeof(pfsyncif));
277126258Smlaier	pfsyncif.sc_mbuf = NULL;
278130613Smlaier	pfsyncif.sc_mbuf_net = NULL;
279130613Smlaier	pfsyncif.sc_statep.s = NULL;
280130613Smlaier	pfsyncif.sc_statep_net.s = NULL;
281130613Smlaier	pfsyncif.sc_maxupdates = 128;
282145836Smlaier	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
283130613Smlaier	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
284130613Smlaier	pfsyncif.sc_ureq_received = 0;
285130613Smlaier	pfsyncif.sc_ureq_sent = 0;
286126258Smlaier	ifp = &pfsyncif.sc_if;
287126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
288126258Smlaier	ifp->if_softc = &pfsyncif;
289126258Smlaier	ifp->if_ioctl = pfsyncioctl;
290126258Smlaier	ifp->if_output = pfsyncoutput;
291126258Smlaier	ifp->if_start = pfsyncstart;
292126258Smlaier	ifp->if_type = IFT_PFSYNC;
293126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
294126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
295126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
296126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
297130613Smlaier	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
298130613Smlaier	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
299126258Smlaier	if_attach(ifp);
300126258Smlaier	if_alloc_sadl(ifp);
301126258Smlaier
302126258Smlaier#if NBPFILTER > 0
303126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
304126258Smlaier#endif
305126258Smlaier}
306126261Smlaier#endif
307126258Smlaier
308126258Smlaier/*
309126258Smlaier * Start output on the pfsync interface.
310126258Smlaier */
311126258Smlaiervoid
312126258Smlaierpfsyncstart(struct ifnet *ifp)
313126258Smlaier{
314130613Smlaier#ifdef __FreeBSD__
315130613Smlaier	IF_LOCK(&ifp->if_snd);
316130613Smlaier	_IF_DROP(&ifp->if_snd);
317130613Smlaier	_IF_DRAIN(&ifp->if_snd);
318130613Smlaier	IF_UNLOCK(&ifp->if_snd);
319130613Smlaier#else
320126258Smlaier	struct mbuf *m;
321126258Smlaier	int s;
322126258Smlaier
323126258Smlaier	for (;;) {
324126258Smlaier		s = splimp();
325126258Smlaier		IF_DROP(&ifp->if_snd);
326126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
327126258Smlaier		splx(s);
328126258Smlaier
329126258Smlaier		if (m == NULL)
330126258Smlaier			return;
331126258Smlaier		else
332126258Smlaier			m_freem(m);
333126258Smlaier	}
334130613Smlaier#endif
335126258Smlaier}
336126258Smlaier
337126258Smlaierint
338130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp)
339130613Smlaier{
340130613Smlaier	struct pf_state	*st = NULL;
341130613Smlaier	struct pf_rule *r = NULL;
342130613Smlaier	struct pfi_kif	*kif;
343130613Smlaier
344130613Smlaier#ifdef __FreeBSD__
345130613Smlaier	PF_ASSERT(MA_OWNED);
346130613Smlaier#endif
347130613Smlaier	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
348130613Smlaier		printf("pfsync_insert_net_state: invalid creator id:"
349130613Smlaier		    " %08x\n", ntohl(sp->creatorid));
350130613Smlaier		return (EINVAL);
351130613Smlaier	}
352130613Smlaier
353130613Smlaier	kif = pfi_lookup_create(sp->ifname);
354130613Smlaier	if (kif == NULL) {
355130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
356130613Smlaier			printf("pfsync_insert_net_state: "
357130613Smlaier			    "unknown interface: %s\n", sp->ifname);
358130613Smlaier		/* skip this state */
359130613Smlaier		return (0);
360130613Smlaier	}
361130613Smlaier
362130613Smlaier	/*
363130613Smlaier	 * Just use the default rule until we have infrastructure to find the
364130613Smlaier	 * best matching rule.
365130613Smlaier	 */
366130613Smlaier	r = &pf_default_rule;
367130613Smlaier
368130613Smlaier	if (!r->max_states || r->states < r->max_states)
369130613Smlaier		st = pool_get(&pf_state_pl, PR_NOWAIT);
370130613Smlaier	if (st == NULL) {
371130613Smlaier		pfi_maybe_destroy(kif);
372130613Smlaier		return (ENOMEM);
373130613Smlaier	}
374130613Smlaier	bzero(st, sizeof(*st));
375130613Smlaier
376130613Smlaier	st->rule.ptr = r;
377130613Smlaier	/* XXX get pointers to nat_rule and anchor */
378130613Smlaier
379145836Smlaier	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
380145836Smlaier	r->states++;
381145836Smlaier
382130613Smlaier	/* fill in the rest of the state entry */
383130613Smlaier	pf_state_host_ntoh(&sp->lan, &st->lan);
384130613Smlaier	pf_state_host_ntoh(&sp->gwy, &st->gwy);
385130613Smlaier	pf_state_host_ntoh(&sp->ext, &st->ext);
386130613Smlaier
387130613Smlaier	pf_state_peer_ntoh(&sp->src, &st->src);
388130613Smlaier	pf_state_peer_ntoh(&sp->dst, &st->dst);
389130613Smlaier
390130613Smlaier	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
391145836Smlaier	st->creation = time_second - ntohl(sp->creation);
392130613Smlaier	st->expire = ntohl(sp->expire) + time_second;
393130613Smlaier
394130613Smlaier	st->af = sp->af;
395130613Smlaier	st->proto = sp->proto;
396130613Smlaier	st->direction = sp->direction;
397130613Smlaier	st->log = sp->log;
398130613Smlaier	st->timeout = sp->timeout;
399130613Smlaier	st->allow_opts = sp->allow_opts;
400130613Smlaier
401130613Smlaier	bcopy(sp->id, &st->id, sizeof(st->id));
402130613Smlaier	st->creatorid = sp->creatorid;
403145836Smlaier	st->sync_flags = PFSTATE_FROMSYNC;
404130613Smlaier
405130613Smlaier
406130613Smlaier	if (pf_insert_state(kif, st)) {
407130613Smlaier		pfi_maybe_destroy(kif);
408145836Smlaier		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
409145836Smlaier		r->states--;
410130613Smlaier		pool_put(&pf_state_pl, st);
411130613Smlaier		return (EINVAL);
412130613Smlaier	}
413130613Smlaier
414130613Smlaier	return (0);
415130613Smlaier}
416130613Smlaier
417130613Smlaiervoid
418130613Smlaier#ifdef __FreeBSD__
419130613Smlaierpfsync_input(struct mbuf *m, __unused int off)
420130613Smlaier#else
421130613Smlaierpfsync_input(struct mbuf *m, ...)
422130613Smlaier#endif
423130613Smlaier{
424130613Smlaier	struct ip *ip = mtod(m, struct ip *);
425130613Smlaier	struct pfsync_header *ph;
426130613Smlaier#ifdef __FreeBSD__
427130613Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
428130613Smlaier#else
429130613Smlaier	struct pfsync_softc *sc = &pfsyncif;
430130613Smlaier#endif
431130613Smlaier	struct pf_state *st, key;
432130613Smlaier	struct pfsync_state *sp;
433130613Smlaier	struct pfsync_state_upd *up;
434130613Smlaier	struct pfsync_state_del *dp;
435130613Smlaier	struct pfsync_state_clr *cp;
436130613Smlaier	struct pfsync_state_upd_req *rup;
437130613Smlaier	struct pfsync_state_bus *bus;
438130613Smlaier	struct in_addr src;
439130613Smlaier	struct mbuf *mp;
440145836Smlaier	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
441130613Smlaier
442130613Smlaier	pfsyncstats.pfsyncs_ipackets++;
443130613Smlaier
444130613Smlaier	/* verify that we have a sync interface configured */
445130613Smlaier	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
446130613Smlaier		goto done;
447130613Smlaier
448130613Smlaier	/* verify that the packet came in on the right interface */
449130613Smlaier	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
450130613Smlaier		pfsyncstats.pfsyncs_badif++;
451130613Smlaier		goto done;
452130613Smlaier	}
453130613Smlaier
454130613Smlaier	/* verify that the IP TTL is 255.  */
455130613Smlaier	if (ip->ip_ttl != PFSYNC_DFLTTL) {
456130613Smlaier		pfsyncstats.pfsyncs_badttl++;
457130613Smlaier		goto done;
458130613Smlaier	}
459130613Smlaier
460130613Smlaier	iplen = ip->ip_hl << 2;
461130613Smlaier
462130613Smlaier	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
463130613Smlaier		pfsyncstats.pfsyncs_hdrops++;
464130613Smlaier		goto done;
465130613Smlaier	}
466130613Smlaier
467130613Smlaier	if (iplen + sizeof(*ph) > m->m_len) {
468130613Smlaier		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
469130613Smlaier			pfsyncstats.pfsyncs_hdrops++;
470130613Smlaier			goto done;
471130613Smlaier		}
472130613Smlaier		ip = mtod(m, struct ip *);
473130613Smlaier	}
474130613Smlaier	ph = (struct pfsync_header *)((char *)ip + iplen);
475130613Smlaier
476130613Smlaier	/* verify the version */
477130613Smlaier	if (ph->version != PFSYNC_VERSION) {
478130613Smlaier		pfsyncstats.pfsyncs_badver++;
479130613Smlaier		goto done;
480130613Smlaier	}
481130613Smlaier
482130613Smlaier	action = ph->action;
483130613Smlaier	count = ph->count;
484130613Smlaier
485130613Smlaier	/* make sure it's a valid action code */
486130613Smlaier	if (action >= PFSYNC_ACT_MAX) {
487130613Smlaier		pfsyncstats.pfsyncs_badact++;
488130613Smlaier		goto done;
489130613Smlaier	}
490130613Smlaier
491130613Smlaier	/* Cheaper to grab this now than having to mess with mbufs later */
492130613Smlaier	src = ip->ip_src;
493130613Smlaier
494130613Smlaier	switch (action) {
495130613Smlaier	case PFSYNC_ACT_CLR: {
496145836Smlaier		struct pf_state *nexts;
497130613Smlaier		struct pfi_kif	*kif;
498130613Smlaier		u_int32_t creatorid;
499130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
500130613Smlaier		    sizeof(*cp), &offp)) == NULL) {
501130613Smlaier			pfsyncstats.pfsyncs_badlen++;
502130613Smlaier			return;
503130613Smlaier		}
504130613Smlaier		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
505130613Smlaier		creatorid = cp->creatorid;
506130613Smlaier
507130613Smlaier		s = splsoftnet();
508130613Smlaier#ifdef __FreeBSD__
509130613Smlaier		PF_LOCK();
510130613Smlaier#endif
511130613Smlaier		if (cp->ifname[0] == '\0') {
512145836Smlaier			for (st = RB_MIN(pf_state_tree_id, &tree_id);
513145836Smlaier			    st; st = nexts) {
514145836Smlaier                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
515145836Smlaier				if (st->creatorid == creatorid) {
516130613Smlaier					st->timeout = PFTM_PURGE;
517145836Smlaier					pf_purge_expired_state(st);
518145836Smlaier				}
519130613Smlaier			}
520130613Smlaier		} else {
521130613Smlaier			kif = pfi_lookup_if(cp->ifname);
522130613Smlaier			if (kif == NULL) {
523130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
524130613Smlaier					printf("pfsync_input: PFSYNC_ACT_CLR "
525130613Smlaier					    "bad interface: %s\n", cp->ifname);
526130613Smlaier				splx(s);
527130613Smlaier#ifdef __FreeBSD__
528130613Smlaier				PF_UNLOCK();
529130613Smlaier#endif
530130613Smlaier				goto done;
531130613Smlaier			}
532145836Smlaier			for (st = RB_MIN(pf_state_tree_lan_ext,
533145836Smlaier			    &kif->pfik_lan_ext); st; st = nexts) {
534145836Smlaier				nexts = RB_NEXT(pf_state_tree_lan_ext,
535145836Smlaier				    &kif->pfik_lan_ext, st);
536145836Smlaier				if (st->creatorid == creatorid) {
537130613Smlaier					st->timeout = PFTM_PURGE;
538145836Smlaier					pf_purge_expired_state(st);
539145836Smlaier				}
540130613Smlaier			}
541130613Smlaier		}
542130613Smlaier#ifdef __FreeBSD__
543130613Smlaier		PF_UNLOCK();
544130613Smlaier#endif
545130613Smlaier		splx(s);
546130613Smlaier
547130613Smlaier		break;
548130613Smlaier	}
549130613Smlaier	case PFSYNC_ACT_INS:
550130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
551130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
552130613Smlaier			pfsyncstats.pfsyncs_badlen++;
553130613Smlaier			return;
554130613Smlaier		}
555130613Smlaier
556130613Smlaier		s = splsoftnet();
557130613Smlaier#ifdef __FreeBSD__
558130613Smlaier		PF_LOCK();
559130613Smlaier#endif
560130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
561130613Smlaier		    i < count; i++, sp++) {
562130613Smlaier			/* check for invalid values */
563130613Smlaier			if (sp->timeout >= PFTM_MAX ||
564130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
565130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST ||
566130613Smlaier			    sp->direction > PF_OUT ||
567130613Smlaier			    (sp->af != AF_INET && sp->af != AF_INET6)) {
568130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
569130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_INS: "
570130613Smlaier					    "invalid value\n");
571130613Smlaier				pfsyncstats.pfsyncs_badstate++;
572130613Smlaier				continue;
573130613Smlaier			}
574130613Smlaier
575130613Smlaier			if ((error = pfsync_insert_net_state(sp))) {
576130613Smlaier				if (error == ENOMEM) {
577130613Smlaier					splx(s);
578130613Smlaier#ifdef __FreeBSD__
579130613Smlaier					PF_UNLOCK();
580130613Smlaier#endif
581130613Smlaier					goto done;
582130613Smlaier				}
583130613Smlaier				continue;
584130613Smlaier			}
585130613Smlaier		}
586130613Smlaier#ifdef __FreeBSD__
587130613Smlaier		PF_UNLOCK();
588130613Smlaier#endif
589130613Smlaier		splx(s);
590130613Smlaier		break;
591130613Smlaier	case PFSYNC_ACT_UPD:
592130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
593130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
594130613Smlaier			pfsyncstats.pfsyncs_badlen++;
595130613Smlaier			return;
596130613Smlaier		}
597130613Smlaier
598130613Smlaier		s = splsoftnet();
599130613Smlaier#ifdef __FreeBSD__
600130613Smlaier		PF_LOCK();
601130613Smlaier#endif
602130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
603130613Smlaier		    i < count; i++, sp++) {
604145836Smlaier			int flags = PFSYNC_FLAG_STALE;
605145836Smlaier
606130613Smlaier			/* check for invalid values */
607130613Smlaier			if (sp->timeout >= PFTM_MAX ||
608130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
609130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST) {
610130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
611130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_UPD: "
612130613Smlaier					    "invalid value\n");
613130613Smlaier				pfsyncstats.pfsyncs_badstate++;
614130613Smlaier				continue;
615130613Smlaier			}
616130613Smlaier
617130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
618130613Smlaier			key.creatorid = sp->creatorid;
619130613Smlaier
620130613Smlaier			st = pf_find_state_byid(&key);
621130613Smlaier			if (st == NULL) {
622130613Smlaier				/* insert the update */
623130613Smlaier				if (pfsync_insert_net_state(sp))
624130613Smlaier					pfsyncstats.pfsyncs_badstate++;
625130613Smlaier				continue;
626130613Smlaier			}
627145836Smlaier			sfail = 0;
628145836Smlaier			if (st->proto == IPPROTO_TCP) {
629145836Smlaier				/*
630145836Smlaier				 * The state should never go backwards except
631145836Smlaier				 * for syn-proxy states.  Neither should the
632145836Smlaier				 * sequence window slide backwards.
633145836Smlaier				 */
634145836Smlaier				if (st->src.state > sp->src.state &&
635145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
636145836Smlaier				    sp->src.state >= PF_TCPS_PROXY_SRC))
637145836Smlaier					sfail = 1;
638145836Smlaier				else if (SEQ_GT(st->src.seqlo,
639145836Smlaier				    ntohl(sp->src.seqlo)))
640145836Smlaier					sfail = 3;
641145836Smlaier				else if (st->dst.state > sp->dst.state) {
642145836Smlaier					/* There might still be useful
643145836Smlaier					 * information about the src state here,
644145836Smlaier					 * so import that part of the update,
645145836Smlaier					 * then "fail" so we send the updated
646145836Smlaier					 * state back to the peer who is missing
647145836Smlaier					 * our what we know. */
648145836Smlaier					pf_state_peer_ntoh(&sp->src, &st->src);
649145836Smlaier					/* XXX do anything with timeouts? */
650145836Smlaier					sfail = 7;
651145836Smlaier					flags = 0;
652145836Smlaier				} else if (st->dst.state >= TCPS_SYN_SENT &&
653145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
654145836Smlaier					sfail = 4;
655145836Smlaier			} else {
656145836Smlaier				/*
657145836Smlaier				 * Non-TCP protocol state machine always go
658145836Smlaier				 * forwards
659145836Smlaier				 */
660145836Smlaier				if (st->src.state > sp->src.state)
661145836Smlaier					sfail = 5;
662145836Smlaier				else if ( st->dst.state > sp->dst.state)
663145836Smlaier					sfail = 6;
664145836Smlaier			}
665145836Smlaier			if (sfail) {
666145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
667145836Smlaier					printf("pfsync: %s stale update "
668145836Smlaier					    "(%d) id: %016llx "
669145836Smlaier					    "creatorid: %08x\n",
670145836Smlaier					    (sfail < 7 ?  "ignoring"
671145836Smlaier					     : "partial"), sfail,
672145836Smlaier#ifdef __FreeBSD__
673145836Smlaier					    (unsigned long long)be64toh(st->id),
674145836Smlaier#else
675145836Smlaier					    betoh64(st->id),
676145836Smlaier#endif
677145836Smlaier					    ntohl(st->creatorid));
678145836Smlaier				pfsyncstats.pfsyncs_badstate++;
679145836Smlaier
680145836Smlaier				if (!(sp->sync_flags & PFSTATE_STALE)) {
681145836Smlaier					/* we have a better state, send it */
682145836Smlaier					if (sc->sc_mbuf != NULL && !stale)
683145836Smlaier						pfsync_sendout(sc);
684145836Smlaier					stale++;
685145836Smlaier					if (!st->sync_flags)
686145836Smlaier						pfsync_pack_state(
687145836Smlaier						    PFSYNC_ACT_UPD, st, flags);
688145836Smlaier				}
689145836Smlaier				continue;
690145836Smlaier			}
691130613Smlaier			pf_state_peer_ntoh(&sp->src, &st->src);
692130613Smlaier			pf_state_peer_ntoh(&sp->dst, &st->dst);
693130613Smlaier			st->expire = ntohl(sp->expire) + time_second;
694130613Smlaier			st->timeout = sp->timeout;
695130613Smlaier		}
696145836Smlaier		if (stale && sc->sc_mbuf != NULL)
697145836Smlaier			pfsync_sendout(sc);
698130613Smlaier#ifdef __FreeBSD__
699130613Smlaier		PF_UNLOCK();
700130613Smlaier#endif
701130613Smlaier		splx(s);
702130613Smlaier		break;
703130613Smlaier	/*
704130613Smlaier	 * It's not strictly necessary for us to support the "uncompressed"
705130613Smlaier	 * delete action, but it's relatively simple and maintains consistency.
706130613Smlaier	 */
707130613Smlaier	case PFSYNC_ACT_DEL:
708130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
709130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
710130613Smlaier			pfsyncstats.pfsyncs_badlen++;
711130613Smlaier			return;
712130613Smlaier		}
713130613Smlaier
714130613Smlaier		s = splsoftnet();
715130613Smlaier#ifdef __FreeBSD__
716130613Smlaier		PF_LOCK();
717130613Smlaier#endif
718130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
719130613Smlaier		    i < count; i++, sp++) {
720130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
721130613Smlaier			key.creatorid = sp->creatorid;
722130613Smlaier
723130613Smlaier			st = pf_find_state_byid(&key);
724130613Smlaier			if (st == NULL) {
725130613Smlaier				pfsyncstats.pfsyncs_badstate++;
726130613Smlaier				continue;
727130613Smlaier			}
728130613Smlaier			st->timeout = PFTM_PURGE;
729130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
730145836Smlaier			pf_purge_expired_state(st);
731130613Smlaier		}
732130613Smlaier#ifdef __FreeBSD__
733130613Smlaier		PF_UNLOCK();
734130613Smlaier#endif
735130613Smlaier		splx(s);
736130613Smlaier		break;
737130613Smlaier	case PFSYNC_ACT_UPD_C: {
738130613Smlaier		int update_requested = 0;
739130613Smlaier
740130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
741130613Smlaier		    count * sizeof(*up), &offp)) == NULL) {
742130613Smlaier			pfsyncstats.pfsyncs_badlen++;
743130613Smlaier			return;
744130613Smlaier		}
745130613Smlaier
746130613Smlaier		s = splsoftnet();
747130613Smlaier#ifdef __FreeBSD__
748130613Smlaier		PF_LOCK();
749130613Smlaier#endif
750130613Smlaier		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
751130613Smlaier		    i < count; i++, up++) {
752130613Smlaier			/* check for invalid values */
753130613Smlaier			if (up->timeout >= PFTM_MAX ||
754130613Smlaier			    up->src.state > PF_TCPS_PROXY_DST ||
755130613Smlaier			    up->dst.state > PF_TCPS_PROXY_DST) {
756130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
757130613Smlaier					printf("pfsync_insert: "
758130613Smlaier					    "PFSYNC_ACT_UPD_C: "
759130613Smlaier					    "invalid value\n");
760130613Smlaier				pfsyncstats.pfsyncs_badstate++;
761130613Smlaier				continue;
762130613Smlaier			}
763130613Smlaier
764130613Smlaier			bcopy(up->id, &key.id, sizeof(key.id));
765130613Smlaier			key.creatorid = up->creatorid;
766130613Smlaier
767130613Smlaier			st = pf_find_state_byid(&key);
768130613Smlaier			if (st == NULL) {
769130613Smlaier				/* We don't have this state. Ask for it. */
770145836Smlaier				error = pfsync_request_update(up, &src);
771145836Smlaier				if (error == ENOMEM) {
772145836Smlaier					splx(s);
773145836Smlaier					goto done;
774145836Smlaier				}
775130613Smlaier				update_requested = 1;
776130613Smlaier				pfsyncstats.pfsyncs_badstate++;
777130613Smlaier				continue;
778130613Smlaier			}
779145836Smlaier			sfail = 0;
780145836Smlaier			if (st->proto == IPPROTO_TCP) {
781145836Smlaier				/*
782145836Smlaier				 * The state should never go backwards except
783145836Smlaier				 * for syn-proxy states.  Neither should the
784145836Smlaier				 * sequence window slide backwards.
785145836Smlaier				 */
786145836Smlaier				if (st->src.state > up->src.state &&
787145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
788145836Smlaier				    up->src.state >= PF_TCPS_PROXY_SRC))
789145836Smlaier					sfail = 1;
790145836Smlaier				else if (st->dst.state > up->dst.state)
791145836Smlaier					sfail = 2;
792145836Smlaier				else if (SEQ_GT(st->src.seqlo,
793145836Smlaier				    ntohl(up->src.seqlo)))
794145836Smlaier					sfail = 3;
795145836Smlaier				else if (st->dst.state >= TCPS_SYN_SENT &&
796145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
797145836Smlaier					sfail = 4;
798145836Smlaier			} else {
799145836Smlaier				/*
800145836Smlaier				 * Non-TCP protocol state machine always go
801145836Smlaier				 * forwards
802145836Smlaier				 */
803145836Smlaier				if (st->src.state > up->src.state)
804145836Smlaier					sfail = 5;
805145836Smlaier				else if (st->dst.state > up->dst.state)
806145836Smlaier					sfail = 6;
807145836Smlaier			}
808145836Smlaier			if (sfail) {
809145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
810145836Smlaier					printf("pfsync: ignoring stale update "
811145836Smlaier					    "(%d) id: %016llx "
812145836Smlaier					    "creatorid: %08x\n", sfail,
813145836Smlaier#ifdef __FreeBSD__
814145836Smlaier					    (unsigned long long)be64toh(st->id),
815145836Smlaier#else
816145836Smlaier					    betoh64(st->id),
817145836Smlaier#endif
818145836Smlaier					    ntohl(st->creatorid));
819145836Smlaier				pfsyncstats.pfsyncs_badstate++;
820145836Smlaier
821145836Smlaier				/* we have a better state, send it out */
822145836Smlaier				if ((!stale || update_requested) &&
823145836Smlaier				    sc->sc_mbuf != NULL) {
824145836Smlaier					pfsync_sendout(sc);
825145836Smlaier					update_requested = 0;
826145836Smlaier				}
827145836Smlaier				stale++;
828145836Smlaier				if (!st->sync_flags)
829145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD, st,
830145836Smlaier					    PFSYNC_FLAG_STALE);
831145836Smlaier				continue;
832145836Smlaier			}
833130613Smlaier			pf_state_peer_ntoh(&up->src, &st->src);
834130613Smlaier			pf_state_peer_ntoh(&up->dst, &st->dst);
835130613Smlaier			st->expire = ntohl(up->expire) + time_second;
836130613Smlaier			st->timeout = up->timeout;
837130613Smlaier		}
838145836Smlaier		if ((update_requested || stale) && sc->sc_mbuf)
839130613Smlaier			pfsync_sendout(sc);
840130613Smlaier#ifdef __FreeBSD__
841130613Smlaier		PF_UNLOCK();
842130613Smlaier#endif
843130613Smlaier		splx(s);
844130613Smlaier		break;
845130613Smlaier	}
846130613Smlaier	case PFSYNC_ACT_DEL_C:
847130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
848130613Smlaier		    count * sizeof(*dp), &offp)) == NULL) {
849130613Smlaier			pfsyncstats.pfsyncs_badlen++;
850130613Smlaier			return;
851130613Smlaier		}
852130613Smlaier
853130613Smlaier		s = splsoftnet();
854130613Smlaier#ifdef __FreeBSD__
855130613Smlaier		PF_LOCK();
856130613Smlaier#endif
857130613Smlaier		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
858130613Smlaier		    i < count; i++, dp++) {
859130613Smlaier			bcopy(dp->id, &key.id, sizeof(key.id));
860130613Smlaier			key.creatorid = dp->creatorid;
861130613Smlaier
862130613Smlaier			st = pf_find_state_byid(&key);
863130613Smlaier			if (st == NULL) {
864130613Smlaier				pfsyncstats.pfsyncs_badstate++;
865130613Smlaier				continue;
866130613Smlaier			}
867130613Smlaier			st->timeout = PFTM_PURGE;
868130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
869145836Smlaier			pf_purge_expired_state(st);
870130613Smlaier		}
871130613Smlaier#ifdef __FreeBSD__
872130613Smlaier		PF_UNLOCK();
873130613Smlaier#endif
874130613Smlaier		splx(s);
875130613Smlaier		break;
876130613Smlaier	case PFSYNC_ACT_INS_F:
877130613Smlaier	case PFSYNC_ACT_DEL_F:
878130613Smlaier		/* not implemented */
879130613Smlaier		break;
880130613Smlaier	case PFSYNC_ACT_UREQ:
881130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
882130613Smlaier		    count * sizeof(*rup), &offp)) == NULL) {
883130613Smlaier			pfsyncstats.pfsyncs_badlen++;
884130613Smlaier			return;
885130613Smlaier		}
886130613Smlaier
887130613Smlaier		s = splsoftnet();
888130613Smlaier#ifdef __FreeBSD__
889130613Smlaier		PF_LOCK();
890130613Smlaier#endif
891130613Smlaier		if (sc->sc_mbuf != NULL)
892130613Smlaier			pfsync_sendout(sc);
893130613Smlaier		for (i = 0,
894130613Smlaier		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
895130613Smlaier		    i < count; i++, rup++) {
896130613Smlaier			bcopy(rup->id, &key.id, sizeof(key.id));
897130613Smlaier			key.creatorid = rup->creatorid;
898130613Smlaier
899130613Smlaier			if (key.id == 0 && key.creatorid == 0) {
900130613Smlaier				sc->sc_ureq_received = time_uptime;
901130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
902130613Smlaier					printf("pfsync: received "
903130613Smlaier					    "bulk update request\n");
904130613Smlaier				pfsync_send_bus(sc, PFSYNC_BUS_START);
905130613Smlaier#ifdef __FreeBSD__
906130613Smlaier				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
907130613Smlaier				    pfsync_bulk_update,
908130613Smlaier				    LIST_FIRST(&pfsync_list));
909130613Smlaier#else
910130613Smlaier				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
911130613Smlaier#endif
912130613Smlaier			} else {
913130613Smlaier				st = pf_find_state_byid(&key);
914130613Smlaier				if (st == NULL) {
915130613Smlaier					pfsyncstats.pfsyncs_badstate++;
916130613Smlaier					continue;
917130613Smlaier				}
918145836Smlaier				if (!st->sync_flags)
919145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD,
920145836Smlaier					    st, 0);
921130613Smlaier			}
922130613Smlaier		}
923130613Smlaier		if (sc->sc_mbuf != NULL)
924130613Smlaier			pfsync_sendout(sc);
925130613Smlaier#ifdef __FreeBSD__
926130613Smlaier		PF_UNLOCK();
927130613Smlaier#endif
928130613Smlaier		splx(s);
929130613Smlaier		break;
930130613Smlaier	case PFSYNC_ACT_BUS:
931130613Smlaier		/* If we're not waiting for a bulk update, who cares. */
932130613Smlaier		if (sc->sc_ureq_sent == 0)
933130613Smlaier			break;
934130613Smlaier
935130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
936130613Smlaier		    sizeof(*bus), &offp)) == NULL) {
937130613Smlaier			pfsyncstats.pfsyncs_badlen++;
938130613Smlaier			return;
939130613Smlaier		}
940130613Smlaier		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
941130613Smlaier		switch (bus->status) {
942130613Smlaier		case PFSYNC_BUS_START:
943130613Smlaier#ifdef __FreeBSD__
944130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo,
945130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
946130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
947130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
948130613Smlaier#else
949130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo,
950130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
951130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
952130613Smlaier#endif
953130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
954130613Smlaier				printf("pfsync: received bulk "
955130613Smlaier				    "update start\n");
956130613Smlaier			break;
957130613Smlaier		case PFSYNC_BUS_END:
958130613Smlaier			if (time_uptime - ntohl(bus->endtime) >=
959130613Smlaier			    sc->sc_ureq_sent) {
960130613Smlaier				/* that's it, we're happy */
961130613Smlaier				sc->sc_ureq_sent = 0;
962130613Smlaier				sc->sc_bulk_tries = 0;
963130613Smlaier#ifdef __FreeBSD__
964130613Smlaier				callout_stop(&sc->sc_bulkfail_tmo);
965130613Smlaier#else
966130613Smlaier				timeout_del(&sc->sc_bulkfail_tmo);
967130613Smlaier#endif
968145836Smlaier#if NCARP > 0	/* XXX_IMPORT */
969145836Smlaier				if (!pfsync_sync_ok)
970145836Smlaier					carp_suppress_preempt--;
971145836Smlaier#endif
972130613Smlaier				pfsync_sync_ok = 1;
973130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
974130613Smlaier					printf("pfsync: received valid "
975130613Smlaier					    "bulk update end\n");
976130613Smlaier			} else {
977130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
978130613Smlaier					printf("pfsync: received invalid "
979130613Smlaier					    "bulk update end: bad timestamp\n");
980130613Smlaier			}
981130613Smlaier			break;
982130613Smlaier		}
983130613Smlaier		break;
984130613Smlaier	}
985130613Smlaier
986130613Smlaierdone:
987130613Smlaier	if (m)
988130613Smlaier		m_freem(m);
989130613Smlaier}
990130613Smlaier
991130613Smlaierint
992126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
993126258Smlaier	struct rtentry *rt)
994126258Smlaier{
995126258Smlaier	m_freem(m);
996126258Smlaier	return (0);
997126258Smlaier}
998126258Smlaier
999126258Smlaier/* ARGSUSED */
1000126258Smlaierint
1001126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1002126258Smlaier{
1003130613Smlaier#ifndef __FreeBSD__
1004130613Smlaier	struct proc *p = curproc;
1005130613Smlaier#endif
1006126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1007126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
1008130613Smlaier	struct ip_moptions *imo = &sc->sc_imo;
1009130613Smlaier	struct pfsyncreq pfsyncr;
1010130613Smlaier	struct ifnet    *sifp;
1011130613Smlaier	int s, error;
1012126258Smlaier
1013126258Smlaier	switch (cmd) {
1014126258Smlaier	case SIOCSIFADDR:
1015126258Smlaier	case SIOCAIFADDR:
1016126258Smlaier	case SIOCSIFDSTADDR:
1017126258Smlaier	case SIOCSIFFLAGS:
1018148891Smlaier#ifdef __FreeBSD__
1019126258Smlaier		if (ifp->if_flags & IFF_UP)
1020148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
1021126258Smlaier		else
1022148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1023148891Smlaier#else
1024148891Smlaier		if (ifp->if_flags & IFF_UP)
1025148891Smlaier			ifp->if_flags |= IFF_RUNNING;
1026148891Smlaier		else
1027148891Smlaier			ifp->if_flags &= ~IFF_RUNNING;
1028148891Smlaier#endif
1029126258Smlaier		break;
1030126258Smlaier	case SIOCSIFMTU:
1031126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
1032126258Smlaier			return (EINVAL);
1033126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
1034126258Smlaier			ifr->ifr_mtu = MCLBYTES;
1035126258Smlaier		s = splnet();
1036130613Smlaier#ifdef __FreeBSD__
1037130613Smlaier		PF_LOCK();
1038130613Smlaier#endif
1039130613Smlaier		if (ifr->ifr_mtu < ifp->if_mtu) {
1040126258Smlaier			pfsync_sendout(sc);
1041130613Smlaier		}
1042126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
1043130613Smlaier#ifdef __FreeBSD__
1044130613Smlaier		PF_UNLOCK();
1045130613Smlaier#endif
1046126258Smlaier		splx(s);
1047126258Smlaier		break;
1048130613Smlaier	case SIOCGETPFSYNC:
1049130613Smlaier#ifdef __FreeBSD__
1050130613Smlaier		/* XXX: read unlocked */
1051130613Smlaier#endif
1052130613Smlaier		bzero(&pfsyncr, sizeof(pfsyncr));
1053130613Smlaier		if (sc->sc_sync_ifp)
1054145836Smlaier			strlcpy(pfsyncr.pfsyncr_syncdev,
1055130613Smlaier			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
1056145836Smlaier		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1057130613Smlaier		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1058130613Smlaier		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
1059130613Smlaier			return (error);
1060130613Smlaier		break;
1061130613Smlaier	case SIOCSETPFSYNC:
1062130613Smlaier#ifdef __FreeBSD__
1063164033Srwatson		if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
1064130613Smlaier#else
1065130613Smlaier		if ((error = suser(p, p->p_acflag)) != 0)
1066130613Smlaier#endif
1067130613Smlaier			return (error);
1068130613Smlaier		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1069130613Smlaier			return (error);
1070130613Smlaier
1071145836Smlaier		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1072159603Smlaier#ifdef __FreeBSD__
1073159603Smlaier			sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
1074159603Smlaier#else
1075145836Smlaier			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1076159603Smlaier#endif
1077145836Smlaier		else
1078145836Smlaier			sc->sc_sync_peer.s_addr =
1079145836Smlaier			    pfsyncr.pfsyncr_syncpeer.s_addr;
1080145836Smlaier
1081130613Smlaier		if (pfsyncr.pfsyncr_maxupdates > 255)
1082130613Smlaier			return (EINVAL);
1083130613Smlaier#ifdef __FreeBSD__
1084147261Smlaier		callout_drain(&sc->sc_send_tmo);
1085130613Smlaier		PF_LOCK();
1086130613Smlaier#endif
1087130613Smlaier		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1088130613Smlaier
1089145836Smlaier		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1090130613Smlaier			sc->sc_sync_ifp = NULL;
1091130613Smlaier			if (sc->sc_mbuf_net != NULL) {
1092130613Smlaier				/* Don't keep stale pfsync packets around. */
1093130613Smlaier				s = splnet();
1094130613Smlaier				m_freem(sc->sc_mbuf_net);
1095130613Smlaier				sc->sc_mbuf_net = NULL;
1096130613Smlaier				sc->sc_statep_net.s = NULL;
1097130613Smlaier				splx(s);
1098130613Smlaier			}
1099145836Smlaier			if (imo->imo_num_memberships > 0) {
1100145836Smlaier				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1101145836Smlaier				imo->imo_multicast_ifp = NULL;
1102145836Smlaier			}
1103130613Smlaier#ifdef __FreeBSD__
1104130613Smlaier			PF_UNLOCK();
1105130613Smlaier#endif
1106130613Smlaier			break;
1107130613Smlaier		}
1108145836Smlaier
1109145836Smlaier		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
1110130613Smlaier#ifdef __FreeBSD__
1111130613Smlaier			PF_UNLOCK();
1112130613Smlaier#endif
1113130613Smlaier			return (EINVAL);
1114130613Smlaier		}
1115130613Smlaier
1116130613Smlaier		s = splnet();
1117141584Smlaier#ifdef __FreeBSD__
1118141584Smlaier		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
1119141584Smlaier#else
1120130613Smlaier		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1121141584Smlaier#endif
1122130613Smlaier		    (sc->sc_sync_ifp != NULL &&
1123130613Smlaier		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
1124130613Smlaier		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1125130613Smlaier			pfsync_sendout(sc);
1126130613Smlaier		sc->sc_sync_ifp = sifp;
1127130613Smlaier
1128141584Smlaier#ifdef __FreeBSD__
1129141584Smlaier		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
1130141584Smlaier#else
1131130613Smlaier		pfsync_setmtu(sc, sc->sc_if.if_mtu);
1132141584Smlaier#endif
1133130613Smlaier
1134130613Smlaier		if (imo->imo_num_memberships > 0) {
1135130613Smlaier			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1136130613Smlaier			imo->imo_multicast_ifp = NULL;
1137130613Smlaier		}
1138130613Smlaier
1139145836Smlaier		if (sc->sc_sync_ifp &&
1140159603Smlaier#ifdef __FreeBSD__
1141159603Smlaier		    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1142159603Smlaier#else
1143145836Smlaier		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1144159603Smlaier#endif
1145130613Smlaier			struct in_addr addr;
1146130613Smlaier
1147145836Smlaier			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
1148145836Smlaier				sc->sc_sync_ifp = NULL;
1149130613Smlaier#ifdef __FreeBSD__
1150145836Smlaier				PF_UNLOCK();
1151145836Smlaier#endif
1152145836Smlaier				splx(s);
1153145836Smlaier				return (EADDRNOTAVAIL);
1154145836Smlaier			}
1155145836Smlaier#ifdef __FreeBSD__
1156130613Smlaier			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
1157130613Smlaier			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1158130613Smlaier#else
1159130613Smlaier			addr.s_addr = INADDR_PFSYNC_GROUP;
1160130613Smlaier#endif
1161145836Smlaier
1162130613Smlaier			if ((imo->imo_membership[0] =
1163130613Smlaier			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
1164145836Smlaier				sc->sc_sync_ifp = NULL;
1165130613Smlaier				splx(s);
1166130613Smlaier				return (ENOBUFS);
1167130613Smlaier			}
1168130613Smlaier			imo->imo_num_memberships++;
1169130613Smlaier			imo->imo_multicast_ifp = sc->sc_sync_ifp;
1170130613Smlaier			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1171130613Smlaier			imo->imo_multicast_loop = 0;
1172149982Smlaier#ifdef __FreeBSD__
1173149982Smlaier			PF_LOCK();
1174149982Smlaier#endif
1175145836Smlaier		}
1176130613Smlaier
1177145836Smlaier		if (sc->sc_sync_ifp ||
1178159603Smlaier#ifdef __FreeBSD__
1179159603Smlaier		    sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
1180159603Smlaier#else
1181145836Smlaier		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
1182159603Smlaier#endif
1183130613Smlaier			/* Request a full state table update. */
1184130613Smlaier			sc->sc_ureq_sent = time_uptime;
1185145836Smlaier#if NCARP > 0
1186145836Smlaier			if (pfsync_sync_ok)
1187145836Smlaier				carp_suppress_preempt++;
1188130613Smlaier#endif
1189130613Smlaier			pfsync_sync_ok = 0;
1190130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1191130613Smlaier				printf("pfsync: requesting bulk update\n");
1192130613Smlaier#ifdef __FreeBSD__
1193130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1194130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
1195130613Smlaier#else
1196130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1197130613Smlaier#endif
1198145836Smlaier			error = pfsync_request_update(NULL, NULL);
1199145836Smlaier			if (error == ENOMEM) {
1200145836Smlaier#ifdef __FreeBSD__
1201145836Smlaier				PF_UNLOCK();
1202145836Smlaier#endif
1203145836Smlaier				splx(s);
1204145836Smlaier				return (ENOMEM);
1205145836Smlaier			}
1206130613Smlaier			pfsync_sendout(sc);
1207130613Smlaier		}
1208130613Smlaier#ifdef __FreeBSD__
1209130613Smlaier		PF_UNLOCK();
1210130613Smlaier#endif
1211130613Smlaier		splx(s);
1212130613Smlaier
1213130613Smlaier		break;
1214130613Smlaier
1215126258Smlaier	default:
1216126258Smlaier		return (ENOTTY);
1217126258Smlaier	}
1218126258Smlaier
1219126258Smlaier	return (0);
1220126258Smlaier}
1221126258Smlaier
1222126258Smlaiervoid
1223130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1224130613Smlaier{
1225126258Smlaier	int mtu;
1226130613Smlaier
1227130613Smlaier	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1228130613Smlaier		mtu = sc->sc_sync_ifp->if_mtu;
1229130613Smlaier	else
1230130613Smlaier		mtu = mtu_req;
1231130613Smlaier
1232130613Smlaier	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1233130613Smlaier	    sizeof(struct pfsync_state);
1234130613Smlaier	if (sc->sc_maxcount > 254)
1235130613Smlaier	    sc->sc_maxcount = 254;
1236141584Smlaier#ifdef __FreeBSD__
1237141584Smlaier	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
1238141584Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1239141584Smlaier#else
1240126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1241130613Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1242141584Smlaier#endif
1243126258Smlaier}
1244126258Smlaier
1245126258Smlaierstruct mbuf *
1246130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1247126258Smlaier{
1248126258Smlaier	struct pfsync_header *h;
1249126258Smlaier	struct mbuf *m;
1250126258Smlaier	int len;
1251126258Smlaier
1252130613Smlaier#ifdef __FreeBSD__
1253130613Smlaier	PF_ASSERT(MA_OWNED);
1254130613Smlaier#endif
1255126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
1256126258Smlaier	if (m == NULL) {
1257141584Smlaier#ifdef __FreeBSD__
1258141584Smlaier		SCP2IFP(sc)->if_oerrors++;
1259141584Smlaier#else
1260126258Smlaier		sc->sc_if.if_oerrors++;
1261141584Smlaier#endif
1262126258Smlaier		return (NULL);
1263126258Smlaier	}
1264126258Smlaier
1265130613Smlaier	switch (action) {
1266130613Smlaier	case PFSYNC_ACT_CLR:
1267130613Smlaier		len = sizeof(struct pfsync_header) +
1268130613Smlaier		    sizeof(struct pfsync_state_clr);
1269130613Smlaier		break;
1270130613Smlaier	case PFSYNC_ACT_UPD_C:
1271130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1272130613Smlaier		    sizeof(struct pfsync_header);
1273130613Smlaier		break;
1274130613Smlaier	case PFSYNC_ACT_DEL_C:
1275130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1276130613Smlaier		    sizeof(struct pfsync_header);
1277130613Smlaier		break;
1278130613Smlaier	case PFSYNC_ACT_UREQ:
1279130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1280130613Smlaier		    sizeof(struct pfsync_header);
1281130613Smlaier		break;
1282130613Smlaier	case PFSYNC_ACT_BUS:
1283130613Smlaier		len = sizeof(struct pfsync_header) +
1284130613Smlaier		    sizeof(struct pfsync_state_bus);
1285130613Smlaier		break;
1286130613Smlaier	default:
1287130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1288130613Smlaier		    sizeof(struct pfsync_header);
1289130613Smlaier		break;
1290130613Smlaier	}
1291130613Smlaier
1292126258Smlaier	if (len > MHLEN) {
1293126258Smlaier		MCLGET(m, M_DONTWAIT);
1294126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
1295126258Smlaier			m_free(m);
1296141584Smlaier#ifdef __FreeBSD__
1297141584Smlaier			SCP2IFP(sc)->if_oerrors++;
1298141584Smlaier#else
1299126258Smlaier			sc->sc_if.if_oerrors++;
1300141584Smlaier#endif
1301126258Smlaier			return (NULL);
1302126258Smlaier		}
1303130613Smlaier		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1304130613Smlaier	} else
1305130613Smlaier		MH_ALIGN(m, len);
1306130613Smlaier
1307126258Smlaier	m->m_pkthdr.rcvif = NULL;
1308130613Smlaier	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1309126258Smlaier	h = mtod(m, struct pfsync_header *);
1310126258Smlaier	h->version = PFSYNC_VERSION;
1311126258Smlaier	h->af = 0;
1312126258Smlaier	h->count = 0;
1313126258Smlaier	h->action = action;
1314126258Smlaier
1315130613Smlaier	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
1316127145Smlaier#ifdef __FreeBSD__
1317126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1318126261Smlaier	    LIST_FIRST(&pfsync_list));
1319126261Smlaier#else
1320126258Smlaier	timeout_add(&sc->sc_tmo, hz);
1321126261Smlaier#endif
1322126258Smlaier	return (m);
1323126258Smlaier}
1324126258Smlaier
1325126258Smlaierint
1326145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
1327126258Smlaier{
1328127145Smlaier#ifdef __FreeBSD__
1329141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1330126261Smlaier#else
1331126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1332130613Smlaier#endif
1333126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1334130613Smlaier	struct pfsync_header *h, *h_net;
1335130613Smlaier	struct pfsync_state *sp = NULL;
1336130613Smlaier	struct pfsync_state_upd *up = NULL;
1337130613Smlaier	struct pfsync_state_del *dp = NULL;
1338130613Smlaier	struct pf_rule *r;
1339126258Smlaier	u_long secs;
1340130613Smlaier	int s, ret = 0;
1341130613Smlaier	u_int8_t i = 255, newaction = 0;
1342126258Smlaier
1343130613Smlaier#ifdef __FreeBSD__
1344130613Smlaier	PF_ASSERT(MA_OWNED);
1345130613Smlaier#endif
1346130613Smlaier	/*
1347130613Smlaier	 * If a packet falls in the forest and there's nobody around to
1348130613Smlaier	 * hear, does it make a sound?
1349130613Smlaier	 */
1350145836Smlaier	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
1351159603Smlaier#ifdef __FreeBSD__
1352159603Smlaier	    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1353159603Smlaier#else
1354145836Smlaier	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1355159603Smlaier#endif
1356130613Smlaier		/* Don't leave any stale pfsync packets hanging around. */
1357130613Smlaier		if (sc->sc_mbuf != NULL) {
1358130613Smlaier			m_freem(sc->sc_mbuf);
1359130613Smlaier			sc->sc_mbuf = NULL;
1360130613Smlaier			sc->sc_statep.s = NULL;
1361130613Smlaier		}
1362130613Smlaier		return (0);
1363130613Smlaier	}
1364130613Smlaier
1365126258Smlaier	if (action >= PFSYNC_ACT_MAX)
1366126258Smlaier		return (EINVAL);
1367126258Smlaier
1368126258Smlaier	s = splnet();
1369130613Smlaier	if (sc->sc_mbuf == NULL) {
1370130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1371130613Smlaier		    (void *)&sc->sc_statep.s)) == NULL) {
1372126258Smlaier			splx(s);
1373126258Smlaier			return (ENOMEM);
1374126258Smlaier		}
1375130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1376126258Smlaier	} else {
1377130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1378126258Smlaier		if (h->action != action) {
1379126258Smlaier			pfsync_sendout(sc);
1380130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1381130613Smlaier			    (void *)&sc->sc_statep.s)) == NULL) {
1382126258Smlaier				splx(s);
1383126258Smlaier				return (ENOMEM);
1384126258Smlaier			}
1385130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1386130613Smlaier		} else {
1387130613Smlaier			/*
1388130613Smlaier			 * If it's an update, look in the packet to see if
1389130613Smlaier			 * we already have an update for the state.
1390130613Smlaier			 */
1391130613Smlaier			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1392130613Smlaier				struct pfsync_state *usp =
1393130613Smlaier				    (void *)((char *)h + PFSYNC_HDRLEN);
1394130613Smlaier
1395130613Smlaier				for (i = 0; i < h->count; i++) {
1396130613Smlaier					if (!memcmp(usp->id, &st->id,
1397130613Smlaier					    PFSYNC_ID_LEN) &&
1398130613Smlaier					    usp->creatorid == st->creatorid) {
1399130613Smlaier						sp = usp;
1400130613Smlaier						sp->updates++;
1401130613Smlaier						break;
1402130613Smlaier					}
1403130613Smlaier					usp++;
1404130613Smlaier				}
1405130613Smlaier			}
1406126258Smlaier		}
1407126258Smlaier	}
1408126258Smlaier
1409130613Smlaier	secs = time_second;
1410126258Smlaier
1411130613Smlaier	st->pfsync_time = time_uptime;
1412130613Smlaier	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1413130613Smlaier	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1414130613Smlaier
1415130613Smlaier	if (sp == NULL) {
1416130613Smlaier		/* not a "duplicate" update */
1417130613Smlaier		i = 255;
1418130613Smlaier		sp = sc->sc_statep.s++;
1419130613Smlaier		sc->sc_mbuf->m_pkthdr.len =
1420130613Smlaier		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1421130613Smlaier		h->count++;
1422130613Smlaier		bzero(sp, sizeof(*sp));
1423130613Smlaier
1424130613Smlaier		bcopy(&st->id, sp->id, sizeof(sp->id));
1425130613Smlaier		sp->creatorid = st->creatorid;
1426130613Smlaier
1427130613Smlaier		strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1428130613Smlaier		pf_state_host_hton(&st->lan, &sp->lan);
1429130613Smlaier		pf_state_host_hton(&st->gwy, &sp->gwy);
1430130613Smlaier		pf_state_host_hton(&st->ext, &sp->ext);
1431130613Smlaier
1432130613Smlaier		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1433130613Smlaier
1434130613Smlaier		sp->creation = htonl(secs - st->creation);
1435130613Smlaier		sp->packets[0] = htonl(st->packets[0]);
1436130613Smlaier		sp->packets[1] = htonl(st->packets[1]);
1437130613Smlaier		sp->bytes[0] = htonl(st->bytes[0]);
1438130613Smlaier		sp->bytes[1] = htonl(st->bytes[1]);
1439130613Smlaier		if ((r = st->rule.ptr) == NULL)
1440130613Smlaier			sp->rule = htonl(-1);
1441130613Smlaier		else
1442130613Smlaier			sp->rule = htonl(r->nr);
1443130613Smlaier		if ((r = st->anchor.ptr) == NULL)
1444130613Smlaier			sp->anchor = htonl(-1);
1445130613Smlaier		else
1446130613Smlaier			sp->anchor = htonl(r->nr);
1447130613Smlaier		sp->af = st->af;
1448130613Smlaier		sp->proto = st->proto;
1449130613Smlaier		sp->direction = st->direction;
1450130613Smlaier		sp->log = st->log;
1451130613Smlaier		sp->allow_opts = st->allow_opts;
1452130613Smlaier		sp->timeout = st->timeout;
1453130613Smlaier
1454145836Smlaier		if (flags & PFSYNC_FLAG_STALE)
1455145836Smlaier			sp->sync_flags |= PFSTATE_STALE;
1456130613Smlaier	}
1457130613Smlaier
1458126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
1459126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
1460126258Smlaier
1461126258Smlaier	if (st->expire <= secs)
1462126258Smlaier		sp->expire = htonl(0);
1463126258Smlaier	else
1464126258Smlaier		sp->expire = htonl(st->expire - secs);
1465126258Smlaier
1466130613Smlaier	/* do we need to build "compressed" actions for network transfer? */
1467145836Smlaier	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
1468130613Smlaier		switch (action) {
1469130613Smlaier		case PFSYNC_ACT_UPD:
1470130613Smlaier			newaction = PFSYNC_ACT_UPD_C;
1471130613Smlaier			break;
1472130613Smlaier		case PFSYNC_ACT_DEL:
1473130613Smlaier			newaction = PFSYNC_ACT_DEL_C;
1474130613Smlaier			break;
1475130613Smlaier		default:
1476130613Smlaier			/* by default we just send the uncompressed states */
1477130613Smlaier			break;
1478130613Smlaier		}
1479130613Smlaier	}
1480130613Smlaier
1481130613Smlaier	if (newaction) {
1482130613Smlaier		if (sc->sc_mbuf_net == NULL) {
1483130613Smlaier			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1484130613Smlaier			    (void *)&sc->sc_statep_net.s)) == NULL) {
1485130613Smlaier				splx(s);
1486130613Smlaier				return (ENOMEM);
1487130613Smlaier			}
1488130613Smlaier		}
1489130613Smlaier		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1490130613Smlaier
1491130613Smlaier		switch (newaction) {
1492130613Smlaier		case PFSYNC_ACT_UPD_C:
1493130613Smlaier			if (i != 255) {
1494130613Smlaier				up = (void *)((char *)h_net +
1495130613Smlaier				    PFSYNC_HDRLEN + (i * sizeof(*up)));
1496130613Smlaier				up->updates++;
1497130613Smlaier			} else {
1498130613Smlaier				h_net->count++;
1499130613Smlaier				sc->sc_mbuf_net->m_pkthdr.len =
1500130613Smlaier				    sc->sc_mbuf_net->m_len += sizeof(*up);
1501130613Smlaier				up = sc->sc_statep_net.u++;
1502130613Smlaier
1503130613Smlaier				bzero(up, sizeof(*up));
1504130613Smlaier				bcopy(&st->id, up->id, sizeof(up->id));
1505130613Smlaier				up->creatorid = st->creatorid;
1506130613Smlaier			}
1507130613Smlaier			up->timeout = st->timeout;
1508130613Smlaier			up->expire = sp->expire;
1509130613Smlaier			up->src = sp->src;
1510130613Smlaier			up->dst = sp->dst;
1511130613Smlaier			break;
1512130613Smlaier		case PFSYNC_ACT_DEL_C:
1513130613Smlaier			sc->sc_mbuf_net->m_pkthdr.len =
1514130613Smlaier			    sc->sc_mbuf_net->m_len += sizeof(*dp);
1515130613Smlaier			dp = sc->sc_statep_net.d++;
1516130613Smlaier			h_net->count++;
1517130613Smlaier
1518130613Smlaier			bzero(dp, sizeof(*dp));
1519130613Smlaier			bcopy(&st->id, dp->id, sizeof(dp->id));
1520130613Smlaier			dp->creatorid = st->creatorid;
1521130613Smlaier			break;
1522130613Smlaier		}
1523130613Smlaier	}
1524130613Smlaier
1525130613Smlaier	if (h->count == sc->sc_maxcount ||
1526130613Smlaier	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1527126258Smlaier		ret = pfsync_sendout(sc);
1528126258Smlaier
1529126258Smlaier	splx(s);
1530130613Smlaier	return (ret);
1531126258Smlaier}
1532126258Smlaier
1533130613Smlaier/* This must be called in splnet() */
1534126258Smlaierint
1535130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1536126258Smlaier{
1537127145Smlaier#ifdef __FreeBSD__
1538141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1539126261Smlaier#else
1540126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1541130613Smlaier#endif
1542130613Smlaier	struct pfsync_header *h;
1543126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1544130613Smlaier	struct pfsync_state_upd_req *rup;
1545145836Smlaier	int ret = 0;
1546130613Smlaier
1547130613Smlaier#ifdef __FreeBSD__
1548130613Smlaier	PF_ASSERT(MA_OWNED);
1549126261Smlaier#endif
1550130613Smlaier	if (sc->sc_mbuf == NULL) {
1551130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1552145836Smlaier		    (void *)&sc->sc_statep.s)) == NULL)
1553130613Smlaier			return (ENOMEM);
1554130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1555130613Smlaier	} else {
1556130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1557130613Smlaier		if (h->action != PFSYNC_ACT_UREQ) {
1558130613Smlaier			pfsync_sendout(sc);
1559130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1560145836Smlaier			    (void *)&sc->sc_statep.s)) == NULL)
1561130613Smlaier				return (ENOMEM);
1562130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1563130613Smlaier		}
1564130613Smlaier	}
1565130613Smlaier
1566130613Smlaier	if (src != NULL)
1567130613Smlaier		sc->sc_sendaddr = *src;
1568130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1569130613Smlaier	h->count++;
1570130613Smlaier	rup = sc->sc_statep.r++;
1571130613Smlaier	bzero(rup, sizeof(*rup));
1572130613Smlaier	if (up != NULL) {
1573130613Smlaier		bcopy(up->id, rup->id, sizeof(rup->id));
1574130613Smlaier		rup->creatorid = up->creatorid;
1575130613Smlaier	}
1576130613Smlaier
1577130613Smlaier	if (h->count == sc->sc_maxcount)
1578130613Smlaier		ret = pfsync_sendout(sc);
1579130613Smlaier
1580130613Smlaier	return (ret);
1581130613Smlaier}
1582130613Smlaier
1583130613Smlaierint
1584130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname)
1585130613Smlaier{
1586130613Smlaier#ifdef __FreeBSD__
1587141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1588130613Smlaier#else
1589130613Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1590130613Smlaier#endif
1591130613Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1592130613Smlaier	struct pfsync_state_clr *cp;
1593126258Smlaier	int s, ret;
1594126258Smlaier
1595126258Smlaier	s = splnet();
1596130613Smlaier#ifdef __FreeBSD__
1597130613Smlaier	PF_ASSERT(MA_OWNED);
1598130613Smlaier#endif
1599130613Smlaier	if (sc->sc_mbuf != NULL)
1600130613Smlaier		pfsync_sendout(sc);
1601130613Smlaier	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1602130613Smlaier	    (void *)&sc->sc_statep.c)) == NULL) {
1603126258Smlaier		splx(s);
1604126258Smlaier		return (ENOMEM);
1605126258Smlaier	}
1606130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1607130613Smlaier	cp = sc->sc_statep.c;
1608130613Smlaier	cp->creatorid = creatorid;
1609130613Smlaier	if (ifname != NULL)
1610130613Smlaier		strlcpy(cp->ifname, ifname, IFNAMSIZ);
1611126258Smlaier
1612126258Smlaier	ret = (pfsync_sendout(sc));
1613126258Smlaier	splx(s);
1614126258Smlaier	return (ret);
1615126258Smlaier}
1616126258Smlaier
1617126258Smlaiervoid
1618126258Smlaierpfsync_timeout(void *v)
1619126258Smlaier{
1620126258Smlaier	struct pfsync_softc *sc = v;
1621126258Smlaier	int s;
1622126258Smlaier
1623126258Smlaier	s = splnet();
1624130613Smlaier#ifdef __FreeBSD__
1625130613Smlaier	PF_LOCK();
1626130613Smlaier#endif
1627126258Smlaier	pfsync_sendout(sc);
1628130613Smlaier#ifdef __FreeBSD__
1629130613Smlaier	PF_UNLOCK();
1630130613Smlaier#endif
1631126258Smlaier	splx(s);
1632126258Smlaier}
1633126258Smlaier
1634145836Smlaier/* This must be called in splnet() */
1635130613Smlaiervoid
1636130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1637130613Smlaier{
1638130613Smlaier	struct pfsync_state_bus *bus;
1639130613Smlaier
1640130613Smlaier#ifdef __FreeBSD__
1641130613Smlaier	PF_ASSERT(MA_OWNED);
1642130613Smlaier#endif
1643130613Smlaier	if (sc->sc_mbuf != NULL)
1644130613Smlaier		pfsync_sendout(sc);
1645130613Smlaier
1646130613Smlaier	if (pfsync_sync_ok &&
1647130613Smlaier	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1648130613Smlaier	    (void *)&sc->sc_statep.b)) != NULL) {
1649130613Smlaier		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1650130613Smlaier		bus = sc->sc_statep.b;
1651130613Smlaier		bus->creatorid = pf_status.hostid;
1652130613Smlaier		bus->status = status;
1653130613Smlaier		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1654130613Smlaier		pfsync_sendout(sc);
1655130613Smlaier	}
1656130613Smlaier}
1657130613Smlaier
1658130613Smlaiervoid
1659130613Smlaierpfsync_bulk_update(void *v)
1660130613Smlaier{
1661130613Smlaier	struct pfsync_softc *sc = v;
1662130613Smlaier	int s, i = 0;
1663130613Smlaier	struct pf_state *state;
1664130613Smlaier
1665130613Smlaier#ifdef __FreeBSD__
1666130613Smlaier	PF_LOCK();
1667130613Smlaier#endif
1668130613Smlaier	s = splnet();
1669130613Smlaier	if (sc->sc_mbuf != NULL)
1670130613Smlaier		pfsync_sendout(sc);
1671130613Smlaier
1672130613Smlaier	/*
1673130613Smlaier	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1674130613Smlaier	 * been sent since the latest request was made.
1675130613Smlaier	 */
1676130613Smlaier	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1677130613Smlaier	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1678130613Smlaier		if (state->pfsync_time > sc->sc_ureq_received) {
1679130613Smlaier			/* we're done */
1680130613Smlaier			pfsync_send_bus(sc, PFSYNC_BUS_END);
1681130613Smlaier			sc->sc_ureq_received = 0;
1682130613Smlaier#ifdef __FreeBSD__
1683130613Smlaier			callout_stop(&sc->sc_bulk_tmo);
1684130613Smlaier#else
1685130613Smlaier			timeout_del(&sc->sc_bulk_tmo);
1686130613Smlaier#endif
1687130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1688130613Smlaier				printf("pfsync: bulk update complete\n");
1689130613Smlaier			break;
1690130613Smlaier		} else {
1691130613Smlaier			/* send an update and move to end of list */
1692130613Smlaier			if (!state->sync_flags)
1693130613Smlaier				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1694130613Smlaier			state->pfsync_time = time_uptime;
1695130613Smlaier			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1696130613Smlaier			TAILQ_INSERT_TAIL(&state_updates, state,
1697130613Smlaier			    u.s.entry_updates);
1698130613Smlaier
1699130613Smlaier			/* look again for more in a bit */
1700130613Smlaier#ifdef __FreeBSD__
1701130613Smlaier			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1702130613Smlaier			    LIST_FIRST(&pfsync_list));
1703130613Smlaier#else
1704130613Smlaier			timeout_add(&sc->sc_bulk_tmo, 1);
1705130613Smlaier#endif
1706130613Smlaier		}
1707130613Smlaier	}
1708130613Smlaier	if (sc->sc_mbuf != NULL)
1709130613Smlaier		pfsync_sendout(sc);
1710130613Smlaier	splx(s);
1711130613Smlaier#ifdef __FreeBSD__
1712130613Smlaier	PF_UNLOCK();
1713130613Smlaier#endif
1714130613Smlaier}
1715130613Smlaier
1716130613Smlaiervoid
1717130613Smlaierpfsync_bulkfail(void *v)
1718130613Smlaier{
1719130613Smlaier	struct pfsync_softc *sc = v;
1720145836Smlaier	int s, error;
1721130613Smlaier
1722130613Smlaier#ifdef __FreeBSD__
1723130613Smlaier	PF_LOCK();
1724130613Smlaier#endif
1725130613Smlaier	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1726130613Smlaier		/* Try again in a bit */
1727130613Smlaier#ifdef __FreeBSD__
1728130613Smlaier		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1729130613Smlaier		    LIST_FIRST(&pfsync_list));
1730130613Smlaier#else
1731130613Smlaier		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1732130613Smlaier#endif
1733145836Smlaier		s = splnet();
1734145836Smlaier		error = pfsync_request_update(NULL, NULL);
1735145836Smlaier		if (error == ENOMEM) {
1736145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1737145836Smlaier				printf("pfsync: cannot allocate mbufs for "
1738145836Smlaier				    "bulk update\n");
1739145836Smlaier		} else
1740145836Smlaier			pfsync_sendout(sc);
1741145836Smlaier		splx(s);
1742130613Smlaier	} else {
1743130613Smlaier		/* Pretend like the transfer was ok */
1744130613Smlaier		sc->sc_ureq_sent = 0;
1745130613Smlaier		sc->sc_bulk_tries = 0;
1746145836Smlaier#if NCARP > 0
1747145836Smlaier		if (!pfsync_sync_ok)
1748145836Smlaier			carp_suppress_preempt--;
1749145836Smlaier#endif
1750130613Smlaier		pfsync_sync_ok = 1;
1751130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
1752130613Smlaier			printf("pfsync: failed to receive "
1753130613Smlaier			    "bulk update status\n");
1754130613Smlaier#ifdef __FreeBSD__
1755130613Smlaier		callout_stop(&sc->sc_bulkfail_tmo);
1756130613Smlaier#else
1757130613Smlaier		timeout_del(&sc->sc_bulkfail_tmo);
1758130613Smlaier#endif
1759130613Smlaier	}
1760130613Smlaier#ifdef __FreeBSD__
1761130613Smlaier	PF_UNLOCK();
1762130613Smlaier#endif
1763130613Smlaier}
1764130613Smlaier
1765145836Smlaier/* This must be called in splnet() */
1766126258Smlaierint
1767126258Smlaierpfsync_sendout(sc)
1768126258Smlaier	struct pfsync_softc *sc;
1769126258Smlaier{
1770138666Smlaier#if NBPFILTER > 0
1771141584Smlaier# ifdef __FreeBSD__
1772141584Smlaier	struct ifnet *ifp = SCP2IFP(sc);
1773141584Smlaier# else
1774141584Smlaier	struct ifnet *ifp = &sc->if_sc;
1775141584Smlaier# endif
1776138666Smlaier#endif
1777130613Smlaier	struct mbuf *m;
1778126258Smlaier
1779127145Smlaier#ifdef __FreeBSD__
1780130613Smlaier	PF_ASSERT(MA_OWNED);
1781126261Smlaier	callout_stop(&sc->sc_tmo);
1782126261Smlaier#else
1783126258Smlaier	timeout_del(&sc->sc_tmo);
1784126261Smlaier#endif
1785130613Smlaier
1786130613Smlaier	if (sc->sc_mbuf == NULL)
1787130613Smlaier		return (0);
1788130613Smlaier	m = sc->sc_mbuf;
1789126258Smlaier	sc->sc_mbuf = NULL;
1790130613Smlaier	sc->sc_statep.s = NULL;
1791126258Smlaier
1792127145Smlaier#ifdef __FreeBSD__
1793126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1794126261Smlaier#endif
1795126258Smlaier#if NBPFILTER > 0
1796165632Sjhb#ifdef __FreeBSD__
1797165632Sjhb	BPF_MTAP(ifp, m);
1798165632Sjhb#else
1799126258Smlaier	if (ifp->if_bpf)
1800126258Smlaier		bpf_mtap(ifp->if_bpf, m);
1801126258Smlaier#endif
1802165632Sjhb#endif
1803126258Smlaier
1804130613Smlaier	if (sc->sc_mbuf_net) {
1805130613Smlaier		m_freem(m);
1806130613Smlaier		m = sc->sc_mbuf_net;
1807130613Smlaier		sc->sc_mbuf_net = NULL;
1808130613Smlaier		sc->sc_statep_net.s = NULL;
1809130613Smlaier	}
1810126258Smlaier
1811159603Smlaier#ifdef __FreeBSD__
1812159603Smlaier	if (sc->sc_sync_ifp ||
1813159603Smlaier	    sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
1814159603Smlaier#else
1815159603Smlaier	if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1816159603Smlaier#endif
1817130613Smlaier		struct ip *ip;
1818130613Smlaier		struct sockaddr sa;
1819130613Smlaier
1820130613Smlaier		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1821130613Smlaier		if (m == NULL) {
1822130613Smlaier			pfsyncstats.pfsyncs_onomem++;
1823130613Smlaier			return (0);
1824130613Smlaier		}
1825130613Smlaier		ip = mtod(m, struct ip *);
1826130613Smlaier		ip->ip_v = IPVERSION;
1827130613Smlaier		ip->ip_hl = sizeof(*ip) >> 2;
1828130613Smlaier		ip->ip_tos = IPTOS_LOWDELAY;
1829130613Smlaier#ifdef __FreeBSD__
1830130613Smlaier		ip->ip_len = m->m_pkthdr.len;
1831130613Smlaier#else
1832130613Smlaier		ip->ip_len = htons(m->m_pkthdr.len);
1833130613Smlaier#endif
1834130613Smlaier		ip->ip_id = htons(ip_randomid());
1835130613Smlaier#ifdef __FreeBSD__
1836130613Smlaier		ip->ip_off = IP_DF;
1837130613Smlaier#else
1838130613Smlaier		ip->ip_off = htons(IP_DF);
1839130613Smlaier#endif
1840130613Smlaier		ip->ip_ttl = PFSYNC_DFLTTL;
1841130613Smlaier		ip->ip_p = IPPROTO_PFSYNC;
1842130613Smlaier		ip->ip_sum = 0;
1843130613Smlaier
1844130613Smlaier		bzero(&sa, sizeof(sa));
1845145836Smlaier		ip->ip_src.s_addr = INADDR_ANY;
1846130613Smlaier
1847130613Smlaier#ifdef __FreeBSD__
1848130613Smlaier		if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1849130613Smlaier#else
1850130613Smlaier		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1851130613Smlaier#endif
1852130613Smlaier			m->m_flags |= M_MCAST;
1853130613Smlaier		ip->ip_dst = sc->sc_sendaddr;
1854145836Smlaier		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
1855130613Smlaier
1856130613Smlaier		pfsyncstats.pfsyncs_opackets++;
1857130613Smlaier#ifdef __FreeBSD__
1858147614Smlaier		if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
1859147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1860147261Smlaier		callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
1861147261Smlaier#else
1862130613Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1863130613Smlaier			pfsyncstats.pfsyncs_oerrors++;
1864130613Smlaier#endif
1865130613Smlaier	} else
1866130613Smlaier		m_freem(m);
1867130613Smlaier
1868126258Smlaier	return (0);
1869126258Smlaier}
1870126261Smlaier
1871147261Smlaier#ifdef __FreeBSD__
1872147261Smlaierstatic void
1873147261Smlaierpfsync_senddef(void *arg)
1874147261Smlaier{
1875147261Smlaier	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
1876147261Smlaier	struct mbuf *m;
1877126261Smlaier
1878147261Smlaier	for(;;) {
1879147261Smlaier		IF_DEQUEUE(&sc->sc_ifq, m);
1880147261Smlaier		if (m == NULL)
1881147261Smlaier			break;
1882147261Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1883147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1884147261Smlaier	}
1885147261Smlaier}
1886147261Smlaier
1887126261Smlaierstatic int
1888126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
1889126261Smlaier{
1890126261Smlaier	int error = 0;
1891126261Smlaier
1892126261Smlaier	switch (type) {
1893126261Smlaier	case MOD_LOAD:
1894126261Smlaier		LIST_INIT(&pfsync_list);
1895126261Smlaier		if_clone_attach(&pfsync_cloner);
1896126261Smlaier		break;
1897126261Smlaier
1898126261Smlaier	case MOD_UNLOAD:
1899126261Smlaier		if_clone_detach(&pfsync_cloner);
1900126261Smlaier		break;
1901126261Smlaier
1902126261Smlaier	default:
1903126261Smlaier		error = EINVAL;
1904126261Smlaier		break;
1905126261Smlaier	}
1906126261Smlaier
1907126261Smlaier	return error;
1908126261Smlaier}
1909126261Smlaier
1910126261Smlaierstatic moduledata_t pfsync_mod = {
1911126261Smlaier	"pfsync",
1912126261Smlaier	pfsync_modevent,
1913126261Smlaier	0
1914126261Smlaier};
1915126261Smlaier
1916126261Smlaier#define PFSYNC_MODVER 1
1917126261Smlaier
1918135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1919126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
1920126261Smlaier#endif /* __FreeBSD__ */
1921