source: rtems-libbsd/contrib/pf/rtems/freebsd/net/if_pfsync.c @ 9a8e3e0

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 9a8e3e0 was 9a8e3e0, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/12 at 14:17:55

Revert move of contrib until more sorted out

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