if_pfsync.c revision 145836
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 145836 2005-05-03 16:43:32Z mlaier $	*/
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"
41127145Smlaier#define	NBPFILTER	DEV_BPF
42127145Smlaier#define	NPFSYNC		DEV_PFSYNC
43126261Smlaier#endif
44126258Smlaier
45126258Smlaier#include <sys/param.h>
46130613Smlaier#include <sys/proc.h>
47126258Smlaier#include <sys/systm.h>
48126258Smlaier#include <sys/time.h>
49126258Smlaier#include <sys/mbuf.h>
50126258Smlaier#include <sys/socket.h>
51145836Smlaier#include <sys/kernel.h>
52127145Smlaier#ifdef __FreeBSD__
53145836Smlaier#include <sys/endian.h>
54126261Smlaier#include <sys/malloc.h>
55129907Smlaier#include <sys/module.h>
56126261Smlaier#include <sys/sockio.h>
57130613Smlaier#include <sys/lock.h>
58130613Smlaier#include <sys/mutex.h>
59126261Smlaier#else
60126258Smlaier#include <sys/ioctl.h>
61126258Smlaier#include <sys/timeout.h>
62126261Smlaier#endif
63126258Smlaier
64126258Smlaier#include <net/if.h>
65130933Sbrooks#if defined(__FreeBSD__)
66130933Sbrooks#include <net/if_clone.h>
67130933Sbrooks#endif
68126258Smlaier#include <net/if_types.h>
69126258Smlaier#include <net/route.h>
70126258Smlaier#include <net/bpf.h>
71145836Smlaier#include <netinet/tcp.h>
72145836Smlaier#include <netinet/tcp_seq.h>
73126258Smlaier
74126258Smlaier#ifdef	INET
75126258Smlaier#include <netinet/in.h>
76130613Smlaier#include <netinet/in_systm.h>
77126258Smlaier#include <netinet/in_var.h>
78130613Smlaier#include <netinet/ip.h>
79130613Smlaier#include <netinet/ip_var.h>
80126258Smlaier#endif
81126258Smlaier
82126258Smlaier#ifdef INET6
83126258Smlaier#ifndef INET
84126258Smlaier#include <netinet/in.h>
85126258Smlaier#endif
86126258Smlaier#include <netinet6/nd6.h>
87126258Smlaier#endif /* INET6 */
88126258Smlaier
89145836Smlaier#ifdef __FreeBSD__
90145836Smlaier#include "opt_carp.h"
91145836Smlaier#ifdef DEV_CARP
92145836Smlaier#define	NCARP	1
93145836Smlaier#endif
94145836Smlaier#else
95145836Smlaier#include "carp.h"
96145836Smlaier#endif
97145836Smlaier#if NCARP > 0
98145836Smlaierextern int carp_suppress_preempt;
99145836Smlaier#endif
100145836Smlaier
101126258Smlaier#include <net/pfvar.h>
102126258Smlaier#include <net/if_pfsync.h>
103126258Smlaier
104127145Smlaier#ifdef __FreeBSD__
105127145Smlaier#define	PFSYNCNAME	"pfsync"
106126261Smlaier#endif
107126261Smlaier
108126258Smlaier#define PFSYNC_MINMTU	\
109126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
110126258Smlaier
111126258Smlaier#ifdef PFSYNCDEBUG
112126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
113126258Smlaierint pfsyncdebug;
114126258Smlaier#else
115126258Smlaier#define DPRINTF(x)
116126258Smlaier#endif
117126258Smlaier
118127145Smlaier#ifndef __FreeBSD__
119130613Smlaierstruct pfsync_softc	pfsyncif;
120126261Smlaier#endif
121130613Smlaierstruct pfsyncstats	pfsyncstats;
122126258Smlaier
123127145Smlaier#ifdef __FreeBSD__
124130613Smlaier
125130613Smlaier/*
126130613Smlaier * Locking notes:
127130613Smlaier * Whenever we really touch/look at the state table we have to hold the
128130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per
129130613Smlaier * softc lock instead.
130130613Smlaier *
131130613Smlaier */
132130613Smlaier
133128209Sbrooksstatic void	pfsync_clone_destroy(struct ifnet *);
134128209Sbrooksstatic int	pfsync_clone_create(struct if_clone *, int);
135126261Smlaier#else
136126258Smlaiervoid	pfsyncattach(int);
137126261Smlaier#endif
138130613Smlaiervoid	pfsync_setmtu(struct pfsync_softc *, int);
139130613Smlaierint	pfsync_insert_net_state(struct pfsync_state *);
140126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
141130613Smlaier	    struct rtentry *);
142126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
143126258Smlaiervoid	pfsyncstart(struct ifnet *);
144126258Smlaier
145130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
146130613Smlaierint	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
147130613Smlaierint	pfsync_sendout(struct pfsync_softc *);
148130613Smlaiervoid	pfsync_timeout(void *);
149130613Smlaiervoid	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
150130613Smlaiervoid	pfsync_bulk_update(void *);
151130613Smlaiervoid	pfsync_bulkfail(void *);
152126258Smlaier
153145836Smlaierint	pfsync_sync_ok;
154127145Smlaier#ifndef __FreeBSD__
155126258Smlaierextern int ifqmaxlen;
156130613Smlaierextern struct timeval time;
157130613Smlaierextern struct timeval mono_time;
158130613Smlaierextern int hz;
159126261Smlaier#endif
160126258Smlaier
161127145Smlaier#ifdef __FreeBSD__
162126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
163126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
164141584Smlaier#define	SCP2IFP(sc)		(&(sc)->sc_if)
165130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1);
166126261Smlaier
167128209Sbrooksstatic void
168126261Smlaierpfsync_clone_destroy(struct ifnet *ifp)
169126261Smlaier{
170126261Smlaier        struct pfsync_softc *sc;
171126261Smlaier
172130613Smlaier	sc = ifp->if_softc;
173126261Smlaier	callout_stop(&sc->sc_tmo);
174130613Smlaier	callout_stop(&sc->sc_bulk_tmo);
175130613Smlaier	callout_stop(&sc->sc_bulkfail_tmo);
176126261Smlaier
177126261Smlaier#if NBPFILTER > 0
178126261Smlaier        bpfdetach(ifp);
179126261Smlaier#endif
180126261Smlaier        if_detach(ifp);
181126261Smlaier        LIST_REMOVE(sc, sc_next);
182126261Smlaier        free(sc, M_PFSYNC);
183126261Smlaier}
184126261Smlaier
185128209Sbrooksstatic int
186126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
187126261Smlaier{
188126261Smlaier	struct pfsync_softc *sc;
189130613Smlaier	struct ifnet *ifp;
190126261Smlaier
191126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
192130613Smlaier	    M_WAITOK|M_ZERO);
193126261Smlaier
194130613Smlaier	pfsync_sync_ok = 1;
195130613Smlaier	sc->sc_mbuf = NULL;
196130613Smlaier	sc->sc_mbuf_net = NULL;
197130613Smlaier	sc->sc_statep.s = NULL;
198130613Smlaier	sc->sc_statep_net.s = NULL;
199130613Smlaier	sc->sc_maxupdates = 128;
200130613Smlaier	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
201130613Smlaier	sc->sc_ureq_received = 0;
202130613Smlaier	sc->sc_ureq_sent = 0;
203130613Smlaier
204141584Smlaier	ifp = SCP2IFP(sc);
205130613Smlaier	if_initname(ifp, ifc->ifc_name, unit);
206130613Smlaier	ifp->if_ioctl = pfsyncioctl;
207130613Smlaier	ifp->if_output = pfsyncoutput;
208130613Smlaier	ifp->if_start = pfsyncstart;
209130613Smlaier	ifp->if_type = IFT_PFSYNC;
210130613Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
211130613Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
212130613Smlaier	ifp->if_baudrate = IF_Mbps(100);
213130613Smlaier	ifp->if_softc = sc;
214126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
215126261Smlaier	/*
216126261Smlaier	 * XXX
217126261Smlaier	 *  The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
218126261Smlaier	 * if Gaint lock is removed from the network stack.
219126261Smlaier	 */
220126261Smlaier	callout_init(&sc->sc_tmo, 0);
221130613Smlaier	callout_init(&sc->sc_bulk_tmo, 0);
222130613Smlaier	callout_init(&sc->sc_bulkfail_tmo, 0);
223141584Smlaier	if_attach(ifp);
224126261Smlaier
225126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
226126261Smlaier#if NBPFILTER > 0
227141584Smlaier	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
228126261Smlaier#endif
229126261Smlaier
230126261Smlaier	return (0);
231126261Smlaier}
232126261Smlaier#else /* !__FreeBSD__ */
233126261Smlaiervoid
234126258Smlaierpfsyncattach(int npfsync)
235126258Smlaier{
236126258Smlaier	struct ifnet *ifp;
237126258Smlaier
238130613Smlaier	pfsync_sync_ok = 1;
239130613Smlaier	bzero(&pfsyncif, sizeof(pfsyncif));
240126258Smlaier	pfsyncif.sc_mbuf = NULL;
241130613Smlaier	pfsyncif.sc_mbuf_net = NULL;
242130613Smlaier	pfsyncif.sc_statep.s = NULL;
243130613Smlaier	pfsyncif.sc_statep_net.s = NULL;
244130613Smlaier	pfsyncif.sc_maxupdates = 128;
245145836Smlaier	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
246130613Smlaier	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
247130613Smlaier	pfsyncif.sc_ureq_received = 0;
248130613Smlaier	pfsyncif.sc_ureq_sent = 0;
249126258Smlaier	ifp = &pfsyncif.sc_if;
250126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
251126258Smlaier	ifp->if_softc = &pfsyncif;
252126258Smlaier	ifp->if_ioctl = pfsyncioctl;
253126258Smlaier	ifp->if_output = pfsyncoutput;
254126258Smlaier	ifp->if_start = pfsyncstart;
255126258Smlaier	ifp->if_type = IFT_PFSYNC;
256126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
257126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
258126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
259126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
260130613Smlaier	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
261130613Smlaier	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
262126258Smlaier	if_attach(ifp);
263126258Smlaier	if_alloc_sadl(ifp);
264126258Smlaier
265126258Smlaier#if NBPFILTER > 0
266126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
267126258Smlaier#endif
268126258Smlaier}
269126261Smlaier#endif
270126258Smlaier
271126258Smlaier/*
272126258Smlaier * Start output on the pfsync interface.
273126258Smlaier */
274126258Smlaiervoid
275126258Smlaierpfsyncstart(struct ifnet *ifp)
276126258Smlaier{
277130613Smlaier#ifdef __FreeBSD__
278130613Smlaier	IF_LOCK(&ifp->if_snd);
279130613Smlaier	_IF_DROP(&ifp->if_snd);
280130613Smlaier	_IF_DRAIN(&ifp->if_snd);
281130613Smlaier	IF_UNLOCK(&ifp->if_snd);
282130613Smlaier#else
283126258Smlaier	struct mbuf *m;
284126258Smlaier	int s;
285126258Smlaier
286126258Smlaier	for (;;) {
287126258Smlaier		s = splimp();
288126258Smlaier		IF_DROP(&ifp->if_snd);
289126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
290126258Smlaier		splx(s);
291126258Smlaier
292126258Smlaier		if (m == NULL)
293126258Smlaier			return;
294126258Smlaier		else
295126258Smlaier			m_freem(m);
296126258Smlaier	}
297130613Smlaier#endif
298126258Smlaier}
299126258Smlaier
300126258Smlaierint
301130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp)
302130613Smlaier{
303130613Smlaier	struct pf_state	*st = NULL;
304130613Smlaier	struct pf_rule *r = NULL;
305130613Smlaier	struct pfi_kif	*kif;
306130613Smlaier
307130613Smlaier#ifdef __FreeBSD__
308130613Smlaier	PF_ASSERT(MA_OWNED);
309130613Smlaier#endif
310130613Smlaier	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
311130613Smlaier		printf("pfsync_insert_net_state: invalid creator id:"
312130613Smlaier		    " %08x\n", ntohl(sp->creatorid));
313130613Smlaier		return (EINVAL);
314130613Smlaier	}
315130613Smlaier
316130613Smlaier	kif = pfi_lookup_create(sp->ifname);
317130613Smlaier	if (kif == NULL) {
318130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
319130613Smlaier			printf("pfsync_insert_net_state: "
320130613Smlaier			    "unknown interface: %s\n", sp->ifname);
321130613Smlaier		/* skip this state */
322130613Smlaier		return (0);
323130613Smlaier	}
324130613Smlaier
325130613Smlaier	/*
326130613Smlaier	 * Just use the default rule until we have infrastructure to find the
327130613Smlaier	 * best matching rule.
328130613Smlaier	 */
329130613Smlaier	r = &pf_default_rule;
330130613Smlaier
331130613Smlaier	if (!r->max_states || r->states < r->max_states)
332130613Smlaier		st = pool_get(&pf_state_pl, PR_NOWAIT);
333130613Smlaier	if (st == NULL) {
334130613Smlaier		pfi_maybe_destroy(kif);
335130613Smlaier		return (ENOMEM);
336130613Smlaier	}
337130613Smlaier	bzero(st, sizeof(*st));
338130613Smlaier
339130613Smlaier	st->rule.ptr = r;
340130613Smlaier	/* XXX get pointers to nat_rule and anchor */
341130613Smlaier
342145836Smlaier	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
343145836Smlaier	r->states++;
344145836Smlaier
345130613Smlaier	/* fill in the rest of the state entry */
346130613Smlaier	pf_state_host_ntoh(&sp->lan, &st->lan);
347130613Smlaier	pf_state_host_ntoh(&sp->gwy, &st->gwy);
348130613Smlaier	pf_state_host_ntoh(&sp->ext, &st->ext);
349130613Smlaier
350130613Smlaier	pf_state_peer_ntoh(&sp->src, &st->src);
351130613Smlaier	pf_state_peer_ntoh(&sp->dst, &st->dst);
352130613Smlaier
353130613Smlaier	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
354145836Smlaier	st->creation = time_second - ntohl(sp->creation);
355130613Smlaier	st->expire = ntohl(sp->expire) + time_second;
356130613Smlaier
357130613Smlaier	st->af = sp->af;
358130613Smlaier	st->proto = sp->proto;
359130613Smlaier	st->direction = sp->direction;
360130613Smlaier	st->log = sp->log;
361130613Smlaier	st->timeout = sp->timeout;
362130613Smlaier	st->allow_opts = sp->allow_opts;
363130613Smlaier
364130613Smlaier	bcopy(sp->id, &st->id, sizeof(st->id));
365130613Smlaier	st->creatorid = sp->creatorid;
366145836Smlaier	st->sync_flags = PFSTATE_FROMSYNC;
367130613Smlaier
368130613Smlaier
369130613Smlaier	if (pf_insert_state(kif, st)) {
370130613Smlaier		pfi_maybe_destroy(kif);
371145836Smlaier		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
372145836Smlaier		r->states--;
373130613Smlaier		pool_put(&pf_state_pl, st);
374130613Smlaier		return (EINVAL);
375130613Smlaier	}
376130613Smlaier
377130613Smlaier	return (0);
378130613Smlaier}
379130613Smlaier
380130613Smlaiervoid
381130613Smlaier#ifdef __FreeBSD__
382130613Smlaierpfsync_input(struct mbuf *m, __unused int off)
383130613Smlaier#else
384130613Smlaierpfsync_input(struct mbuf *m, ...)
385130613Smlaier#endif
386130613Smlaier{
387130613Smlaier	struct ip *ip = mtod(m, struct ip *);
388130613Smlaier	struct pfsync_header *ph;
389130613Smlaier#ifdef __FreeBSD__
390130613Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
391130613Smlaier#else
392130613Smlaier	struct pfsync_softc *sc = &pfsyncif;
393130613Smlaier#endif
394130613Smlaier	struct pf_state *st, key;
395130613Smlaier	struct pfsync_state *sp;
396130613Smlaier	struct pfsync_state_upd *up;
397130613Smlaier	struct pfsync_state_del *dp;
398130613Smlaier	struct pfsync_state_clr *cp;
399130613Smlaier	struct pfsync_state_upd_req *rup;
400130613Smlaier	struct pfsync_state_bus *bus;
401130613Smlaier	struct in_addr src;
402130613Smlaier	struct mbuf *mp;
403145836Smlaier	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
404130613Smlaier
405130613Smlaier	pfsyncstats.pfsyncs_ipackets++;
406130613Smlaier
407130613Smlaier	/* verify that we have a sync interface configured */
408130613Smlaier	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
409130613Smlaier		goto done;
410130613Smlaier
411130613Smlaier	/* verify that the packet came in on the right interface */
412130613Smlaier	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
413130613Smlaier		pfsyncstats.pfsyncs_badif++;
414130613Smlaier		goto done;
415130613Smlaier	}
416130613Smlaier
417130613Smlaier	/* verify that the IP TTL is 255.  */
418130613Smlaier	if (ip->ip_ttl != PFSYNC_DFLTTL) {
419130613Smlaier		pfsyncstats.pfsyncs_badttl++;
420130613Smlaier		goto done;
421130613Smlaier	}
422130613Smlaier
423130613Smlaier	iplen = ip->ip_hl << 2;
424130613Smlaier
425130613Smlaier	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
426130613Smlaier		pfsyncstats.pfsyncs_hdrops++;
427130613Smlaier		goto done;
428130613Smlaier	}
429130613Smlaier
430130613Smlaier	if (iplen + sizeof(*ph) > m->m_len) {
431130613Smlaier		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
432130613Smlaier			pfsyncstats.pfsyncs_hdrops++;
433130613Smlaier			goto done;
434130613Smlaier		}
435130613Smlaier		ip = mtod(m, struct ip *);
436130613Smlaier	}
437130613Smlaier	ph = (struct pfsync_header *)((char *)ip + iplen);
438130613Smlaier
439130613Smlaier	/* verify the version */
440130613Smlaier	if (ph->version != PFSYNC_VERSION) {
441130613Smlaier		pfsyncstats.pfsyncs_badver++;
442130613Smlaier		goto done;
443130613Smlaier	}
444130613Smlaier
445130613Smlaier	action = ph->action;
446130613Smlaier	count = ph->count;
447130613Smlaier
448130613Smlaier	/* make sure it's a valid action code */
449130613Smlaier	if (action >= PFSYNC_ACT_MAX) {
450130613Smlaier		pfsyncstats.pfsyncs_badact++;
451130613Smlaier		goto done;
452130613Smlaier	}
453130613Smlaier
454130613Smlaier	/* Cheaper to grab this now than having to mess with mbufs later */
455130613Smlaier	src = ip->ip_src;
456130613Smlaier
457130613Smlaier	switch (action) {
458130613Smlaier	case PFSYNC_ACT_CLR: {
459145836Smlaier		struct pf_state *nexts;
460130613Smlaier		struct pfi_kif	*kif;
461130613Smlaier		u_int32_t creatorid;
462130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
463130613Smlaier		    sizeof(*cp), &offp)) == NULL) {
464130613Smlaier			pfsyncstats.pfsyncs_badlen++;
465130613Smlaier			return;
466130613Smlaier		}
467130613Smlaier		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
468130613Smlaier		creatorid = cp->creatorid;
469130613Smlaier
470130613Smlaier		s = splsoftnet();
471130613Smlaier#ifdef __FreeBSD__
472130613Smlaier		PF_LOCK();
473130613Smlaier#endif
474130613Smlaier		if (cp->ifname[0] == '\0') {
475145836Smlaier			for (st = RB_MIN(pf_state_tree_id, &tree_id);
476145836Smlaier			    st; st = nexts) {
477145836Smlaier                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
478145836Smlaier				if (st->creatorid == creatorid) {
479130613Smlaier					st->timeout = PFTM_PURGE;
480145836Smlaier					pf_purge_expired_state(st);
481145836Smlaier				}
482130613Smlaier			}
483130613Smlaier		} else {
484130613Smlaier			kif = pfi_lookup_if(cp->ifname);
485130613Smlaier			if (kif == NULL) {
486130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
487130613Smlaier					printf("pfsync_input: PFSYNC_ACT_CLR "
488130613Smlaier					    "bad interface: %s\n", cp->ifname);
489130613Smlaier				splx(s);
490130613Smlaier#ifdef __FreeBSD__
491130613Smlaier				PF_UNLOCK();
492130613Smlaier#endif
493130613Smlaier				goto done;
494130613Smlaier			}
495145836Smlaier			for (st = RB_MIN(pf_state_tree_lan_ext,
496145836Smlaier			    &kif->pfik_lan_ext); st; st = nexts) {
497145836Smlaier				nexts = RB_NEXT(pf_state_tree_lan_ext,
498145836Smlaier				    &kif->pfik_lan_ext, st);
499145836Smlaier				if (st->creatorid == creatorid) {
500130613Smlaier					st->timeout = PFTM_PURGE;
501145836Smlaier					pf_purge_expired_state(st);
502145836Smlaier				}
503130613Smlaier			}
504130613Smlaier		}
505130613Smlaier#ifdef __FreeBSD__
506130613Smlaier		PF_UNLOCK();
507130613Smlaier#endif
508130613Smlaier		splx(s);
509130613Smlaier
510130613Smlaier		break;
511130613Smlaier	}
512130613Smlaier	case PFSYNC_ACT_INS:
513130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
514130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
515130613Smlaier			pfsyncstats.pfsyncs_badlen++;
516130613Smlaier			return;
517130613Smlaier		}
518130613Smlaier
519130613Smlaier		s = splsoftnet();
520130613Smlaier#ifdef __FreeBSD__
521130613Smlaier		PF_LOCK();
522130613Smlaier#endif
523130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
524130613Smlaier		    i < count; i++, sp++) {
525130613Smlaier			/* check for invalid values */
526130613Smlaier			if (sp->timeout >= PFTM_MAX ||
527130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
528130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST ||
529130613Smlaier			    sp->direction > PF_OUT ||
530130613Smlaier			    (sp->af != AF_INET && sp->af != AF_INET6)) {
531130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
532130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_INS: "
533130613Smlaier					    "invalid value\n");
534130613Smlaier				pfsyncstats.pfsyncs_badstate++;
535130613Smlaier				continue;
536130613Smlaier			}
537130613Smlaier
538130613Smlaier			if ((error = pfsync_insert_net_state(sp))) {
539130613Smlaier				if (error == ENOMEM) {
540130613Smlaier					splx(s);
541130613Smlaier#ifdef __FreeBSD__
542130613Smlaier					PF_UNLOCK();
543130613Smlaier#endif
544130613Smlaier					goto done;
545130613Smlaier				}
546130613Smlaier				continue;
547130613Smlaier			}
548130613Smlaier		}
549130613Smlaier#ifdef __FreeBSD__
550130613Smlaier		PF_UNLOCK();
551130613Smlaier#endif
552130613Smlaier		splx(s);
553130613Smlaier		break;
554130613Smlaier	case PFSYNC_ACT_UPD:
555130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
556130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
557130613Smlaier			pfsyncstats.pfsyncs_badlen++;
558130613Smlaier			return;
559130613Smlaier		}
560130613Smlaier
561130613Smlaier		s = splsoftnet();
562130613Smlaier#ifdef __FreeBSD__
563130613Smlaier		PF_LOCK();
564130613Smlaier#endif
565130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
566130613Smlaier		    i < count; i++, sp++) {
567145836Smlaier			int flags = PFSYNC_FLAG_STALE;
568145836Smlaier
569130613Smlaier			/* check for invalid values */
570130613Smlaier			if (sp->timeout >= PFTM_MAX ||
571130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
572130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST) {
573130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
574130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_UPD: "
575130613Smlaier					    "invalid value\n");
576130613Smlaier				pfsyncstats.pfsyncs_badstate++;
577130613Smlaier				continue;
578130613Smlaier			}
579130613Smlaier
580130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
581130613Smlaier			key.creatorid = sp->creatorid;
582130613Smlaier
583130613Smlaier			st = pf_find_state_byid(&key);
584130613Smlaier			if (st == NULL) {
585130613Smlaier				/* insert the update */
586130613Smlaier				if (pfsync_insert_net_state(sp))
587130613Smlaier					pfsyncstats.pfsyncs_badstate++;
588130613Smlaier				continue;
589130613Smlaier			}
590145836Smlaier			sfail = 0;
591145836Smlaier			if (st->proto == IPPROTO_TCP) {
592145836Smlaier				/*
593145836Smlaier				 * The state should never go backwards except
594145836Smlaier				 * for syn-proxy states.  Neither should the
595145836Smlaier				 * sequence window slide backwards.
596145836Smlaier				 */
597145836Smlaier				if (st->src.state > sp->src.state &&
598145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
599145836Smlaier				    sp->src.state >= PF_TCPS_PROXY_SRC))
600145836Smlaier					sfail = 1;
601145836Smlaier				else if (SEQ_GT(st->src.seqlo,
602145836Smlaier				    ntohl(sp->src.seqlo)))
603145836Smlaier					sfail = 3;
604145836Smlaier				else if (st->dst.state > sp->dst.state) {
605145836Smlaier					/* There might still be useful
606145836Smlaier					 * information about the src state here,
607145836Smlaier					 * so import that part of the update,
608145836Smlaier					 * then "fail" so we send the updated
609145836Smlaier					 * state back to the peer who is missing
610145836Smlaier					 * our what we know. */
611145836Smlaier					pf_state_peer_ntoh(&sp->src, &st->src);
612145836Smlaier					/* XXX do anything with timeouts? */
613145836Smlaier					sfail = 7;
614145836Smlaier					flags = 0;
615145836Smlaier				} else if (st->dst.state >= TCPS_SYN_SENT &&
616145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
617145836Smlaier					sfail = 4;
618145836Smlaier			} else {
619145836Smlaier				/*
620145836Smlaier				 * Non-TCP protocol state machine always go
621145836Smlaier				 * forwards
622145836Smlaier				 */
623145836Smlaier				if (st->src.state > sp->src.state)
624145836Smlaier					sfail = 5;
625145836Smlaier				else if ( st->dst.state > sp->dst.state)
626145836Smlaier					sfail = 6;
627145836Smlaier			}
628145836Smlaier			if (sfail) {
629145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
630145836Smlaier					printf("pfsync: %s stale update "
631145836Smlaier					    "(%d) id: %016llx "
632145836Smlaier					    "creatorid: %08x\n",
633145836Smlaier					    (sfail < 7 ?  "ignoring"
634145836Smlaier					     : "partial"), sfail,
635145836Smlaier#ifdef __FreeBSD__
636145836Smlaier					    (unsigned long long)be64toh(st->id),
637145836Smlaier#else
638145836Smlaier					    betoh64(st->id),
639145836Smlaier#endif
640145836Smlaier					    ntohl(st->creatorid));
641145836Smlaier				pfsyncstats.pfsyncs_badstate++;
642145836Smlaier
643145836Smlaier				if (!(sp->sync_flags & PFSTATE_STALE)) {
644145836Smlaier					/* we have a better state, send it */
645145836Smlaier					if (sc->sc_mbuf != NULL && !stale)
646145836Smlaier						pfsync_sendout(sc);
647145836Smlaier					stale++;
648145836Smlaier					if (!st->sync_flags)
649145836Smlaier						pfsync_pack_state(
650145836Smlaier						    PFSYNC_ACT_UPD, st, flags);
651145836Smlaier				}
652145836Smlaier				continue;
653145836Smlaier			}
654130613Smlaier			pf_state_peer_ntoh(&sp->src, &st->src);
655130613Smlaier			pf_state_peer_ntoh(&sp->dst, &st->dst);
656130613Smlaier			st->expire = ntohl(sp->expire) + time_second;
657130613Smlaier			st->timeout = sp->timeout;
658130613Smlaier		}
659145836Smlaier		if (stale && sc->sc_mbuf != NULL)
660145836Smlaier			pfsync_sendout(sc);
661130613Smlaier#ifdef __FreeBSD__
662130613Smlaier		PF_UNLOCK();
663130613Smlaier#endif
664130613Smlaier		splx(s);
665130613Smlaier		break;
666130613Smlaier	/*
667130613Smlaier	 * It's not strictly necessary for us to support the "uncompressed"
668130613Smlaier	 * delete action, but it's relatively simple and maintains consistency.
669130613Smlaier	 */
670130613Smlaier	case PFSYNC_ACT_DEL:
671130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
672130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
673130613Smlaier			pfsyncstats.pfsyncs_badlen++;
674130613Smlaier			return;
675130613Smlaier		}
676130613Smlaier
677130613Smlaier		s = splsoftnet();
678130613Smlaier#ifdef __FreeBSD__
679130613Smlaier		PF_LOCK();
680130613Smlaier#endif
681130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
682130613Smlaier		    i < count; i++, sp++) {
683130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
684130613Smlaier			key.creatorid = sp->creatorid;
685130613Smlaier
686130613Smlaier			st = pf_find_state_byid(&key);
687130613Smlaier			if (st == NULL) {
688130613Smlaier				pfsyncstats.pfsyncs_badstate++;
689130613Smlaier				continue;
690130613Smlaier			}
691130613Smlaier			st->timeout = PFTM_PURGE;
692130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
693145836Smlaier			pf_purge_expired_state(st);
694130613Smlaier		}
695130613Smlaier#ifdef __FreeBSD__
696130613Smlaier		PF_UNLOCK();
697130613Smlaier#endif
698130613Smlaier		splx(s);
699130613Smlaier		break;
700130613Smlaier	case PFSYNC_ACT_UPD_C: {
701130613Smlaier		int update_requested = 0;
702130613Smlaier
703130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
704130613Smlaier		    count * sizeof(*up), &offp)) == NULL) {
705130613Smlaier			pfsyncstats.pfsyncs_badlen++;
706130613Smlaier			return;
707130613Smlaier		}
708130613Smlaier
709130613Smlaier		s = splsoftnet();
710130613Smlaier#ifdef __FreeBSD__
711130613Smlaier		PF_LOCK();
712130613Smlaier#endif
713130613Smlaier		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
714130613Smlaier		    i < count; i++, up++) {
715130613Smlaier			/* check for invalid values */
716130613Smlaier			if (up->timeout >= PFTM_MAX ||
717130613Smlaier			    up->src.state > PF_TCPS_PROXY_DST ||
718130613Smlaier			    up->dst.state > PF_TCPS_PROXY_DST) {
719130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
720130613Smlaier					printf("pfsync_insert: "
721130613Smlaier					    "PFSYNC_ACT_UPD_C: "
722130613Smlaier					    "invalid value\n");
723130613Smlaier				pfsyncstats.pfsyncs_badstate++;
724130613Smlaier				continue;
725130613Smlaier			}
726130613Smlaier
727130613Smlaier			bcopy(up->id, &key.id, sizeof(key.id));
728130613Smlaier			key.creatorid = up->creatorid;
729130613Smlaier
730130613Smlaier			st = pf_find_state_byid(&key);
731130613Smlaier			if (st == NULL) {
732130613Smlaier				/* We don't have this state. Ask for it. */
733145836Smlaier				error = pfsync_request_update(up, &src);
734145836Smlaier				if (error == ENOMEM) {
735145836Smlaier					splx(s);
736145836Smlaier					goto done;
737145836Smlaier				}
738130613Smlaier				update_requested = 1;
739130613Smlaier				pfsyncstats.pfsyncs_badstate++;
740130613Smlaier				continue;
741130613Smlaier			}
742145836Smlaier			sfail = 0;
743145836Smlaier			if (st->proto == IPPROTO_TCP) {
744145836Smlaier				/*
745145836Smlaier				 * The state should never go backwards except
746145836Smlaier				 * for syn-proxy states.  Neither should the
747145836Smlaier				 * sequence window slide backwards.
748145836Smlaier				 */
749145836Smlaier				if (st->src.state > up->src.state &&
750145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
751145836Smlaier				    up->src.state >= PF_TCPS_PROXY_SRC))
752145836Smlaier					sfail = 1;
753145836Smlaier				else if (st->dst.state > up->dst.state)
754145836Smlaier					sfail = 2;
755145836Smlaier				else if (SEQ_GT(st->src.seqlo,
756145836Smlaier				    ntohl(up->src.seqlo)))
757145836Smlaier					sfail = 3;
758145836Smlaier				else if (st->dst.state >= TCPS_SYN_SENT &&
759145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
760145836Smlaier					sfail = 4;
761145836Smlaier			} else {
762145836Smlaier				/*
763145836Smlaier				 * Non-TCP protocol state machine always go
764145836Smlaier				 * forwards
765145836Smlaier				 */
766145836Smlaier				if (st->src.state > up->src.state)
767145836Smlaier					sfail = 5;
768145836Smlaier				else if (st->dst.state > up->dst.state)
769145836Smlaier					sfail = 6;
770145836Smlaier			}
771145836Smlaier			if (sfail) {
772145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
773145836Smlaier					printf("pfsync: ignoring stale update "
774145836Smlaier					    "(%d) id: %016llx "
775145836Smlaier					    "creatorid: %08x\n", sfail,
776145836Smlaier#ifdef __FreeBSD__
777145836Smlaier					    (unsigned long long)be64toh(st->id),
778145836Smlaier#else
779145836Smlaier					    betoh64(st->id),
780145836Smlaier#endif
781145836Smlaier					    ntohl(st->creatorid));
782145836Smlaier				pfsyncstats.pfsyncs_badstate++;
783145836Smlaier
784145836Smlaier				/* we have a better state, send it out */
785145836Smlaier				if ((!stale || update_requested) &&
786145836Smlaier				    sc->sc_mbuf != NULL) {
787145836Smlaier					pfsync_sendout(sc);
788145836Smlaier					update_requested = 0;
789145836Smlaier				}
790145836Smlaier				stale++;
791145836Smlaier				if (!st->sync_flags)
792145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD, st,
793145836Smlaier					    PFSYNC_FLAG_STALE);
794145836Smlaier				continue;
795145836Smlaier			}
796130613Smlaier			pf_state_peer_ntoh(&up->src, &st->src);
797130613Smlaier			pf_state_peer_ntoh(&up->dst, &st->dst);
798130613Smlaier			st->expire = ntohl(up->expire) + time_second;
799130613Smlaier			st->timeout = up->timeout;
800130613Smlaier		}
801145836Smlaier		if ((update_requested || stale) && sc->sc_mbuf)
802130613Smlaier			pfsync_sendout(sc);
803130613Smlaier#ifdef __FreeBSD__
804130613Smlaier		PF_UNLOCK();
805130613Smlaier#endif
806130613Smlaier		splx(s);
807130613Smlaier		break;
808130613Smlaier	}
809130613Smlaier	case PFSYNC_ACT_DEL_C:
810130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
811130613Smlaier		    count * sizeof(*dp), &offp)) == NULL) {
812130613Smlaier			pfsyncstats.pfsyncs_badlen++;
813130613Smlaier			return;
814130613Smlaier		}
815130613Smlaier
816130613Smlaier		s = splsoftnet();
817130613Smlaier#ifdef __FreeBSD__
818130613Smlaier		PF_LOCK();
819130613Smlaier#endif
820130613Smlaier		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
821130613Smlaier		    i < count; i++, dp++) {
822130613Smlaier			bcopy(dp->id, &key.id, sizeof(key.id));
823130613Smlaier			key.creatorid = dp->creatorid;
824130613Smlaier
825130613Smlaier			st = pf_find_state_byid(&key);
826130613Smlaier			if (st == NULL) {
827130613Smlaier				pfsyncstats.pfsyncs_badstate++;
828130613Smlaier				continue;
829130613Smlaier			}
830130613Smlaier			st->timeout = PFTM_PURGE;
831130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
832145836Smlaier			pf_purge_expired_state(st);
833130613Smlaier		}
834130613Smlaier#ifdef __FreeBSD__
835130613Smlaier		PF_UNLOCK();
836130613Smlaier#endif
837130613Smlaier		splx(s);
838130613Smlaier		break;
839130613Smlaier	case PFSYNC_ACT_INS_F:
840130613Smlaier	case PFSYNC_ACT_DEL_F:
841130613Smlaier		/* not implemented */
842130613Smlaier		break;
843130613Smlaier	case PFSYNC_ACT_UREQ:
844130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
845130613Smlaier		    count * sizeof(*rup), &offp)) == NULL) {
846130613Smlaier			pfsyncstats.pfsyncs_badlen++;
847130613Smlaier			return;
848130613Smlaier		}
849130613Smlaier
850130613Smlaier		s = splsoftnet();
851130613Smlaier#ifdef __FreeBSD__
852130613Smlaier		PF_LOCK();
853130613Smlaier#endif
854130613Smlaier		if (sc->sc_mbuf != NULL)
855130613Smlaier			pfsync_sendout(sc);
856130613Smlaier		for (i = 0,
857130613Smlaier		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
858130613Smlaier		    i < count; i++, rup++) {
859130613Smlaier			bcopy(rup->id, &key.id, sizeof(key.id));
860130613Smlaier			key.creatorid = rup->creatorid;
861130613Smlaier
862130613Smlaier			if (key.id == 0 && key.creatorid == 0) {
863130613Smlaier				sc->sc_ureq_received = time_uptime;
864130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
865130613Smlaier					printf("pfsync: received "
866130613Smlaier					    "bulk update request\n");
867130613Smlaier				pfsync_send_bus(sc, PFSYNC_BUS_START);
868130613Smlaier#ifdef __FreeBSD__
869130613Smlaier				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
870130613Smlaier				    pfsync_bulk_update,
871130613Smlaier				    LIST_FIRST(&pfsync_list));
872130613Smlaier#else
873130613Smlaier				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
874130613Smlaier#endif
875130613Smlaier			} else {
876130613Smlaier				st = pf_find_state_byid(&key);
877130613Smlaier				if (st == NULL) {
878130613Smlaier					pfsyncstats.pfsyncs_badstate++;
879130613Smlaier					continue;
880130613Smlaier				}
881145836Smlaier				if (!st->sync_flags)
882145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD,
883145836Smlaier					    st, 0);
884130613Smlaier			}
885130613Smlaier		}
886130613Smlaier		if (sc->sc_mbuf != NULL)
887130613Smlaier			pfsync_sendout(sc);
888130613Smlaier#ifdef __FreeBSD__
889130613Smlaier		PF_UNLOCK();
890130613Smlaier#endif
891130613Smlaier		splx(s);
892130613Smlaier		break;
893130613Smlaier	case PFSYNC_ACT_BUS:
894130613Smlaier		/* If we're not waiting for a bulk update, who cares. */
895130613Smlaier		if (sc->sc_ureq_sent == 0)
896130613Smlaier			break;
897130613Smlaier
898130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
899130613Smlaier		    sizeof(*bus), &offp)) == NULL) {
900130613Smlaier			pfsyncstats.pfsyncs_badlen++;
901130613Smlaier			return;
902130613Smlaier		}
903130613Smlaier		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
904130613Smlaier		switch (bus->status) {
905130613Smlaier		case PFSYNC_BUS_START:
906130613Smlaier#ifdef __FreeBSD__
907130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo,
908130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
909130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
910130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
911130613Smlaier#else
912130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo,
913130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
914130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
915130613Smlaier#endif
916130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
917130613Smlaier				printf("pfsync: received bulk "
918130613Smlaier				    "update start\n");
919130613Smlaier			break;
920130613Smlaier		case PFSYNC_BUS_END:
921130613Smlaier			if (time_uptime - ntohl(bus->endtime) >=
922130613Smlaier			    sc->sc_ureq_sent) {
923130613Smlaier				/* that's it, we're happy */
924130613Smlaier				sc->sc_ureq_sent = 0;
925130613Smlaier				sc->sc_bulk_tries = 0;
926130613Smlaier#ifdef __FreeBSD__
927130613Smlaier				callout_stop(&sc->sc_bulkfail_tmo);
928130613Smlaier#else
929130613Smlaier				timeout_del(&sc->sc_bulkfail_tmo);
930130613Smlaier#endif
931145836Smlaier#if NCARP > 0	/* XXX_IMPORT */
932145836Smlaier				if (!pfsync_sync_ok)
933145836Smlaier					carp_suppress_preempt--;
934145836Smlaier#endif
935130613Smlaier				pfsync_sync_ok = 1;
936130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
937130613Smlaier					printf("pfsync: received valid "
938130613Smlaier					    "bulk update end\n");
939130613Smlaier			} else {
940130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
941130613Smlaier					printf("pfsync: received invalid "
942130613Smlaier					    "bulk update end: bad timestamp\n");
943130613Smlaier			}
944130613Smlaier			break;
945130613Smlaier		}
946130613Smlaier		break;
947130613Smlaier	}
948130613Smlaier
949130613Smlaierdone:
950130613Smlaier	if (m)
951130613Smlaier		m_freem(m);
952130613Smlaier}
953130613Smlaier
954130613Smlaierint
955126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
956126258Smlaier	struct rtentry *rt)
957126258Smlaier{
958126258Smlaier	m_freem(m);
959126258Smlaier	return (0);
960126258Smlaier}
961126258Smlaier
962126258Smlaier/* ARGSUSED */
963126258Smlaierint
964126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
965126258Smlaier{
966130613Smlaier#ifndef __FreeBSD__
967130613Smlaier	struct proc *p = curproc;
968130613Smlaier#endif
969126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
970126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
971130613Smlaier	struct ip_moptions *imo = &sc->sc_imo;
972130613Smlaier	struct pfsyncreq pfsyncr;
973130613Smlaier	struct ifnet    *sifp;
974130613Smlaier	int s, error;
975126258Smlaier
976126258Smlaier	switch (cmd) {
977126258Smlaier	case SIOCSIFADDR:
978126258Smlaier	case SIOCAIFADDR:
979126258Smlaier	case SIOCSIFDSTADDR:
980126258Smlaier	case SIOCSIFFLAGS:
981126258Smlaier		if (ifp->if_flags & IFF_UP)
982126258Smlaier			ifp->if_flags |= IFF_RUNNING;
983126258Smlaier		else
984126258Smlaier			ifp->if_flags &= ~IFF_RUNNING;
985126258Smlaier		break;
986126258Smlaier	case SIOCSIFMTU:
987126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
988126258Smlaier			return (EINVAL);
989126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
990126258Smlaier			ifr->ifr_mtu = MCLBYTES;
991126258Smlaier		s = splnet();
992130613Smlaier#ifdef __FreeBSD__
993130613Smlaier		PF_LOCK();
994130613Smlaier#endif
995130613Smlaier		if (ifr->ifr_mtu < ifp->if_mtu) {
996126258Smlaier			pfsync_sendout(sc);
997130613Smlaier		}
998126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
999130613Smlaier#ifdef __FreeBSD__
1000130613Smlaier		PF_UNLOCK();
1001130613Smlaier#endif
1002126258Smlaier		splx(s);
1003126258Smlaier		break;
1004130613Smlaier	case SIOCGETPFSYNC:
1005130613Smlaier#ifdef __FreeBSD__
1006130613Smlaier		/* XXX: read unlocked */
1007130613Smlaier#endif
1008130613Smlaier		bzero(&pfsyncr, sizeof(pfsyncr));
1009130613Smlaier		if (sc->sc_sync_ifp)
1010145836Smlaier			strlcpy(pfsyncr.pfsyncr_syncdev,
1011130613Smlaier			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
1012145836Smlaier		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1013130613Smlaier		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1014130613Smlaier		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
1015130613Smlaier			return (error);
1016130613Smlaier		break;
1017130613Smlaier	case SIOCSETPFSYNC:
1018130613Smlaier#ifdef __FreeBSD__
1019130613Smlaier		if ((error = suser(curthread)) != 0)
1020130613Smlaier#else
1021130613Smlaier		if ((error = suser(p, p->p_acflag)) != 0)
1022130613Smlaier#endif
1023130613Smlaier			return (error);
1024130613Smlaier		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1025130613Smlaier			return (error);
1026130613Smlaier
1027145836Smlaier		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1028145836Smlaier			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1029145836Smlaier		else
1030145836Smlaier			sc->sc_sync_peer.s_addr =
1031145836Smlaier			    pfsyncr.pfsyncr_syncpeer.s_addr;
1032145836Smlaier
1033130613Smlaier		if (pfsyncr.pfsyncr_maxupdates > 255)
1034130613Smlaier			return (EINVAL);
1035130613Smlaier#ifdef __FreeBSD__
1036130613Smlaier		PF_LOCK();
1037130613Smlaier#endif
1038130613Smlaier		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1039130613Smlaier
1040145836Smlaier		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1041130613Smlaier			sc->sc_sync_ifp = NULL;
1042130613Smlaier			if (sc->sc_mbuf_net != NULL) {
1043130613Smlaier				/* Don't keep stale pfsync packets around. */
1044130613Smlaier				s = splnet();
1045130613Smlaier				m_freem(sc->sc_mbuf_net);
1046130613Smlaier				sc->sc_mbuf_net = NULL;
1047130613Smlaier				sc->sc_statep_net.s = NULL;
1048130613Smlaier				splx(s);
1049130613Smlaier			}
1050145836Smlaier			if (imo->imo_num_memberships > 0) {
1051145836Smlaier				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1052145836Smlaier				imo->imo_multicast_ifp = NULL;
1053145836Smlaier			}
1054130613Smlaier#ifdef __FreeBSD__
1055130613Smlaier			PF_UNLOCK();
1056130613Smlaier#endif
1057130613Smlaier			break;
1058130613Smlaier		}
1059145836Smlaier
1060145836Smlaier		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
1061130613Smlaier#ifdef __FreeBSD__
1062130613Smlaier			PF_UNLOCK();
1063130613Smlaier#endif
1064130613Smlaier			return (EINVAL);
1065130613Smlaier		}
1066130613Smlaier
1067130613Smlaier		s = splnet();
1068141584Smlaier#ifdef __FreeBSD__
1069141584Smlaier		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
1070141584Smlaier#else
1071130613Smlaier		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1072141584Smlaier#endif
1073130613Smlaier		    (sc->sc_sync_ifp != NULL &&
1074130613Smlaier		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
1075130613Smlaier		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1076130613Smlaier			pfsync_sendout(sc);
1077130613Smlaier		sc->sc_sync_ifp = sifp;
1078130613Smlaier
1079141584Smlaier#ifdef __FreeBSD__
1080141584Smlaier		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
1081141584Smlaier#else
1082130613Smlaier		pfsync_setmtu(sc, sc->sc_if.if_mtu);
1083141584Smlaier#endif
1084130613Smlaier
1085130613Smlaier		if (imo->imo_num_memberships > 0) {
1086130613Smlaier			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1087130613Smlaier			imo->imo_multicast_ifp = NULL;
1088130613Smlaier		}
1089130613Smlaier
1090145836Smlaier		if (sc->sc_sync_ifp &&
1091145836Smlaier		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1092130613Smlaier			struct in_addr addr;
1093130613Smlaier
1094145836Smlaier			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
1095145836Smlaier				sc->sc_sync_ifp = NULL;
1096130613Smlaier#ifdef __FreeBSD__
1097145836Smlaier				PF_UNLOCK();
1098145836Smlaier#endif
1099145836Smlaier				splx(s);
1100145836Smlaier				return (EADDRNOTAVAIL);
1101145836Smlaier			}
1102145836Smlaier#ifdef __FreeBSD__
1103130613Smlaier			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
1104130613Smlaier			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1105130613Smlaier#else
1106130613Smlaier			addr.s_addr = INADDR_PFSYNC_GROUP;
1107130613Smlaier#endif
1108145836Smlaier
1109130613Smlaier			if ((imo->imo_membership[0] =
1110130613Smlaier			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
1111145836Smlaier				sc->sc_sync_ifp = NULL;
1112130613Smlaier				splx(s);
1113130613Smlaier				return (ENOBUFS);
1114130613Smlaier			}
1115130613Smlaier			imo->imo_num_memberships++;
1116130613Smlaier			imo->imo_multicast_ifp = sc->sc_sync_ifp;
1117130613Smlaier			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1118130613Smlaier			imo->imo_multicast_loop = 0;
1119145836Smlaier		}
1120130613Smlaier
1121145836Smlaier		if (sc->sc_sync_ifp ||
1122145836Smlaier		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
1123130613Smlaier			/* Request a full state table update. */
1124130613Smlaier#ifdef __FreeBSD__
1125130613Smlaier			PF_LOCK();
1126145836Smlaier#endif
1127130613Smlaier			sc->sc_ureq_sent = time_uptime;
1128145836Smlaier#if NCARP > 0
1129145836Smlaier			if (pfsync_sync_ok)
1130145836Smlaier				carp_suppress_preempt++;
1131130613Smlaier#endif
1132130613Smlaier			pfsync_sync_ok = 0;
1133130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1134130613Smlaier				printf("pfsync: requesting bulk update\n");
1135130613Smlaier#ifdef __FreeBSD__
1136130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1137130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
1138130613Smlaier#else
1139130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1140130613Smlaier#endif
1141145836Smlaier			error = pfsync_request_update(NULL, NULL);
1142145836Smlaier			if (error == ENOMEM) {
1143145836Smlaier#ifdef __FreeBSD__
1144145836Smlaier				PF_UNLOCK();
1145145836Smlaier#endif
1146145836Smlaier				splx(s);
1147145836Smlaier				return (ENOMEM);
1148145836Smlaier			}
1149130613Smlaier			pfsync_sendout(sc);
1150130613Smlaier		}
1151130613Smlaier#ifdef __FreeBSD__
1152130613Smlaier		PF_UNLOCK();
1153130613Smlaier#endif
1154130613Smlaier		splx(s);
1155130613Smlaier
1156130613Smlaier		break;
1157130613Smlaier
1158126258Smlaier	default:
1159126258Smlaier		return (ENOTTY);
1160126258Smlaier	}
1161126258Smlaier
1162126258Smlaier	return (0);
1163126258Smlaier}
1164126258Smlaier
1165126258Smlaiervoid
1166130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1167130613Smlaier{
1168126258Smlaier	int mtu;
1169130613Smlaier
1170130613Smlaier	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1171130613Smlaier		mtu = sc->sc_sync_ifp->if_mtu;
1172130613Smlaier	else
1173130613Smlaier		mtu = mtu_req;
1174130613Smlaier
1175130613Smlaier	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1176130613Smlaier	    sizeof(struct pfsync_state);
1177130613Smlaier	if (sc->sc_maxcount > 254)
1178130613Smlaier	    sc->sc_maxcount = 254;
1179141584Smlaier#ifdef __FreeBSD__
1180141584Smlaier	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
1181141584Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1182141584Smlaier#else
1183126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1184130613Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1185141584Smlaier#endif
1186126258Smlaier}
1187126258Smlaier
1188126258Smlaierstruct mbuf *
1189130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1190126258Smlaier{
1191126258Smlaier	struct pfsync_header *h;
1192126258Smlaier	struct mbuf *m;
1193126258Smlaier	int len;
1194126258Smlaier
1195130613Smlaier#ifdef __FreeBSD__
1196130613Smlaier	PF_ASSERT(MA_OWNED);
1197130613Smlaier#endif
1198126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
1199126258Smlaier	if (m == NULL) {
1200141584Smlaier#ifdef __FreeBSD__
1201141584Smlaier		SCP2IFP(sc)->if_oerrors++;
1202141584Smlaier#else
1203126258Smlaier		sc->sc_if.if_oerrors++;
1204141584Smlaier#endif
1205126258Smlaier		return (NULL);
1206126258Smlaier	}
1207126258Smlaier
1208130613Smlaier	switch (action) {
1209130613Smlaier	case PFSYNC_ACT_CLR:
1210130613Smlaier		len = sizeof(struct pfsync_header) +
1211130613Smlaier		    sizeof(struct pfsync_state_clr);
1212130613Smlaier		break;
1213130613Smlaier	case PFSYNC_ACT_UPD_C:
1214130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1215130613Smlaier		    sizeof(struct pfsync_header);
1216130613Smlaier		break;
1217130613Smlaier	case PFSYNC_ACT_DEL_C:
1218130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1219130613Smlaier		    sizeof(struct pfsync_header);
1220130613Smlaier		break;
1221130613Smlaier	case PFSYNC_ACT_UREQ:
1222130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1223130613Smlaier		    sizeof(struct pfsync_header);
1224130613Smlaier		break;
1225130613Smlaier	case PFSYNC_ACT_BUS:
1226130613Smlaier		len = sizeof(struct pfsync_header) +
1227130613Smlaier		    sizeof(struct pfsync_state_bus);
1228130613Smlaier		break;
1229130613Smlaier	default:
1230130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1231130613Smlaier		    sizeof(struct pfsync_header);
1232130613Smlaier		break;
1233130613Smlaier	}
1234130613Smlaier
1235126258Smlaier	if (len > MHLEN) {
1236126258Smlaier		MCLGET(m, M_DONTWAIT);
1237126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
1238126258Smlaier			m_free(m);
1239141584Smlaier#ifdef __FreeBSD__
1240141584Smlaier			SCP2IFP(sc)->if_oerrors++;
1241141584Smlaier#else
1242126258Smlaier			sc->sc_if.if_oerrors++;
1243141584Smlaier#endif
1244126258Smlaier			return (NULL);
1245126258Smlaier		}
1246130613Smlaier		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1247130613Smlaier	} else
1248130613Smlaier		MH_ALIGN(m, len);
1249130613Smlaier
1250126258Smlaier	m->m_pkthdr.rcvif = NULL;
1251130613Smlaier	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1252126258Smlaier	h = mtod(m, struct pfsync_header *);
1253126258Smlaier	h->version = PFSYNC_VERSION;
1254126258Smlaier	h->af = 0;
1255126258Smlaier	h->count = 0;
1256126258Smlaier	h->action = action;
1257126258Smlaier
1258130613Smlaier	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
1259127145Smlaier#ifdef __FreeBSD__
1260126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1261126261Smlaier	    LIST_FIRST(&pfsync_list));
1262126261Smlaier#else
1263126258Smlaier	timeout_add(&sc->sc_tmo, hz);
1264126261Smlaier#endif
1265126258Smlaier	return (m);
1266126258Smlaier}
1267126258Smlaier
1268126258Smlaierint
1269145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
1270126258Smlaier{
1271127145Smlaier#ifdef __FreeBSD__
1272141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1273126261Smlaier#else
1274126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1275130613Smlaier#endif
1276126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1277130613Smlaier	struct pfsync_header *h, *h_net;
1278130613Smlaier	struct pfsync_state *sp = NULL;
1279130613Smlaier	struct pfsync_state_upd *up = NULL;
1280130613Smlaier	struct pfsync_state_del *dp = NULL;
1281130613Smlaier	struct pf_rule *r;
1282126258Smlaier	u_long secs;
1283130613Smlaier	int s, ret = 0;
1284130613Smlaier	u_int8_t i = 255, newaction = 0;
1285126258Smlaier
1286130613Smlaier#ifdef __FreeBSD__
1287130613Smlaier	PF_ASSERT(MA_OWNED);
1288130613Smlaier#endif
1289130613Smlaier	/*
1290130613Smlaier	 * If a packet falls in the forest and there's nobody around to
1291130613Smlaier	 * hear, does it make a sound?
1292130613Smlaier	 */
1293145836Smlaier	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
1294145836Smlaier	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1295130613Smlaier		/* Don't leave any stale pfsync packets hanging around. */
1296130613Smlaier		if (sc->sc_mbuf != NULL) {
1297130613Smlaier			m_freem(sc->sc_mbuf);
1298130613Smlaier			sc->sc_mbuf = NULL;
1299130613Smlaier			sc->sc_statep.s = NULL;
1300130613Smlaier		}
1301130613Smlaier		return (0);
1302130613Smlaier	}
1303130613Smlaier
1304126258Smlaier	if (action >= PFSYNC_ACT_MAX)
1305126258Smlaier		return (EINVAL);
1306126258Smlaier
1307126258Smlaier	s = splnet();
1308130613Smlaier	if (sc->sc_mbuf == NULL) {
1309130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1310130613Smlaier		    (void *)&sc->sc_statep.s)) == NULL) {
1311126258Smlaier			splx(s);
1312126258Smlaier			return (ENOMEM);
1313126258Smlaier		}
1314130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1315126258Smlaier	} else {
1316130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1317126258Smlaier		if (h->action != action) {
1318126258Smlaier			pfsync_sendout(sc);
1319130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1320130613Smlaier			    (void *)&sc->sc_statep.s)) == NULL) {
1321126258Smlaier				splx(s);
1322126258Smlaier				return (ENOMEM);
1323126258Smlaier			}
1324130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1325130613Smlaier		} else {
1326130613Smlaier			/*
1327130613Smlaier			 * If it's an update, look in the packet to see if
1328130613Smlaier			 * we already have an update for the state.
1329130613Smlaier			 */
1330130613Smlaier			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1331130613Smlaier				struct pfsync_state *usp =
1332130613Smlaier				    (void *)((char *)h + PFSYNC_HDRLEN);
1333130613Smlaier
1334130613Smlaier				for (i = 0; i < h->count; i++) {
1335130613Smlaier					if (!memcmp(usp->id, &st->id,
1336130613Smlaier					    PFSYNC_ID_LEN) &&
1337130613Smlaier					    usp->creatorid == st->creatorid) {
1338130613Smlaier						sp = usp;
1339130613Smlaier						sp->updates++;
1340130613Smlaier						break;
1341130613Smlaier					}
1342130613Smlaier					usp++;
1343130613Smlaier				}
1344130613Smlaier			}
1345126258Smlaier		}
1346126258Smlaier	}
1347126258Smlaier
1348130613Smlaier	secs = time_second;
1349126258Smlaier
1350130613Smlaier	st->pfsync_time = time_uptime;
1351130613Smlaier	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1352130613Smlaier	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1353130613Smlaier
1354130613Smlaier	if (sp == NULL) {
1355130613Smlaier		/* not a "duplicate" update */
1356130613Smlaier		i = 255;
1357130613Smlaier		sp = sc->sc_statep.s++;
1358130613Smlaier		sc->sc_mbuf->m_pkthdr.len =
1359130613Smlaier		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1360130613Smlaier		h->count++;
1361130613Smlaier		bzero(sp, sizeof(*sp));
1362130613Smlaier
1363130613Smlaier		bcopy(&st->id, sp->id, sizeof(sp->id));
1364130613Smlaier		sp->creatorid = st->creatorid;
1365130613Smlaier
1366130613Smlaier		strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1367130613Smlaier		pf_state_host_hton(&st->lan, &sp->lan);
1368130613Smlaier		pf_state_host_hton(&st->gwy, &sp->gwy);
1369130613Smlaier		pf_state_host_hton(&st->ext, &sp->ext);
1370130613Smlaier
1371130613Smlaier		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1372130613Smlaier
1373130613Smlaier		sp->creation = htonl(secs - st->creation);
1374130613Smlaier		sp->packets[0] = htonl(st->packets[0]);
1375130613Smlaier		sp->packets[1] = htonl(st->packets[1]);
1376130613Smlaier		sp->bytes[0] = htonl(st->bytes[0]);
1377130613Smlaier		sp->bytes[1] = htonl(st->bytes[1]);
1378130613Smlaier		if ((r = st->rule.ptr) == NULL)
1379130613Smlaier			sp->rule = htonl(-1);
1380130613Smlaier		else
1381130613Smlaier			sp->rule = htonl(r->nr);
1382130613Smlaier		if ((r = st->anchor.ptr) == NULL)
1383130613Smlaier			sp->anchor = htonl(-1);
1384130613Smlaier		else
1385130613Smlaier			sp->anchor = htonl(r->nr);
1386130613Smlaier		sp->af = st->af;
1387130613Smlaier		sp->proto = st->proto;
1388130613Smlaier		sp->direction = st->direction;
1389130613Smlaier		sp->log = st->log;
1390130613Smlaier		sp->allow_opts = st->allow_opts;
1391130613Smlaier		sp->timeout = st->timeout;
1392130613Smlaier
1393145836Smlaier		if (flags & PFSYNC_FLAG_STALE)
1394145836Smlaier			sp->sync_flags |= PFSTATE_STALE;
1395130613Smlaier	}
1396130613Smlaier
1397126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
1398126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
1399126258Smlaier
1400126258Smlaier	if (st->expire <= secs)
1401126258Smlaier		sp->expire = htonl(0);
1402126258Smlaier	else
1403126258Smlaier		sp->expire = htonl(st->expire - secs);
1404126258Smlaier
1405130613Smlaier	/* do we need to build "compressed" actions for network transfer? */
1406145836Smlaier	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
1407130613Smlaier		switch (action) {
1408130613Smlaier		case PFSYNC_ACT_UPD:
1409130613Smlaier			newaction = PFSYNC_ACT_UPD_C;
1410130613Smlaier			break;
1411130613Smlaier		case PFSYNC_ACT_DEL:
1412130613Smlaier			newaction = PFSYNC_ACT_DEL_C;
1413130613Smlaier			break;
1414130613Smlaier		default:
1415130613Smlaier			/* by default we just send the uncompressed states */
1416130613Smlaier			break;
1417130613Smlaier		}
1418130613Smlaier	}
1419130613Smlaier
1420130613Smlaier	if (newaction) {
1421130613Smlaier		if (sc->sc_mbuf_net == NULL) {
1422130613Smlaier			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1423130613Smlaier			    (void *)&sc->sc_statep_net.s)) == NULL) {
1424130613Smlaier				splx(s);
1425130613Smlaier				return (ENOMEM);
1426130613Smlaier			}
1427130613Smlaier		}
1428130613Smlaier		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1429130613Smlaier
1430130613Smlaier		switch (newaction) {
1431130613Smlaier		case PFSYNC_ACT_UPD_C:
1432130613Smlaier			if (i != 255) {
1433130613Smlaier				up = (void *)((char *)h_net +
1434130613Smlaier				    PFSYNC_HDRLEN + (i * sizeof(*up)));
1435130613Smlaier				up->updates++;
1436130613Smlaier			} else {
1437130613Smlaier				h_net->count++;
1438130613Smlaier				sc->sc_mbuf_net->m_pkthdr.len =
1439130613Smlaier				    sc->sc_mbuf_net->m_len += sizeof(*up);
1440130613Smlaier				up = sc->sc_statep_net.u++;
1441130613Smlaier
1442130613Smlaier				bzero(up, sizeof(*up));
1443130613Smlaier				bcopy(&st->id, up->id, sizeof(up->id));
1444130613Smlaier				up->creatorid = st->creatorid;
1445130613Smlaier			}
1446130613Smlaier			up->timeout = st->timeout;
1447130613Smlaier			up->expire = sp->expire;
1448130613Smlaier			up->src = sp->src;
1449130613Smlaier			up->dst = sp->dst;
1450130613Smlaier			break;
1451130613Smlaier		case PFSYNC_ACT_DEL_C:
1452130613Smlaier			sc->sc_mbuf_net->m_pkthdr.len =
1453130613Smlaier			    sc->sc_mbuf_net->m_len += sizeof(*dp);
1454130613Smlaier			dp = sc->sc_statep_net.d++;
1455130613Smlaier			h_net->count++;
1456130613Smlaier
1457130613Smlaier			bzero(dp, sizeof(*dp));
1458130613Smlaier			bcopy(&st->id, dp->id, sizeof(dp->id));
1459130613Smlaier			dp->creatorid = st->creatorid;
1460130613Smlaier			break;
1461130613Smlaier		}
1462130613Smlaier	}
1463130613Smlaier
1464130613Smlaier	if (h->count == sc->sc_maxcount ||
1465130613Smlaier	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1466126258Smlaier		ret = pfsync_sendout(sc);
1467126258Smlaier
1468126258Smlaier	splx(s);
1469130613Smlaier	return (ret);
1470126258Smlaier}
1471126258Smlaier
1472130613Smlaier/* This must be called in splnet() */
1473126258Smlaierint
1474130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1475126258Smlaier{
1476127145Smlaier#ifdef __FreeBSD__
1477141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1478126261Smlaier#else
1479126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1480130613Smlaier#endif
1481130613Smlaier	struct pfsync_header *h;
1482126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1483130613Smlaier	struct pfsync_state_upd_req *rup;
1484145836Smlaier	int ret = 0;
1485130613Smlaier
1486130613Smlaier#ifdef __FreeBSD__
1487130613Smlaier	PF_ASSERT(MA_OWNED);
1488126261Smlaier#endif
1489130613Smlaier	if (sc->sc_mbuf == NULL) {
1490130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1491145836Smlaier		    (void *)&sc->sc_statep.s)) == NULL)
1492130613Smlaier			return (ENOMEM);
1493130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1494130613Smlaier	} else {
1495130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1496130613Smlaier		if (h->action != PFSYNC_ACT_UREQ) {
1497130613Smlaier			pfsync_sendout(sc);
1498130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1499145836Smlaier			    (void *)&sc->sc_statep.s)) == NULL)
1500130613Smlaier				return (ENOMEM);
1501130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1502130613Smlaier		}
1503130613Smlaier	}
1504130613Smlaier
1505130613Smlaier	if (src != NULL)
1506130613Smlaier		sc->sc_sendaddr = *src;
1507130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1508130613Smlaier	h->count++;
1509130613Smlaier	rup = sc->sc_statep.r++;
1510130613Smlaier	bzero(rup, sizeof(*rup));
1511130613Smlaier	if (up != NULL) {
1512130613Smlaier		bcopy(up->id, rup->id, sizeof(rup->id));
1513130613Smlaier		rup->creatorid = up->creatorid;
1514130613Smlaier	}
1515130613Smlaier
1516130613Smlaier	if (h->count == sc->sc_maxcount)
1517130613Smlaier		ret = pfsync_sendout(sc);
1518130613Smlaier
1519130613Smlaier	return (ret);
1520130613Smlaier}
1521130613Smlaier
1522130613Smlaierint
1523130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname)
1524130613Smlaier{
1525130613Smlaier#ifdef __FreeBSD__
1526141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1527130613Smlaier#else
1528130613Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1529130613Smlaier#endif
1530130613Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1531130613Smlaier	struct pfsync_state_clr *cp;
1532126258Smlaier	int s, ret;
1533126258Smlaier
1534126258Smlaier	s = splnet();
1535130613Smlaier#ifdef __FreeBSD__
1536130613Smlaier	PF_ASSERT(MA_OWNED);
1537130613Smlaier#endif
1538130613Smlaier	if (sc->sc_mbuf != NULL)
1539130613Smlaier		pfsync_sendout(sc);
1540130613Smlaier	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1541130613Smlaier	    (void *)&sc->sc_statep.c)) == NULL) {
1542126258Smlaier		splx(s);
1543126258Smlaier		return (ENOMEM);
1544126258Smlaier	}
1545130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1546130613Smlaier	cp = sc->sc_statep.c;
1547130613Smlaier	cp->creatorid = creatorid;
1548130613Smlaier	if (ifname != NULL)
1549130613Smlaier		strlcpy(cp->ifname, ifname, IFNAMSIZ);
1550126258Smlaier
1551126258Smlaier	ret = (pfsync_sendout(sc));
1552126258Smlaier	splx(s);
1553126258Smlaier	return (ret);
1554126258Smlaier}
1555126258Smlaier
1556126258Smlaiervoid
1557126258Smlaierpfsync_timeout(void *v)
1558126258Smlaier{
1559126258Smlaier	struct pfsync_softc *sc = v;
1560126258Smlaier	int s;
1561126258Smlaier
1562126258Smlaier	s = splnet();
1563130613Smlaier#ifdef __FreeBSD__
1564130613Smlaier	PF_LOCK();
1565130613Smlaier#endif
1566126258Smlaier	pfsync_sendout(sc);
1567130613Smlaier#ifdef __FreeBSD__
1568130613Smlaier	PF_UNLOCK();
1569130613Smlaier#endif
1570126258Smlaier	splx(s);
1571126258Smlaier}
1572126258Smlaier
1573145836Smlaier/* This must be called in splnet() */
1574130613Smlaiervoid
1575130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1576130613Smlaier{
1577130613Smlaier	struct pfsync_state_bus *bus;
1578130613Smlaier
1579130613Smlaier#ifdef __FreeBSD__
1580130613Smlaier	PF_ASSERT(MA_OWNED);
1581130613Smlaier#endif
1582130613Smlaier	if (sc->sc_mbuf != NULL)
1583130613Smlaier		pfsync_sendout(sc);
1584130613Smlaier
1585130613Smlaier	if (pfsync_sync_ok &&
1586130613Smlaier	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1587130613Smlaier	    (void *)&sc->sc_statep.b)) != NULL) {
1588130613Smlaier		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1589130613Smlaier		bus = sc->sc_statep.b;
1590130613Smlaier		bus->creatorid = pf_status.hostid;
1591130613Smlaier		bus->status = status;
1592130613Smlaier		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1593130613Smlaier		pfsync_sendout(sc);
1594130613Smlaier	}
1595130613Smlaier}
1596130613Smlaier
1597130613Smlaiervoid
1598130613Smlaierpfsync_bulk_update(void *v)
1599130613Smlaier{
1600130613Smlaier	struct pfsync_softc *sc = v;
1601130613Smlaier	int s, i = 0;
1602130613Smlaier	struct pf_state *state;
1603130613Smlaier
1604130613Smlaier#ifdef __FreeBSD__
1605130613Smlaier	PF_LOCK();
1606130613Smlaier#endif
1607130613Smlaier	s = splnet();
1608130613Smlaier	if (sc->sc_mbuf != NULL)
1609130613Smlaier		pfsync_sendout(sc);
1610130613Smlaier
1611130613Smlaier	/*
1612130613Smlaier	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1613130613Smlaier	 * been sent since the latest request was made.
1614130613Smlaier	 */
1615130613Smlaier	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1616130613Smlaier	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1617130613Smlaier		if (state->pfsync_time > sc->sc_ureq_received) {
1618130613Smlaier			/* we're done */
1619130613Smlaier			pfsync_send_bus(sc, PFSYNC_BUS_END);
1620130613Smlaier			sc->sc_ureq_received = 0;
1621130613Smlaier#ifdef __FreeBSD__
1622130613Smlaier			callout_stop(&sc->sc_bulk_tmo);
1623130613Smlaier#else
1624130613Smlaier			timeout_del(&sc->sc_bulk_tmo);
1625130613Smlaier#endif
1626130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1627130613Smlaier				printf("pfsync: bulk update complete\n");
1628130613Smlaier			break;
1629130613Smlaier		} else {
1630130613Smlaier			/* send an update and move to end of list */
1631130613Smlaier			if (!state->sync_flags)
1632130613Smlaier				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1633130613Smlaier			state->pfsync_time = time_uptime;
1634130613Smlaier			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1635130613Smlaier			TAILQ_INSERT_TAIL(&state_updates, state,
1636130613Smlaier			    u.s.entry_updates);
1637130613Smlaier
1638130613Smlaier			/* look again for more in a bit */
1639130613Smlaier#ifdef __FreeBSD__
1640130613Smlaier			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1641130613Smlaier			    LIST_FIRST(&pfsync_list));
1642130613Smlaier#else
1643130613Smlaier			timeout_add(&sc->sc_bulk_tmo, 1);
1644130613Smlaier#endif
1645130613Smlaier		}
1646130613Smlaier	}
1647130613Smlaier	if (sc->sc_mbuf != NULL)
1648130613Smlaier		pfsync_sendout(sc);
1649130613Smlaier	splx(s);
1650130613Smlaier#ifdef __FreeBSD__
1651130613Smlaier	PF_UNLOCK();
1652130613Smlaier#endif
1653130613Smlaier}
1654130613Smlaier
1655130613Smlaiervoid
1656130613Smlaierpfsync_bulkfail(void *v)
1657130613Smlaier{
1658130613Smlaier	struct pfsync_softc *sc = v;
1659145836Smlaier	int s, error;
1660130613Smlaier
1661130613Smlaier#ifdef __FreeBSD__
1662130613Smlaier	PF_LOCK();
1663130613Smlaier#endif
1664130613Smlaier	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1665130613Smlaier		/* Try again in a bit */
1666130613Smlaier#ifdef __FreeBSD__
1667130613Smlaier		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1668130613Smlaier		    LIST_FIRST(&pfsync_list));
1669130613Smlaier#else
1670130613Smlaier		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1671130613Smlaier#endif
1672145836Smlaier		s = splnet();
1673145836Smlaier		error = pfsync_request_update(NULL, NULL);
1674145836Smlaier		if (error == ENOMEM) {
1675145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1676145836Smlaier				printf("pfsync: cannot allocate mbufs for "
1677145836Smlaier				    "bulk update\n");
1678145836Smlaier		} else
1679145836Smlaier			pfsync_sendout(sc);
1680145836Smlaier		splx(s);
1681130613Smlaier	} else {
1682130613Smlaier		/* Pretend like the transfer was ok */
1683130613Smlaier		sc->sc_ureq_sent = 0;
1684130613Smlaier		sc->sc_bulk_tries = 0;
1685145836Smlaier#if NCARP > 0
1686145836Smlaier		if (!pfsync_sync_ok)
1687145836Smlaier			carp_suppress_preempt--;
1688145836Smlaier#endif
1689130613Smlaier		pfsync_sync_ok = 1;
1690130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
1691130613Smlaier			printf("pfsync: failed to receive "
1692130613Smlaier			    "bulk update status\n");
1693130613Smlaier#ifdef __FreeBSD__
1694130613Smlaier		callout_stop(&sc->sc_bulkfail_tmo);
1695130613Smlaier#else
1696130613Smlaier		timeout_del(&sc->sc_bulkfail_tmo);
1697130613Smlaier#endif
1698130613Smlaier	}
1699130613Smlaier#ifdef __FreeBSD__
1700130613Smlaier	PF_UNLOCK();
1701130613Smlaier#endif
1702130613Smlaier}
1703130613Smlaier
1704145836Smlaier/* This must be called in splnet() */
1705126258Smlaierint
1706126258Smlaierpfsync_sendout(sc)
1707126258Smlaier	struct pfsync_softc *sc;
1708126258Smlaier{
1709138666Smlaier#if NBPFILTER > 0
1710141584Smlaier# ifdef __FreeBSD__
1711141584Smlaier	struct ifnet *ifp = SCP2IFP(sc);
1712141584Smlaier# else
1713141584Smlaier	struct ifnet *ifp = &sc->if_sc;
1714141584Smlaier# endif
1715138666Smlaier#endif
1716130613Smlaier	struct mbuf *m;
1717126258Smlaier
1718127145Smlaier#ifdef __FreeBSD__
1719130613Smlaier	PF_ASSERT(MA_OWNED);
1720126261Smlaier	callout_stop(&sc->sc_tmo);
1721126261Smlaier#else
1722126258Smlaier	timeout_del(&sc->sc_tmo);
1723126261Smlaier#endif
1724130613Smlaier
1725130613Smlaier	if (sc->sc_mbuf == NULL)
1726130613Smlaier		return (0);
1727130613Smlaier	m = sc->sc_mbuf;
1728126258Smlaier	sc->sc_mbuf = NULL;
1729130613Smlaier	sc->sc_statep.s = NULL;
1730126258Smlaier
1731127145Smlaier#ifdef __FreeBSD__
1732126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1733126261Smlaier#endif
1734126258Smlaier#if NBPFILTER > 0
1735126258Smlaier	if (ifp->if_bpf)
1736126258Smlaier		bpf_mtap(ifp->if_bpf, m);
1737126258Smlaier#endif
1738126258Smlaier
1739130613Smlaier	if (sc->sc_mbuf_net) {
1740130613Smlaier		m_freem(m);
1741130613Smlaier		m = sc->sc_mbuf_net;
1742130613Smlaier		sc->sc_mbuf_net = NULL;
1743130613Smlaier		sc->sc_statep_net.s = NULL;
1744130613Smlaier	}
1745126258Smlaier
1746145836Smlaier	if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1747130613Smlaier		struct ip *ip;
1748130613Smlaier		struct sockaddr sa;
1749130613Smlaier
1750130613Smlaier		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1751130613Smlaier		if (m == NULL) {
1752130613Smlaier			pfsyncstats.pfsyncs_onomem++;
1753130613Smlaier			return (0);
1754130613Smlaier		}
1755130613Smlaier		ip = mtod(m, struct ip *);
1756130613Smlaier		ip->ip_v = IPVERSION;
1757130613Smlaier		ip->ip_hl = sizeof(*ip) >> 2;
1758130613Smlaier		ip->ip_tos = IPTOS_LOWDELAY;
1759130613Smlaier#ifdef __FreeBSD__
1760130613Smlaier		ip->ip_len = m->m_pkthdr.len;
1761130613Smlaier#else
1762130613Smlaier		ip->ip_len = htons(m->m_pkthdr.len);
1763130613Smlaier#endif
1764130613Smlaier		ip->ip_id = htons(ip_randomid());
1765130613Smlaier#ifdef __FreeBSD__
1766130613Smlaier		ip->ip_off = IP_DF;
1767130613Smlaier#else
1768130613Smlaier		ip->ip_off = htons(IP_DF);
1769130613Smlaier#endif
1770130613Smlaier		ip->ip_ttl = PFSYNC_DFLTTL;
1771130613Smlaier		ip->ip_p = IPPROTO_PFSYNC;
1772130613Smlaier		ip->ip_sum = 0;
1773130613Smlaier
1774130613Smlaier		bzero(&sa, sizeof(sa));
1775145836Smlaier		ip->ip_src.s_addr = INADDR_ANY;
1776130613Smlaier
1777130613Smlaier#ifdef __FreeBSD__
1778130613Smlaier		if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1779130613Smlaier#else
1780130613Smlaier		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1781130613Smlaier#endif
1782130613Smlaier			m->m_flags |= M_MCAST;
1783130613Smlaier		ip->ip_dst = sc->sc_sendaddr;
1784130613Smlaier#ifdef __FreeBSD__
1785145836Smlaier		/* XXX_IMPORT */
1786145836Smlaier		sc->sc_sendaddr.s_addr = htonl(sc->sc_sync_peer.s_addr);
1787130613Smlaier#else
1788145836Smlaier		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
1789130613Smlaier#endif
1790130613Smlaier
1791130613Smlaier		pfsyncstats.pfsyncs_opackets++;
1792130613Smlaier
1793130613Smlaier#ifdef __FreeBSD__
1794130613Smlaier		PF_UNLOCK();
1795130613Smlaier#endif
1796130613Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1797130613Smlaier			pfsyncstats.pfsyncs_oerrors++;
1798130613Smlaier
1799130613Smlaier#ifdef __FreeBSD__
1800130613Smlaier		PF_LOCK();
1801130613Smlaier#endif
1802130613Smlaier	} else
1803130613Smlaier		m_freem(m);
1804130613Smlaier
1805126258Smlaier	return (0);
1806126258Smlaier}
1807126261Smlaier
1808126261Smlaier
1809127145Smlaier#ifdef __FreeBSD__
1810126261Smlaierstatic int
1811126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
1812126261Smlaier{
1813126261Smlaier	int error = 0;
1814126261Smlaier
1815126261Smlaier	switch (type) {
1816126261Smlaier	case MOD_LOAD:
1817126261Smlaier		LIST_INIT(&pfsync_list);
1818126261Smlaier		if_clone_attach(&pfsync_cloner);
1819126261Smlaier		break;
1820126261Smlaier
1821126261Smlaier	case MOD_UNLOAD:
1822126261Smlaier		if_clone_detach(&pfsync_cloner);
1823126261Smlaier		while (!LIST_EMPTY(&pfsync_list))
1824126261Smlaier			pfsync_clone_destroy(
1825141584Smlaier			    SCP2IFP(LIST_FIRST(&pfsync_list)));
1826126261Smlaier		break;
1827126261Smlaier
1828126261Smlaier	default:
1829126261Smlaier		error = EINVAL;
1830126261Smlaier		break;
1831126261Smlaier	}
1832126261Smlaier
1833126261Smlaier	return error;
1834126261Smlaier}
1835126261Smlaier
1836126261Smlaierstatic moduledata_t pfsync_mod = {
1837126261Smlaier	"pfsync",
1838126261Smlaier	pfsync_modevent,
1839126261Smlaier	0
1840126261Smlaier};
1841126261Smlaier
1842126261Smlaier#define PFSYNC_MODVER 1
1843126261Smlaier
1844135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1845126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
1846126261Smlaier#endif /* __FreeBSD__ */
1847