if_pfsync.c revision 167710
1/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 167710 2007-03-19 17:52:15Z bms $	*/
2/*	$OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $	*/
3
4/*
5 * Copyright (c) 2002 Michael Shalayeff
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifdef __FreeBSD__
31#include "opt_inet.h"
32#include "opt_inet6.h"
33#endif
34
35#ifndef __FreeBSD__
36#include "bpfilter.h"
37#include "pfsync.h"
38#elif __FreeBSD__ >= 5
39#include "opt_bpf.h"
40#include "opt_pf.h"
41
42#ifdef DEV_BPF
43#define	NBPFILTER	DEV_BPF
44#else
45#define	NBPFILTER	0
46#endif
47
48#ifdef DEV_PFSYNC
49#define	NPFSYNC		DEV_PFSYNC
50#else
51#define	NPFSYNC		0
52#endif
53
54#endif
55
56#include <sys/param.h>
57#ifdef __FreeBSD__
58#include <sys/priv.h>
59#endif
60#include <sys/proc.h>
61#include <sys/systm.h>
62#include <sys/time.h>
63#include <sys/mbuf.h>
64#include <sys/socket.h>
65#include <sys/kernel.h>
66#ifdef __FreeBSD__
67#include <sys/endian.h>
68#include <sys/malloc.h>
69#include <sys/module.h>
70#include <sys/sockio.h>
71#include <sys/lock.h>
72#include <sys/mutex.h>
73#include <sys/sysctl.h>
74#else
75#include <sys/ioctl.h>
76#include <sys/timeout.h>
77#endif
78
79#include <net/if.h>
80#if defined(__FreeBSD__)
81#include <net/if_clone.h>
82#endif
83#include <net/if_types.h>
84#include <net/route.h>
85#include <net/bpf.h>
86#include <netinet/tcp.h>
87#include <netinet/tcp_seq.h>
88
89#ifdef	INET
90#include <netinet/in.h>
91#include <netinet/in_systm.h>
92#include <netinet/in_var.h>
93#include <netinet/ip.h>
94#include <netinet/ip_var.h>
95#endif
96
97#ifdef INET6
98#ifndef INET
99#include <netinet/in.h>
100#endif
101#include <netinet6/nd6.h>
102#endif /* INET6 */
103
104#ifdef __FreeBSD__
105#include "opt_carp.h"
106#ifdef DEV_CARP
107#define	NCARP	1
108#else
109#define	NCARP	0
110#endif
111#else
112#include "carp.h"
113#endif
114#if NCARP > 0
115extern int carp_suppress_preempt;
116#endif
117
118#include <net/pfvar.h>
119#include <net/if_pfsync.h>
120
121#ifdef __FreeBSD__
122#define	PFSYNCNAME	"pfsync"
123#endif
124
125#define PFSYNC_MINMTU	\
126    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
127
128#ifdef PFSYNCDEBUG
129#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
130int pfsyncdebug;
131#else
132#define DPRINTF(x)
133#endif
134
135#ifndef __FreeBSD__
136struct pfsync_softc	pfsyncif;
137#endif
138struct pfsyncstats	pfsyncstats;
139#ifdef __FreeBSD__
140SYSCTL_DECL(_net_inet_pfsync);
141SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
142    &pfsyncstats, pfsyncstats,
143    "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
144
145/*
146 * Locking notes:
147 * Whenever we really touch/look at the state table we have to hold the
148 * PF_LOCK. Functions that do just the interface handling, grab the per
149 * softc lock instead.
150 *
151 */
152
153static void	pfsync_clone_destroy(struct ifnet *);
154static int	pfsync_clone_create(struct if_clone *, int, caddr_t params);
155static void	pfsync_senddef(void *);
156#else
157void	pfsyncattach(int);
158#endif
159void	pfsync_setmtu(struct pfsync_softc *, int);
160int	pfsync_insert_net_state(struct pfsync_state *);
161int	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
162	    struct rtentry *);
163int	pfsyncioctl(struct ifnet *, u_long, caddr_t);
164void	pfsyncstart(struct ifnet *);
165
166struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
167int	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
168int	pfsync_sendout(struct pfsync_softc *);
169void	pfsync_timeout(void *);
170void	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
171void	pfsync_bulk_update(void *);
172void	pfsync_bulkfail(void *);
173#ifdef __FreeBSD__
174static void	pfsync_ifdetach(void *, struct ifnet *);
175#endif
176
177int	pfsync_sync_ok;
178#ifndef __FreeBSD__
179extern int ifqmaxlen;
180extern struct timeval time;
181extern struct timeval mono_time;
182extern int hz;
183#endif
184
185#ifdef __FreeBSD__
186static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
187static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
188#define	SCP2IFP(sc)		((sc)->sc_ifp)
189IFC_SIMPLE_DECLARE(pfsync, 1);
190
191static void
192pfsync_clone_destroy(struct ifnet *ifp)
193{
194        struct pfsync_softc *sc;
195
196	sc = ifp->if_softc;
197#ifdef __FreeBSD__
198	EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
199#endif
200	callout_stop(&sc->sc_tmo);
201	callout_stop(&sc->sc_bulk_tmo);
202	callout_stop(&sc->sc_bulkfail_tmo);
203
204	callout_stop(&sc->sc_send_tmo);
205
206#if NBPFILTER > 0
207        bpfdetach(ifp);
208#endif
209        if_detach(ifp);
210	if_free(ifp);
211        LIST_REMOVE(sc, sc_next);
212        free(sc->sc_imo.imo_membership, M_PFSYNC);
213        free(sc, M_PFSYNC);
214}
215
216static int
217#ifdef __FreeBSD__
218pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params)
219#else
220pfsync_clone_create(struct if_clone *ifc, int unit)
221#endif
222{
223	struct pfsync_softc *sc;
224	struct ifnet *ifp;
225
226	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
227	    M_WAITOK|M_ZERO);
228	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
229	if (ifp == NULL) {
230		free(sc, M_PFSYNC);
231		return (ENOSPC);
232	}
233
234#ifdef __FreeBSD__
235	sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
236	    pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY);
237	if (sc->sc_detachtag == NULL) {
238		if_free(ifp);
239		free(sc, M_PFSYNC);
240		return (ENOSPC);
241	}
242#endif
243
244	pfsync_sync_ok = 1;
245	sc->sc_mbuf = NULL;
246	sc->sc_mbuf_net = NULL;
247	sc->sc_statep.s = NULL;
248	sc->sc_statep_net.s = NULL;
249	sc->sc_maxupdates = 128;
250	sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
251	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
252	sc->sc_ureq_received = 0;
253	sc->sc_ureq_sent = 0;
254	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
255	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC,
256	    M_WAITOK);
257	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
258
259	ifp = SCP2IFP(sc);
260	if_initname(ifp, ifc->ifc_name, unit);
261	ifp->if_ioctl = pfsyncioctl;
262	ifp->if_output = pfsyncoutput;
263	ifp->if_start = pfsyncstart;
264	ifp->if_snd.ifq_maxlen = ifqmaxlen;
265	ifp->if_hdrlen = PFSYNC_HDRLEN;
266	ifp->if_baudrate = IF_Mbps(100);
267	ifp->if_softc = sc;
268	pfsync_setmtu(sc, MCLBYTES);
269	callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
270	callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
271	callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
272	callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
273	sc->sc_ifq.ifq_maxlen = ifqmaxlen;
274	mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
275	    MTX_DEF);
276	if_attach(ifp);
277
278	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
279#if NBPFILTER > 0
280	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
281#endif
282
283	return (0);
284}
285#else /* !__FreeBSD__ */
286void
287pfsyncattach(int npfsync)
288{
289	struct ifnet *ifp;
290
291	pfsync_sync_ok = 1;
292	bzero(&pfsyncif, sizeof(pfsyncif));
293	pfsyncif.sc_mbuf = NULL;
294	pfsyncif.sc_mbuf_net = NULL;
295	pfsyncif.sc_statep.s = NULL;
296	pfsyncif.sc_statep_net.s = NULL;
297	pfsyncif.sc_maxupdates = 128;
298	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
299	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
300	pfsyncif.sc_ureq_received = 0;
301	pfsyncif.sc_ureq_sent = 0;
302	ifp = &pfsyncif.sc_if;
303	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
304	ifp->if_softc = &pfsyncif;
305	ifp->if_ioctl = pfsyncioctl;
306	ifp->if_output = pfsyncoutput;
307	ifp->if_start = pfsyncstart;
308	ifp->if_type = IFT_PFSYNC;
309	ifp->if_snd.ifq_maxlen = ifqmaxlen;
310	ifp->if_hdrlen = PFSYNC_HDRLEN;
311	pfsync_setmtu(&pfsyncif, MCLBYTES);
312	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
313	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
314	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
315	if_attach(ifp);
316	if_alloc_sadl(ifp);
317
318#if NBPFILTER > 0
319	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
320#endif
321}
322#endif
323
324/*
325 * Start output on the pfsync interface.
326 */
327void
328pfsyncstart(struct ifnet *ifp)
329{
330#ifdef __FreeBSD__
331	IF_LOCK(&ifp->if_snd);
332	_IF_DROP(&ifp->if_snd);
333	_IF_DRAIN(&ifp->if_snd);
334	IF_UNLOCK(&ifp->if_snd);
335#else
336	struct mbuf *m;
337	int s;
338
339	for (;;) {
340		s = splimp();
341		IF_DROP(&ifp->if_snd);
342		IF_DEQUEUE(&ifp->if_snd, m);
343		splx(s);
344
345		if (m == NULL)
346			return;
347		else
348			m_freem(m);
349	}
350#endif
351}
352
353int
354pfsync_insert_net_state(struct pfsync_state *sp)
355{
356	struct pf_state	*st = NULL;
357	struct pf_rule *r = NULL;
358	struct pfi_kif	*kif;
359
360#ifdef __FreeBSD__
361	PF_ASSERT(MA_OWNED);
362#endif
363	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
364		printf("pfsync_insert_net_state: invalid creator id:"
365		    " %08x\n", ntohl(sp->creatorid));
366		return (EINVAL);
367	}
368
369	kif = pfi_lookup_create(sp->ifname);
370	if (kif == NULL) {
371		if (pf_status.debug >= PF_DEBUG_MISC)
372			printf("pfsync_insert_net_state: "
373			    "unknown interface: %s\n", sp->ifname);
374		/* skip this state */
375		return (0);
376	}
377
378	/*
379	 * Just use the default rule until we have infrastructure to find the
380	 * best matching rule.
381	 */
382	r = &pf_default_rule;
383
384	if (!r->max_states || r->states < r->max_states)
385		st = pool_get(&pf_state_pl, PR_NOWAIT);
386	if (st == NULL) {
387		pfi_maybe_destroy(kif);
388		return (ENOMEM);
389	}
390	bzero(st, sizeof(*st));
391
392	st->rule.ptr = r;
393	/* XXX get pointers to nat_rule and anchor */
394
395	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
396	r->states++;
397
398	/* fill in the rest of the state entry */
399	pf_state_host_ntoh(&sp->lan, &st->lan);
400	pf_state_host_ntoh(&sp->gwy, &st->gwy);
401	pf_state_host_ntoh(&sp->ext, &st->ext);
402
403	pf_state_peer_ntoh(&sp->src, &st->src);
404	pf_state_peer_ntoh(&sp->dst, &st->dst);
405
406	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
407	st->creation = time_second - ntohl(sp->creation);
408	st->expire = ntohl(sp->expire) + time_second;
409
410	st->af = sp->af;
411	st->proto = sp->proto;
412	st->direction = sp->direction;
413	st->log = sp->log;
414	st->timeout = sp->timeout;
415	st->allow_opts = sp->allow_opts;
416
417	bcopy(sp->id, &st->id, sizeof(st->id));
418	st->creatorid = sp->creatorid;
419	st->sync_flags = PFSTATE_FROMSYNC;
420
421
422	if (pf_insert_state(kif, st)) {
423		pfi_maybe_destroy(kif);
424		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
425		r->states--;
426		pool_put(&pf_state_pl, st);
427		return (EINVAL);
428	}
429
430	return (0);
431}
432
433void
434#ifdef __FreeBSD__
435pfsync_input(struct mbuf *m, __unused int off)
436#else
437pfsync_input(struct mbuf *m, ...)
438#endif
439{
440	struct ip *ip = mtod(m, struct ip *);
441	struct pfsync_header *ph;
442#ifdef __FreeBSD__
443	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
444#else
445	struct pfsync_softc *sc = &pfsyncif;
446#endif
447	struct pf_state *st, key;
448	struct pfsync_state *sp;
449	struct pfsync_state_upd *up;
450	struct pfsync_state_del *dp;
451	struct pfsync_state_clr *cp;
452	struct pfsync_state_upd_req *rup;
453	struct pfsync_state_bus *bus;
454	struct in_addr src;
455	struct mbuf *mp;
456	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
457
458	pfsyncstats.pfsyncs_ipackets++;
459
460	/* verify that we have a sync interface configured */
461	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
462		goto done;
463
464	/* verify that the packet came in on the right interface */
465	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
466		pfsyncstats.pfsyncs_badif++;
467		goto done;
468	}
469
470	/* verify that the IP TTL is 255.  */
471	if (ip->ip_ttl != PFSYNC_DFLTTL) {
472		pfsyncstats.pfsyncs_badttl++;
473		goto done;
474	}
475
476	iplen = ip->ip_hl << 2;
477
478	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
479		pfsyncstats.pfsyncs_hdrops++;
480		goto done;
481	}
482
483	if (iplen + sizeof(*ph) > m->m_len) {
484		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
485			pfsyncstats.pfsyncs_hdrops++;
486			goto done;
487		}
488		ip = mtod(m, struct ip *);
489	}
490	ph = (struct pfsync_header *)((char *)ip + iplen);
491
492	/* verify the version */
493	if (ph->version != PFSYNC_VERSION) {
494		pfsyncstats.pfsyncs_badver++;
495		goto done;
496	}
497
498	action = ph->action;
499	count = ph->count;
500
501	/* make sure it's a valid action code */
502	if (action >= PFSYNC_ACT_MAX) {
503		pfsyncstats.pfsyncs_badact++;
504		goto done;
505	}
506
507	/* Cheaper to grab this now than having to mess with mbufs later */
508	src = ip->ip_src;
509
510	switch (action) {
511	case PFSYNC_ACT_CLR: {
512		struct pf_state *nexts;
513		struct pfi_kif	*kif;
514		u_int32_t creatorid;
515		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
516		    sizeof(*cp), &offp)) == NULL) {
517			pfsyncstats.pfsyncs_badlen++;
518			return;
519		}
520		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
521		creatorid = cp->creatorid;
522
523		s = splsoftnet();
524#ifdef __FreeBSD__
525		PF_LOCK();
526#endif
527		if (cp->ifname[0] == '\0') {
528			for (st = RB_MIN(pf_state_tree_id, &tree_id);
529			    st; st = nexts) {
530                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
531				if (st->creatorid == creatorid) {
532					st->timeout = PFTM_PURGE;
533					pf_purge_expired_state(st);
534				}
535			}
536		} else {
537			kif = pfi_lookup_if(cp->ifname);
538			if (kif == NULL) {
539				if (pf_status.debug >= PF_DEBUG_MISC)
540					printf("pfsync_input: PFSYNC_ACT_CLR "
541					    "bad interface: %s\n", cp->ifname);
542				splx(s);
543#ifdef __FreeBSD__
544				PF_UNLOCK();
545#endif
546				goto done;
547			}
548			for (st = RB_MIN(pf_state_tree_lan_ext,
549			    &kif->pfik_lan_ext); st; st = nexts) {
550				nexts = RB_NEXT(pf_state_tree_lan_ext,
551				    &kif->pfik_lan_ext, st);
552				if (st->creatorid == creatorid) {
553					st->timeout = PFTM_PURGE;
554					pf_purge_expired_state(st);
555				}
556			}
557		}
558#ifdef __FreeBSD__
559		PF_UNLOCK();
560#endif
561		splx(s);
562
563		break;
564	}
565	case PFSYNC_ACT_INS:
566		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
567		    count * sizeof(*sp), &offp)) == NULL) {
568			pfsyncstats.pfsyncs_badlen++;
569			return;
570		}
571
572		s = splsoftnet();
573#ifdef __FreeBSD__
574		PF_LOCK();
575#endif
576		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
577		    i < count; i++, sp++) {
578			/* check for invalid values */
579			if (sp->timeout >= PFTM_MAX ||
580			    sp->src.state > PF_TCPS_PROXY_DST ||
581			    sp->dst.state > PF_TCPS_PROXY_DST ||
582			    sp->direction > PF_OUT ||
583			    (sp->af != AF_INET && sp->af != AF_INET6)) {
584				if (pf_status.debug >= PF_DEBUG_MISC)
585					printf("pfsync_insert: PFSYNC_ACT_INS: "
586					    "invalid value\n");
587				pfsyncstats.pfsyncs_badstate++;
588				continue;
589			}
590
591			if ((error = pfsync_insert_net_state(sp))) {
592				if (error == ENOMEM) {
593					splx(s);
594#ifdef __FreeBSD__
595					PF_UNLOCK();
596#endif
597					goto done;
598				}
599				continue;
600			}
601		}
602#ifdef __FreeBSD__
603		PF_UNLOCK();
604#endif
605		splx(s);
606		break;
607	case PFSYNC_ACT_UPD:
608		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
609		    count * sizeof(*sp), &offp)) == NULL) {
610			pfsyncstats.pfsyncs_badlen++;
611			return;
612		}
613
614		s = splsoftnet();
615#ifdef __FreeBSD__
616		PF_LOCK();
617#endif
618		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
619		    i < count; i++, sp++) {
620			int flags = PFSYNC_FLAG_STALE;
621
622			/* check for invalid values */
623			if (sp->timeout >= PFTM_MAX ||
624			    sp->src.state > PF_TCPS_PROXY_DST ||
625			    sp->dst.state > PF_TCPS_PROXY_DST) {
626				if (pf_status.debug >= PF_DEBUG_MISC)
627					printf("pfsync_insert: PFSYNC_ACT_UPD: "
628					    "invalid value\n");
629				pfsyncstats.pfsyncs_badstate++;
630				continue;
631			}
632
633			bcopy(sp->id, &key.id, sizeof(key.id));
634			key.creatorid = sp->creatorid;
635
636			st = pf_find_state_byid(&key);
637			if (st == NULL) {
638				/* insert the update */
639				if (pfsync_insert_net_state(sp))
640					pfsyncstats.pfsyncs_badstate++;
641				continue;
642			}
643			sfail = 0;
644			if (st->proto == IPPROTO_TCP) {
645				/*
646				 * The state should never go backwards except
647				 * for syn-proxy states.  Neither should the
648				 * sequence window slide backwards.
649				 */
650				if (st->src.state > sp->src.state &&
651				    (st->src.state < PF_TCPS_PROXY_SRC ||
652				    sp->src.state >= PF_TCPS_PROXY_SRC))
653					sfail = 1;
654				else if (SEQ_GT(st->src.seqlo,
655				    ntohl(sp->src.seqlo)))
656					sfail = 3;
657				else if (st->dst.state > sp->dst.state) {
658					/* There might still be useful
659					 * information about the src state here,
660					 * so import that part of the update,
661					 * then "fail" so we send the updated
662					 * state back to the peer who is missing
663					 * our what we know. */
664					pf_state_peer_ntoh(&sp->src, &st->src);
665					/* XXX do anything with timeouts? */
666					sfail = 7;
667					flags = 0;
668				} else if (st->dst.state >= TCPS_SYN_SENT &&
669				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
670					sfail = 4;
671			} else {
672				/*
673				 * Non-TCP protocol state machine always go
674				 * forwards
675				 */
676				if (st->src.state > sp->src.state)
677					sfail = 5;
678				else if ( st->dst.state > sp->dst.state)
679					sfail = 6;
680			}
681			if (sfail) {
682				if (pf_status.debug >= PF_DEBUG_MISC)
683					printf("pfsync: %s stale update "
684					    "(%d) id: %016llx "
685					    "creatorid: %08x\n",
686					    (sfail < 7 ?  "ignoring"
687					     : "partial"), sfail,
688#ifdef __FreeBSD__
689					    (unsigned long long)be64toh(st->id),
690#else
691					    betoh64(st->id),
692#endif
693					    ntohl(st->creatorid));
694				pfsyncstats.pfsyncs_badstate++;
695
696				if (!(sp->sync_flags & PFSTATE_STALE)) {
697					/* we have a better state, send it */
698					if (sc->sc_mbuf != NULL && !stale)
699						pfsync_sendout(sc);
700					stale++;
701					if (!st->sync_flags)
702						pfsync_pack_state(
703						    PFSYNC_ACT_UPD, st, flags);
704				}
705				continue;
706			}
707			pf_state_peer_ntoh(&sp->src, &st->src);
708			pf_state_peer_ntoh(&sp->dst, &st->dst);
709			st->expire = ntohl(sp->expire) + time_second;
710			st->timeout = sp->timeout;
711		}
712		if (stale && sc->sc_mbuf != NULL)
713			pfsync_sendout(sc);
714#ifdef __FreeBSD__
715		PF_UNLOCK();
716#endif
717		splx(s);
718		break;
719	/*
720	 * It's not strictly necessary for us to support the "uncompressed"
721	 * delete action, but it's relatively simple and maintains consistency.
722	 */
723	case PFSYNC_ACT_DEL:
724		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
725		    count * sizeof(*sp), &offp)) == NULL) {
726			pfsyncstats.pfsyncs_badlen++;
727			return;
728		}
729
730		s = splsoftnet();
731#ifdef __FreeBSD__
732		PF_LOCK();
733#endif
734		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
735		    i < count; i++, sp++) {
736			bcopy(sp->id, &key.id, sizeof(key.id));
737			key.creatorid = sp->creatorid;
738
739			st = pf_find_state_byid(&key);
740			if (st == NULL) {
741				pfsyncstats.pfsyncs_badstate++;
742				continue;
743			}
744			st->timeout = PFTM_PURGE;
745			st->sync_flags |= PFSTATE_FROMSYNC;
746			pf_purge_expired_state(st);
747		}
748#ifdef __FreeBSD__
749		PF_UNLOCK();
750#endif
751		splx(s);
752		break;
753	case PFSYNC_ACT_UPD_C: {
754		int update_requested = 0;
755
756		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
757		    count * sizeof(*up), &offp)) == NULL) {
758			pfsyncstats.pfsyncs_badlen++;
759			return;
760		}
761
762		s = splsoftnet();
763#ifdef __FreeBSD__
764		PF_LOCK();
765#endif
766		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
767		    i < count; i++, up++) {
768			/* check for invalid values */
769			if (up->timeout >= PFTM_MAX ||
770			    up->src.state > PF_TCPS_PROXY_DST ||
771			    up->dst.state > PF_TCPS_PROXY_DST) {
772				if (pf_status.debug >= PF_DEBUG_MISC)
773					printf("pfsync_insert: "
774					    "PFSYNC_ACT_UPD_C: "
775					    "invalid value\n");
776				pfsyncstats.pfsyncs_badstate++;
777				continue;
778			}
779
780			bcopy(up->id, &key.id, sizeof(key.id));
781			key.creatorid = up->creatorid;
782
783			st = pf_find_state_byid(&key);
784			if (st == NULL) {
785				/* We don't have this state. Ask for it. */
786				error = pfsync_request_update(up, &src);
787				if (error == ENOMEM) {
788					splx(s);
789					goto done;
790				}
791				update_requested = 1;
792				pfsyncstats.pfsyncs_badstate++;
793				continue;
794			}
795			sfail = 0;
796			if (st->proto == IPPROTO_TCP) {
797				/*
798				 * The state should never go backwards except
799				 * for syn-proxy states.  Neither should the
800				 * sequence window slide backwards.
801				 */
802				if (st->src.state > up->src.state &&
803				    (st->src.state < PF_TCPS_PROXY_SRC ||
804				    up->src.state >= PF_TCPS_PROXY_SRC))
805					sfail = 1;
806				else if (st->dst.state > up->dst.state)
807					sfail = 2;
808				else if (SEQ_GT(st->src.seqlo,
809				    ntohl(up->src.seqlo)))
810					sfail = 3;
811				else if (st->dst.state >= TCPS_SYN_SENT &&
812				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
813					sfail = 4;
814			} else {
815				/*
816				 * Non-TCP protocol state machine always go
817				 * forwards
818				 */
819				if (st->src.state > up->src.state)
820					sfail = 5;
821				else if (st->dst.state > up->dst.state)
822					sfail = 6;
823			}
824			if (sfail) {
825				if (pf_status.debug >= PF_DEBUG_MISC)
826					printf("pfsync: ignoring stale update "
827					    "(%d) id: %016llx "
828					    "creatorid: %08x\n", sfail,
829#ifdef __FreeBSD__
830					    (unsigned long long)be64toh(st->id),
831#else
832					    betoh64(st->id),
833#endif
834					    ntohl(st->creatorid));
835				pfsyncstats.pfsyncs_badstate++;
836
837				/* we have a better state, send it out */
838				if ((!stale || update_requested) &&
839				    sc->sc_mbuf != NULL) {
840					pfsync_sendout(sc);
841					update_requested = 0;
842				}
843				stale++;
844				if (!st->sync_flags)
845					pfsync_pack_state(PFSYNC_ACT_UPD, st,
846					    PFSYNC_FLAG_STALE);
847				continue;
848			}
849			pf_state_peer_ntoh(&up->src, &st->src);
850			pf_state_peer_ntoh(&up->dst, &st->dst);
851			st->expire = ntohl(up->expire) + time_second;
852			st->timeout = up->timeout;
853		}
854		if ((update_requested || stale) && sc->sc_mbuf)
855			pfsync_sendout(sc);
856#ifdef __FreeBSD__
857		PF_UNLOCK();
858#endif
859		splx(s);
860		break;
861	}
862	case PFSYNC_ACT_DEL_C:
863		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
864		    count * sizeof(*dp), &offp)) == NULL) {
865			pfsyncstats.pfsyncs_badlen++;
866			return;
867		}
868
869		s = splsoftnet();
870#ifdef __FreeBSD__
871		PF_LOCK();
872#endif
873		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
874		    i < count; i++, dp++) {
875			bcopy(dp->id, &key.id, sizeof(key.id));
876			key.creatorid = dp->creatorid;
877
878			st = pf_find_state_byid(&key);
879			if (st == NULL) {
880				pfsyncstats.pfsyncs_badstate++;
881				continue;
882			}
883			st->timeout = PFTM_PURGE;
884			st->sync_flags |= PFSTATE_FROMSYNC;
885			pf_purge_expired_state(st);
886		}
887#ifdef __FreeBSD__
888		PF_UNLOCK();
889#endif
890		splx(s);
891		break;
892	case PFSYNC_ACT_INS_F:
893	case PFSYNC_ACT_DEL_F:
894		/* not implemented */
895		break;
896	case PFSYNC_ACT_UREQ:
897		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
898		    count * sizeof(*rup), &offp)) == NULL) {
899			pfsyncstats.pfsyncs_badlen++;
900			return;
901		}
902
903		s = splsoftnet();
904#ifdef __FreeBSD__
905		PF_LOCK();
906#endif
907		if (sc->sc_mbuf != NULL)
908			pfsync_sendout(sc);
909		for (i = 0,
910		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
911		    i < count; i++, rup++) {
912			bcopy(rup->id, &key.id, sizeof(key.id));
913			key.creatorid = rup->creatorid;
914
915			if (key.id == 0 && key.creatorid == 0) {
916				sc->sc_ureq_received = time_uptime;
917				if (pf_status.debug >= PF_DEBUG_MISC)
918					printf("pfsync: received "
919					    "bulk update request\n");
920				pfsync_send_bus(sc, PFSYNC_BUS_START);
921#ifdef __FreeBSD__
922				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
923				    pfsync_bulk_update,
924				    LIST_FIRST(&pfsync_list));
925#else
926				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
927#endif
928			} else {
929				st = pf_find_state_byid(&key);
930				if (st == NULL) {
931					pfsyncstats.pfsyncs_badstate++;
932					continue;
933				}
934				if (!st->sync_flags)
935					pfsync_pack_state(PFSYNC_ACT_UPD,
936					    st, 0);
937			}
938		}
939		if (sc->sc_mbuf != NULL)
940			pfsync_sendout(sc);
941#ifdef __FreeBSD__
942		PF_UNLOCK();
943#endif
944		splx(s);
945		break;
946	case PFSYNC_ACT_BUS:
947		/* If we're not waiting for a bulk update, who cares. */
948		if (sc->sc_ureq_sent == 0)
949			break;
950
951		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
952		    sizeof(*bus), &offp)) == NULL) {
953			pfsyncstats.pfsyncs_badlen++;
954			return;
955		}
956		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
957		switch (bus->status) {
958		case PFSYNC_BUS_START:
959#ifdef __FreeBSD__
960			callout_reset(&sc->sc_bulkfail_tmo,
961			    pf_pool_limits[PF_LIMIT_STATES].limit /
962			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
963			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
964#else
965			timeout_add(&sc->sc_bulkfail_tmo,
966			    pf_pool_limits[PF_LIMIT_STATES].limit /
967			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
968#endif
969			if (pf_status.debug >= PF_DEBUG_MISC)
970				printf("pfsync: received bulk "
971				    "update start\n");
972			break;
973		case PFSYNC_BUS_END:
974			if (time_uptime - ntohl(bus->endtime) >=
975			    sc->sc_ureq_sent) {
976				/* that's it, we're happy */
977				sc->sc_ureq_sent = 0;
978				sc->sc_bulk_tries = 0;
979#ifdef __FreeBSD__
980				callout_stop(&sc->sc_bulkfail_tmo);
981#else
982				timeout_del(&sc->sc_bulkfail_tmo);
983#endif
984#if NCARP > 0	/* XXX_IMPORT */
985				if (!pfsync_sync_ok)
986					carp_suppress_preempt--;
987#endif
988				pfsync_sync_ok = 1;
989				if (pf_status.debug >= PF_DEBUG_MISC)
990					printf("pfsync: received valid "
991					    "bulk update end\n");
992			} else {
993				if (pf_status.debug >= PF_DEBUG_MISC)
994					printf("pfsync: received invalid "
995					    "bulk update end: bad timestamp\n");
996			}
997			break;
998		}
999		break;
1000	}
1001
1002done:
1003	if (m)
1004		m_freem(m);
1005}
1006
1007int
1008pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1009	struct rtentry *rt)
1010{
1011	m_freem(m);
1012	return (0);
1013}
1014
1015/* ARGSUSED */
1016int
1017pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1018{
1019#ifndef __FreeBSD__
1020	struct proc *p = curproc;
1021#endif
1022	struct pfsync_softc *sc = ifp->if_softc;
1023	struct ifreq *ifr = (struct ifreq *)data;
1024	struct ip_moptions *imo = &sc->sc_imo;
1025	struct pfsyncreq pfsyncr;
1026	struct ifnet    *sifp;
1027	int s, error;
1028
1029	switch (cmd) {
1030	case SIOCSIFADDR:
1031	case SIOCAIFADDR:
1032	case SIOCSIFDSTADDR:
1033	case SIOCSIFFLAGS:
1034#ifdef __FreeBSD__
1035		if (ifp->if_flags & IFF_UP)
1036			ifp->if_drv_flags |= IFF_DRV_RUNNING;
1037		else
1038			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1039#else
1040		if (ifp->if_flags & IFF_UP)
1041			ifp->if_flags |= IFF_RUNNING;
1042		else
1043			ifp->if_flags &= ~IFF_RUNNING;
1044#endif
1045		break;
1046	case SIOCSIFMTU:
1047		if (ifr->ifr_mtu < PFSYNC_MINMTU)
1048			return (EINVAL);
1049		if (ifr->ifr_mtu > MCLBYTES)
1050			ifr->ifr_mtu = MCLBYTES;
1051		s = splnet();
1052#ifdef __FreeBSD__
1053		PF_LOCK();
1054#endif
1055		if (ifr->ifr_mtu < ifp->if_mtu) {
1056			pfsync_sendout(sc);
1057		}
1058		pfsync_setmtu(sc, ifr->ifr_mtu);
1059#ifdef __FreeBSD__
1060		PF_UNLOCK();
1061#endif
1062		splx(s);
1063		break;
1064	case SIOCGETPFSYNC:
1065#ifdef __FreeBSD__
1066		/* XXX: read unlocked */
1067#endif
1068		bzero(&pfsyncr, sizeof(pfsyncr));
1069		if (sc->sc_sync_ifp)
1070			strlcpy(pfsyncr.pfsyncr_syncdev,
1071			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
1072		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1073		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1074		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
1075			return (error);
1076		break;
1077	case SIOCSETPFSYNC:
1078#ifdef __FreeBSD__
1079		if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
1080#else
1081		if ((error = suser(p, p->p_acflag)) != 0)
1082#endif
1083			return (error);
1084		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1085			return (error);
1086
1087		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1088#ifdef __FreeBSD__
1089			sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
1090#else
1091			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1092#endif
1093		else
1094			sc->sc_sync_peer.s_addr =
1095			    pfsyncr.pfsyncr_syncpeer.s_addr;
1096
1097		if (pfsyncr.pfsyncr_maxupdates > 255)
1098			return (EINVAL);
1099#ifdef __FreeBSD__
1100		callout_drain(&sc->sc_send_tmo);
1101		PF_LOCK();
1102#endif
1103		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1104
1105		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1106			sc->sc_sync_ifp = NULL;
1107			if (sc->sc_mbuf_net != NULL) {
1108				/* Don't keep stale pfsync packets around. */
1109				s = splnet();
1110				m_freem(sc->sc_mbuf_net);
1111				sc->sc_mbuf_net = NULL;
1112				sc->sc_statep_net.s = NULL;
1113				splx(s);
1114			}
1115			if (imo->imo_num_memberships > 0) {
1116				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1117				imo->imo_multicast_ifp = NULL;
1118			}
1119#ifdef __FreeBSD__
1120			PF_UNLOCK();
1121#endif
1122			break;
1123		}
1124
1125		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
1126#ifdef __FreeBSD__
1127			PF_UNLOCK();
1128#endif
1129			return (EINVAL);
1130		}
1131
1132		s = splnet();
1133#ifdef __FreeBSD__
1134		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
1135#else
1136		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1137#endif
1138		    (sc->sc_sync_ifp != NULL &&
1139		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
1140		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1141			pfsync_sendout(sc);
1142		sc->sc_sync_ifp = sifp;
1143
1144#ifdef __FreeBSD__
1145		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
1146#else
1147		pfsync_setmtu(sc, sc->sc_if.if_mtu);
1148#endif
1149
1150		if (imo->imo_num_memberships > 0) {
1151			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1152			imo->imo_multicast_ifp = NULL;
1153		}
1154
1155		if (sc->sc_sync_ifp &&
1156#ifdef __FreeBSD__
1157		    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1158#else
1159		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1160#endif
1161			struct in_addr addr;
1162
1163			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
1164				sc->sc_sync_ifp = NULL;
1165#ifdef __FreeBSD__
1166				PF_UNLOCK();
1167#endif
1168				splx(s);
1169				return (EADDRNOTAVAIL);
1170			}
1171#ifdef __FreeBSD__
1172			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
1173			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1174#else
1175			addr.s_addr = INADDR_PFSYNC_GROUP;
1176#endif
1177
1178			if ((imo->imo_membership[0] =
1179			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
1180				sc->sc_sync_ifp = NULL;
1181				splx(s);
1182				return (ENOBUFS);
1183			}
1184			imo->imo_num_memberships++;
1185			imo->imo_multicast_ifp = sc->sc_sync_ifp;
1186			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1187			imo->imo_multicast_loop = 0;
1188#ifdef __FreeBSD__
1189			PF_LOCK();
1190#endif
1191		}
1192
1193		if (sc->sc_sync_ifp ||
1194#ifdef __FreeBSD__
1195		    sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
1196#else
1197		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
1198#endif
1199			/* Request a full state table update. */
1200			sc->sc_ureq_sent = time_uptime;
1201#if NCARP > 0
1202			if (pfsync_sync_ok)
1203				carp_suppress_preempt++;
1204#endif
1205			pfsync_sync_ok = 0;
1206			if (pf_status.debug >= PF_DEBUG_MISC)
1207				printf("pfsync: requesting bulk update\n");
1208#ifdef __FreeBSD__
1209			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1210			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
1211#else
1212			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1213#endif
1214			error = pfsync_request_update(NULL, NULL);
1215			if (error == ENOMEM) {
1216#ifdef __FreeBSD__
1217				PF_UNLOCK();
1218#endif
1219				splx(s);
1220				return (ENOMEM);
1221			}
1222			pfsync_sendout(sc);
1223		}
1224#ifdef __FreeBSD__
1225		PF_UNLOCK();
1226#endif
1227		splx(s);
1228
1229		break;
1230
1231	default:
1232		return (ENOTTY);
1233	}
1234
1235	return (0);
1236}
1237
1238void
1239pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1240{
1241	int mtu;
1242
1243	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1244		mtu = sc->sc_sync_ifp->if_mtu;
1245	else
1246		mtu = mtu_req;
1247
1248	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1249	    sizeof(struct pfsync_state);
1250	if (sc->sc_maxcount > 254)
1251	    sc->sc_maxcount = 254;
1252#ifdef __FreeBSD__
1253	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
1254	    sc->sc_maxcount * sizeof(struct pfsync_state);
1255#else
1256	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1257	    sc->sc_maxcount * sizeof(struct pfsync_state);
1258#endif
1259}
1260
1261struct mbuf *
1262pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1263{
1264	struct pfsync_header *h;
1265	struct mbuf *m;
1266	int len;
1267
1268#ifdef __FreeBSD__
1269	PF_ASSERT(MA_OWNED);
1270#endif
1271	MGETHDR(m, M_DONTWAIT, MT_DATA);
1272	if (m == NULL) {
1273#ifdef __FreeBSD__
1274		SCP2IFP(sc)->if_oerrors++;
1275#else
1276		sc->sc_if.if_oerrors++;
1277#endif
1278		return (NULL);
1279	}
1280
1281	switch (action) {
1282	case PFSYNC_ACT_CLR:
1283		len = sizeof(struct pfsync_header) +
1284		    sizeof(struct pfsync_state_clr);
1285		break;
1286	case PFSYNC_ACT_UPD_C:
1287		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1288		    sizeof(struct pfsync_header);
1289		break;
1290	case PFSYNC_ACT_DEL_C:
1291		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1292		    sizeof(struct pfsync_header);
1293		break;
1294	case PFSYNC_ACT_UREQ:
1295		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1296		    sizeof(struct pfsync_header);
1297		break;
1298	case PFSYNC_ACT_BUS:
1299		len = sizeof(struct pfsync_header) +
1300		    sizeof(struct pfsync_state_bus);
1301		break;
1302	default:
1303		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1304		    sizeof(struct pfsync_header);
1305		break;
1306	}
1307
1308	if (len > MHLEN) {
1309		MCLGET(m, M_DONTWAIT);
1310		if ((m->m_flags & M_EXT) == 0) {
1311			m_free(m);
1312#ifdef __FreeBSD__
1313			SCP2IFP(sc)->if_oerrors++;
1314#else
1315			sc->sc_if.if_oerrors++;
1316#endif
1317			return (NULL);
1318		}
1319		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1320	} else
1321		MH_ALIGN(m, len);
1322
1323	m->m_pkthdr.rcvif = NULL;
1324	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1325	h = mtod(m, struct pfsync_header *);
1326	h->version = PFSYNC_VERSION;
1327	h->af = 0;
1328	h->count = 0;
1329	h->action = action;
1330
1331	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
1332#ifdef __FreeBSD__
1333	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1334	    LIST_FIRST(&pfsync_list));
1335#else
1336	timeout_add(&sc->sc_tmo, hz);
1337#endif
1338	return (m);
1339}
1340
1341int
1342pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
1343{
1344#ifdef __FreeBSD__
1345	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1346#else
1347	struct ifnet *ifp = &pfsyncif.sc_if;
1348#endif
1349	struct pfsync_softc *sc = ifp->if_softc;
1350	struct pfsync_header *h, *h_net;
1351	struct pfsync_state *sp = NULL;
1352	struct pfsync_state_upd *up = NULL;
1353	struct pfsync_state_del *dp = NULL;
1354	struct pf_rule *r;
1355	u_long secs;
1356	int s, ret = 0;
1357	u_int8_t i = 255, newaction = 0;
1358
1359#ifdef __FreeBSD__
1360	PF_ASSERT(MA_OWNED);
1361#endif
1362	/*
1363	 * If a packet falls in the forest and there's nobody around to
1364	 * hear, does it make a sound?
1365	 */
1366	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
1367#ifdef __FreeBSD__
1368	    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1369#else
1370	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1371#endif
1372		/* Don't leave any stale pfsync packets hanging around. */
1373		if (sc->sc_mbuf != NULL) {
1374			m_freem(sc->sc_mbuf);
1375			sc->sc_mbuf = NULL;
1376			sc->sc_statep.s = NULL;
1377		}
1378		return (0);
1379	}
1380
1381	if (action >= PFSYNC_ACT_MAX)
1382		return (EINVAL);
1383
1384	s = splnet();
1385	if (sc->sc_mbuf == NULL) {
1386		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1387		    (void *)&sc->sc_statep.s)) == NULL) {
1388			splx(s);
1389			return (ENOMEM);
1390		}
1391		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1392	} else {
1393		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1394		if (h->action != action) {
1395			pfsync_sendout(sc);
1396			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1397			    (void *)&sc->sc_statep.s)) == NULL) {
1398				splx(s);
1399				return (ENOMEM);
1400			}
1401			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1402		} else {
1403			/*
1404			 * If it's an update, look in the packet to see if
1405			 * we already have an update for the state.
1406			 */
1407			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1408				struct pfsync_state *usp =
1409				    (void *)((char *)h + PFSYNC_HDRLEN);
1410
1411				for (i = 0; i < h->count; i++) {
1412					if (!memcmp(usp->id, &st->id,
1413					    PFSYNC_ID_LEN) &&
1414					    usp->creatorid == st->creatorid) {
1415						sp = usp;
1416						sp->updates++;
1417						break;
1418					}
1419					usp++;
1420				}
1421			}
1422		}
1423	}
1424
1425	secs = time_second;
1426
1427	st->pfsync_time = time_uptime;
1428	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1429	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1430
1431	if (sp == NULL) {
1432		/* not a "duplicate" update */
1433		i = 255;
1434		sp = sc->sc_statep.s++;
1435		sc->sc_mbuf->m_pkthdr.len =
1436		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1437		h->count++;
1438		bzero(sp, sizeof(*sp));
1439
1440		bcopy(&st->id, sp->id, sizeof(sp->id));
1441		sp->creatorid = st->creatorid;
1442
1443		strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1444		pf_state_host_hton(&st->lan, &sp->lan);
1445		pf_state_host_hton(&st->gwy, &sp->gwy);
1446		pf_state_host_hton(&st->ext, &sp->ext);
1447
1448		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1449
1450		sp->creation = htonl(secs - st->creation);
1451		sp->packets[0] = htonl(st->packets[0]);
1452		sp->packets[1] = htonl(st->packets[1]);
1453		sp->bytes[0] = htonl(st->bytes[0]);
1454		sp->bytes[1] = htonl(st->bytes[1]);
1455		if ((r = st->rule.ptr) == NULL)
1456			sp->rule = htonl(-1);
1457		else
1458			sp->rule = htonl(r->nr);
1459		if ((r = st->anchor.ptr) == NULL)
1460			sp->anchor = htonl(-1);
1461		else
1462			sp->anchor = htonl(r->nr);
1463		sp->af = st->af;
1464		sp->proto = st->proto;
1465		sp->direction = st->direction;
1466		sp->log = st->log;
1467		sp->allow_opts = st->allow_opts;
1468		sp->timeout = st->timeout;
1469
1470		if (flags & PFSYNC_FLAG_STALE)
1471			sp->sync_flags |= PFSTATE_STALE;
1472	}
1473
1474	pf_state_peer_hton(&st->src, &sp->src);
1475	pf_state_peer_hton(&st->dst, &sp->dst);
1476
1477	if (st->expire <= secs)
1478		sp->expire = htonl(0);
1479	else
1480		sp->expire = htonl(st->expire - secs);
1481
1482	/* do we need to build "compressed" actions for network transfer? */
1483	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
1484		switch (action) {
1485		case PFSYNC_ACT_UPD:
1486			newaction = PFSYNC_ACT_UPD_C;
1487			break;
1488		case PFSYNC_ACT_DEL:
1489			newaction = PFSYNC_ACT_DEL_C;
1490			break;
1491		default:
1492			/* by default we just send the uncompressed states */
1493			break;
1494		}
1495	}
1496
1497	if (newaction) {
1498		if (sc->sc_mbuf_net == NULL) {
1499			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1500			    (void *)&sc->sc_statep_net.s)) == NULL) {
1501				splx(s);
1502				return (ENOMEM);
1503			}
1504		}
1505		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1506
1507		switch (newaction) {
1508		case PFSYNC_ACT_UPD_C:
1509			if (i != 255) {
1510				up = (void *)((char *)h_net +
1511				    PFSYNC_HDRLEN + (i * sizeof(*up)));
1512				up->updates++;
1513			} else {
1514				h_net->count++;
1515				sc->sc_mbuf_net->m_pkthdr.len =
1516				    sc->sc_mbuf_net->m_len += sizeof(*up);
1517				up = sc->sc_statep_net.u++;
1518
1519				bzero(up, sizeof(*up));
1520				bcopy(&st->id, up->id, sizeof(up->id));
1521				up->creatorid = st->creatorid;
1522			}
1523			up->timeout = st->timeout;
1524			up->expire = sp->expire;
1525			up->src = sp->src;
1526			up->dst = sp->dst;
1527			break;
1528		case PFSYNC_ACT_DEL_C:
1529			sc->sc_mbuf_net->m_pkthdr.len =
1530			    sc->sc_mbuf_net->m_len += sizeof(*dp);
1531			dp = sc->sc_statep_net.d++;
1532			h_net->count++;
1533
1534			bzero(dp, sizeof(*dp));
1535			bcopy(&st->id, dp->id, sizeof(dp->id));
1536			dp->creatorid = st->creatorid;
1537			break;
1538		}
1539	}
1540
1541	if (h->count == sc->sc_maxcount ||
1542	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1543		ret = pfsync_sendout(sc);
1544
1545	splx(s);
1546	return (ret);
1547}
1548
1549/* This must be called in splnet() */
1550int
1551pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1552{
1553#ifdef __FreeBSD__
1554	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1555#else
1556	struct ifnet *ifp = &pfsyncif.sc_if;
1557#endif
1558	struct pfsync_header *h;
1559	struct pfsync_softc *sc = ifp->if_softc;
1560	struct pfsync_state_upd_req *rup;
1561	int ret = 0;
1562
1563#ifdef __FreeBSD__
1564	PF_ASSERT(MA_OWNED);
1565#endif
1566	if (sc->sc_mbuf == NULL) {
1567		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1568		    (void *)&sc->sc_statep.s)) == NULL)
1569			return (ENOMEM);
1570		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1571	} else {
1572		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1573		if (h->action != PFSYNC_ACT_UREQ) {
1574			pfsync_sendout(sc);
1575			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1576			    (void *)&sc->sc_statep.s)) == NULL)
1577				return (ENOMEM);
1578			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1579		}
1580	}
1581
1582	if (src != NULL)
1583		sc->sc_sendaddr = *src;
1584	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1585	h->count++;
1586	rup = sc->sc_statep.r++;
1587	bzero(rup, sizeof(*rup));
1588	if (up != NULL) {
1589		bcopy(up->id, rup->id, sizeof(rup->id));
1590		rup->creatorid = up->creatorid;
1591	}
1592
1593	if (h->count == sc->sc_maxcount)
1594		ret = pfsync_sendout(sc);
1595
1596	return (ret);
1597}
1598
1599int
1600pfsync_clear_states(u_int32_t creatorid, char *ifname)
1601{
1602#ifdef __FreeBSD__
1603	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1604#else
1605	struct ifnet *ifp = &pfsyncif.sc_if;
1606#endif
1607	struct pfsync_softc *sc = ifp->if_softc;
1608	struct pfsync_state_clr *cp;
1609	int s, ret;
1610
1611	s = splnet();
1612#ifdef __FreeBSD__
1613	PF_ASSERT(MA_OWNED);
1614#endif
1615	if (sc->sc_mbuf != NULL)
1616		pfsync_sendout(sc);
1617	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1618	    (void *)&sc->sc_statep.c)) == NULL) {
1619		splx(s);
1620		return (ENOMEM);
1621	}
1622	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1623	cp = sc->sc_statep.c;
1624	cp->creatorid = creatorid;
1625	if (ifname != NULL)
1626		strlcpy(cp->ifname, ifname, IFNAMSIZ);
1627
1628	ret = (pfsync_sendout(sc));
1629	splx(s);
1630	return (ret);
1631}
1632
1633void
1634pfsync_timeout(void *v)
1635{
1636	struct pfsync_softc *sc = v;
1637	int s;
1638
1639	s = splnet();
1640#ifdef __FreeBSD__
1641	PF_LOCK();
1642#endif
1643	pfsync_sendout(sc);
1644#ifdef __FreeBSD__
1645	PF_UNLOCK();
1646#endif
1647	splx(s);
1648}
1649
1650/* This must be called in splnet() */
1651void
1652pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1653{
1654	struct pfsync_state_bus *bus;
1655
1656#ifdef __FreeBSD__
1657	PF_ASSERT(MA_OWNED);
1658#endif
1659	if (sc->sc_mbuf != NULL)
1660		pfsync_sendout(sc);
1661
1662	if (pfsync_sync_ok &&
1663	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1664	    (void *)&sc->sc_statep.b)) != NULL) {
1665		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1666		bus = sc->sc_statep.b;
1667		bus->creatorid = pf_status.hostid;
1668		bus->status = status;
1669		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1670		pfsync_sendout(sc);
1671	}
1672}
1673
1674void
1675pfsync_bulk_update(void *v)
1676{
1677	struct pfsync_softc *sc = v;
1678	int s, i = 0;
1679	struct pf_state *state;
1680
1681#ifdef __FreeBSD__
1682	PF_LOCK();
1683#endif
1684	s = splnet();
1685	if (sc->sc_mbuf != NULL)
1686		pfsync_sendout(sc);
1687
1688	/*
1689	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1690	 * been sent since the latest request was made.
1691	 */
1692	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1693	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1694		if (state->pfsync_time > sc->sc_ureq_received) {
1695			/* we're done */
1696			pfsync_send_bus(sc, PFSYNC_BUS_END);
1697			sc->sc_ureq_received = 0;
1698#ifdef __FreeBSD__
1699			callout_stop(&sc->sc_bulk_tmo);
1700#else
1701			timeout_del(&sc->sc_bulk_tmo);
1702#endif
1703			if (pf_status.debug >= PF_DEBUG_MISC)
1704				printf("pfsync: bulk update complete\n");
1705			break;
1706		} else {
1707			/* send an update and move to end of list */
1708			if (!state->sync_flags)
1709				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1710			state->pfsync_time = time_uptime;
1711			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1712			TAILQ_INSERT_TAIL(&state_updates, state,
1713			    u.s.entry_updates);
1714
1715			/* look again for more in a bit */
1716#ifdef __FreeBSD__
1717			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1718			    LIST_FIRST(&pfsync_list));
1719#else
1720			timeout_add(&sc->sc_bulk_tmo, 1);
1721#endif
1722		}
1723	}
1724	if (sc->sc_mbuf != NULL)
1725		pfsync_sendout(sc);
1726	splx(s);
1727#ifdef __FreeBSD__
1728	PF_UNLOCK();
1729#endif
1730}
1731
1732void
1733pfsync_bulkfail(void *v)
1734{
1735	struct pfsync_softc *sc = v;
1736	int s, error;
1737
1738#ifdef __FreeBSD__
1739	PF_LOCK();
1740#endif
1741	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1742		/* Try again in a bit */
1743#ifdef __FreeBSD__
1744		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1745		    LIST_FIRST(&pfsync_list));
1746#else
1747		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1748#endif
1749		s = splnet();
1750		error = pfsync_request_update(NULL, NULL);
1751		if (error == ENOMEM) {
1752			if (pf_status.debug >= PF_DEBUG_MISC)
1753				printf("pfsync: cannot allocate mbufs for "
1754				    "bulk update\n");
1755		} else
1756			pfsync_sendout(sc);
1757		splx(s);
1758	} else {
1759		/* Pretend like the transfer was ok */
1760		sc->sc_ureq_sent = 0;
1761		sc->sc_bulk_tries = 0;
1762#if NCARP > 0
1763		if (!pfsync_sync_ok)
1764			carp_suppress_preempt--;
1765#endif
1766		pfsync_sync_ok = 1;
1767		if (pf_status.debug >= PF_DEBUG_MISC)
1768			printf("pfsync: failed to receive "
1769			    "bulk update status\n");
1770#ifdef __FreeBSD__
1771		callout_stop(&sc->sc_bulkfail_tmo);
1772#else
1773		timeout_del(&sc->sc_bulkfail_tmo);
1774#endif
1775	}
1776#ifdef __FreeBSD__
1777	PF_UNLOCK();
1778#endif
1779}
1780
1781/* This must be called in splnet() */
1782int
1783pfsync_sendout(sc)
1784	struct pfsync_softc *sc;
1785{
1786#if NBPFILTER > 0
1787# ifdef __FreeBSD__
1788	struct ifnet *ifp = SCP2IFP(sc);
1789# else
1790	struct ifnet *ifp = &sc->if_sc;
1791# endif
1792#endif
1793	struct mbuf *m;
1794
1795#ifdef __FreeBSD__
1796	PF_ASSERT(MA_OWNED);
1797	callout_stop(&sc->sc_tmo);
1798#else
1799	timeout_del(&sc->sc_tmo);
1800#endif
1801
1802	if (sc->sc_mbuf == NULL)
1803		return (0);
1804	m = sc->sc_mbuf;
1805	sc->sc_mbuf = NULL;
1806	sc->sc_statep.s = NULL;
1807
1808#ifdef __FreeBSD__
1809	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1810#endif
1811#if NBPFILTER > 0
1812#ifdef __FreeBSD__
1813	BPF_MTAP(ifp, m);
1814#else
1815	if (ifp->if_bpf)
1816		bpf_mtap(ifp->if_bpf, m);
1817#endif
1818#endif
1819
1820	if (sc->sc_mbuf_net) {
1821		m_freem(m);
1822		m = sc->sc_mbuf_net;
1823		sc->sc_mbuf_net = NULL;
1824		sc->sc_statep_net.s = NULL;
1825	}
1826
1827#ifdef __FreeBSD__
1828	if (sc->sc_sync_ifp ||
1829	    sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
1830#else
1831	if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1832#endif
1833		struct ip *ip;
1834		struct sockaddr sa;
1835
1836		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1837		if (m == NULL) {
1838			pfsyncstats.pfsyncs_onomem++;
1839			return (0);
1840		}
1841		ip = mtod(m, struct ip *);
1842		ip->ip_v = IPVERSION;
1843		ip->ip_hl = sizeof(*ip) >> 2;
1844		ip->ip_tos = IPTOS_LOWDELAY;
1845#ifdef __FreeBSD__
1846		ip->ip_len = m->m_pkthdr.len;
1847#else
1848		ip->ip_len = htons(m->m_pkthdr.len);
1849#endif
1850		ip->ip_id = htons(ip_randomid());
1851#ifdef __FreeBSD__
1852		ip->ip_off = IP_DF;
1853#else
1854		ip->ip_off = htons(IP_DF);
1855#endif
1856		ip->ip_ttl = PFSYNC_DFLTTL;
1857		ip->ip_p = IPPROTO_PFSYNC;
1858		ip->ip_sum = 0;
1859
1860		bzero(&sa, sizeof(sa));
1861		ip->ip_src.s_addr = INADDR_ANY;
1862
1863#ifdef __FreeBSD__
1864		if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1865#else
1866		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1867#endif
1868			m->m_flags |= M_MCAST;
1869		ip->ip_dst = sc->sc_sendaddr;
1870		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
1871
1872		pfsyncstats.pfsyncs_opackets++;
1873#ifdef __FreeBSD__
1874		if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
1875			pfsyncstats.pfsyncs_oerrors++;
1876		callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
1877#else
1878		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1879			pfsyncstats.pfsyncs_oerrors++;
1880#endif
1881	} else
1882		m_freem(m);
1883
1884	return (0);
1885}
1886
1887#ifdef __FreeBSD__
1888static void
1889pfsync_ifdetach(void *arg, struct ifnet *ifp)
1890{
1891	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
1892	struct ip_moptions *imo;
1893
1894	if (sc == NULL || sc->sc_sync_ifp != ifp)
1895		return;		/* not for us; unlocked read */
1896
1897	PF_LOCK();
1898
1899	/* Deal with a member interface going away from under us. */
1900	sc->sc_sync_ifp = NULL;
1901	if (sc->sc_mbuf_net != NULL) {
1902		m_freem(sc->sc_mbuf_net);
1903		sc->sc_mbuf_net = NULL;
1904		sc->sc_statep_net.s = NULL;
1905	}
1906	imo = &sc->sc_imo;
1907	if (imo->imo_num_memberships > 0) {
1908		in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1909		imo->imo_multicast_ifp = NULL;
1910	}
1911
1912	PF_UNLOCK();
1913}
1914
1915static void
1916pfsync_senddef(void *arg)
1917{
1918	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
1919	struct mbuf *m;
1920
1921	for(;;) {
1922		IF_DEQUEUE(&sc->sc_ifq, m);
1923		if (m == NULL)
1924			break;
1925		/* Deal with a member interface going away from under us. */
1926		if (sc->sc_sync_ifp == NULL) {
1927			pfsyncstats.pfsyncs_oerrors++;
1928			m_freem(m);
1929			continue;
1930		}
1931		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1932			pfsyncstats.pfsyncs_oerrors++;
1933	}
1934}
1935
1936static int
1937pfsync_modevent(module_t mod, int type, void *data)
1938{
1939	int error = 0;
1940
1941	switch (type) {
1942	case MOD_LOAD:
1943		LIST_INIT(&pfsync_list);
1944		if_clone_attach(&pfsync_cloner);
1945		break;
1946
1947	case MOD_UNLOAD:
1948		if_clone_detach(&pfsync_cloner);
1949		break;
1950
1951	default:
1952		error = EINVAL;
1953		break;
1954	}
1955
1956	return error;
1957}
1958
1959static moduledata_t pfsync_mod = {
1960	"pfsync",
1961	pfsync_modevent,
1962	0
1963};
1964
1965#define PFSYNC_MODVER 1
1966
1967DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1968MODULE_VERSION(pfsync, PFSYNC_MODVER);
1969#endif /* __FreeBSD__ */
1970