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