xref: /netbsd/sys/dist/pf/net/if_pfsync.c (revision 4196a59b)
1*4196a59bSchristos /*	$NetBSD: if_pfsync.c,v 1.22 2021/03/10 22:18:17 christos Exp $	*/
22d48ac80Sdegroote /*	$OpenBSD: if_pfsync.c,v 1.83 2007/06/26 14:44:12 mcbride Exp $	*/
32d48ac80Sdegroote 
42d48ac80Sdegroote /*
52d48ac80Sdegroote  * Copyright (c) 2002 Michael Shalayeff
62d48ac80Sdegroote  * All rights reserved.
72d48ac80Sdegroote  *
82d48ac80Sdegroote  * Redistribution and use in source and binary forms, with or without
92d48ac80Sdegroote  * modification, are permitted provided that the following conditions
102d48ac80Sdegroote  * are met:
112d48ac80Sdegroote  * 1. Redistributions of source code must retain the above copyright
122d48ac80Sdegroote  *    notice, this list of conditions and the following disclaimer.
132d48ac80Sdegroote  * 2. Redistributions in binary form must reproduce the above copyright
142d48ac80Sdegroote  *    notice, this list of conditions and the following disclaimer in the
152d48ac80Sdegroote  *    documentation and/or other materials provided with the distribution.
162d48ac80Sdegroote  *
172d48ac80Sdegroote  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182d48ac80Sdegroote  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192d48ac80Sdegroote  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202d48ac80Sdegroote  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
212d48ac80Sdegroote  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
222d48ac80Sdegroote  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
232d48ac80Sdegroote  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242d48ac80Sdegroote  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
252d48ac80Sdegroote  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
262d48ac80Sdegroote  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
272d48ac80Sdegroote  * THE POSSIBILITY OF SUCH DAMAGE.
282d48ac80Sdegroote  */
292d48ac80Sdegroote 
302d48ac80Sdegroote #include <sys/cdefs.h>
31*4196a59bSchristos __KERNEL_RCSID(0, "$NetBSD: if_pfsync.c,v 1.22 2021/03/10 22:18:17 christos Exp $");
322d48ac80Sdegroote 
332d48ac80Sdegroote #ifdef _KERNEL_OPT
342d48ac80Sdegroote #include "opt_inet.h"
352d48ac80Sdegroote #include "opt_inet6.h"
362d48ac80Sdegroote #endif
372d48ac80Sdegroote 
382d48ac80Sdegroote #include <sys/param.h>
392d48ac80Sdegroote #include <sys/proc.h>
402d48ac80Sdegroote #include <sys/systm.h>
412d48ac80Sdegroote #include <sys/time.h>
422d48ac80Sdegroote #include <sys/mbuf.h>
432d48ac80Sdegroote #include <sys/socket.h>
442d48ac80Sdegroote #include <sys/ioctl.h>
452d48ac80Sdegroote #include <sys/callout.h>
462d48ac80Sdegroote #include <sys/kernel.h>
472d48ac80Sdegroote 
482d48ac80Sdegroote #include <net/if.h>
492d48ac80Sdegroote #include <net/if_types.h>
502d48ac80Sdegroote #include <net/route.h>
512d48ac80Sdegroote #include <net/bpf.h>
522d48ac80Sdegroote #include <netinet/in.h>
532d48ac80Sdegroote #ifndef __NetBSD__
542d48ac80Sdegroote #include <netinet/if_ether.h>
552d48ac80Sdegroote #else
562d48ac80Sdegroote #include <net/if_ether.h>
572d48ac80Sdegroote #endif /* __NetBSD__ */
582d48ac80Sdegroote #include <netinet/tcp.h>
592d48ac80Sdegroote #include <netinet/tcp_seq.h>
602d48ac80Sdegroote 
612d48ac80Sdegroote #ifdef	INET
622d48ac80Sdegroote #include <netinet/in_systm.h>
632d48ac80Sdegroote #include <netinet/in_var.h>
642d48ac80Sdegroote #include <netinet/ip.h>
652d48ac80Sdegroote #include <netinet/ip_var.h>
662d48ac80Sdegroote #endif
672d48ac80Sdegroote 
682d48ac80Sdegroote #ifdef INET6
692d48ac80Sdegroote #include <netinet6/nd6.h>
702d48ac80Sdegroote #endif /* INET6 */
712d48ac80Sdegroote 
722d48ac80Sdegroote #include "carp.h"
732d48ac80Sdegroote #if NCARP > 0
742d48ac80Sdegroote extern int carp_suppress_preempt;
752d48ac80Sdegroote #endif
762d48ac80Sdegroote 
772d48ac80Sdegroote #include <net/pfvar.h>
782d48ac80Sdegroote #include <net/if_pfsync.h>
792d48ac80Sdegroote 
802d48ac80Sdegroote #ifdef __NetBSD__
812d48ac80Sdegroote #include <sys/conf.h>
822d48ac80Sdegroote #include <sys/lwp.h>
832d48ac80Sdegroote #include <sys/kauth.h>
842d48ac80Sdegroote #include <sys/sysctl.h>
852d48ac80Sdegroote 
862d48ac80Sdegroote #include <net/net_stats.h>
872d48ac80Sdegroote 
884bf9ea45Schristos #include "ioconf.h"
894bf9ea45Schristos 
902d48ac80Sdegroote percpu_t	*pfsyncstat_percpu;
912d48ac80Sdegroote 
922d48ac80Sdegroote #define	PFSYNC_STATINC(x) _NET_STATINC(pfsyncstat_percpu, x)
932d48ac80Sdegroote #endif /* __NetBSD__ */
942d48ac80Sdegroote 
952d48ac80Sdegroote #include "pfsync.h"
962d48ac80Sdegroote 
972d48ac80Sdegroote #define PFSYNC_MINMTU	\
982d48ac80Sdegroote     (sizeof(struct pfsync_header) + sizeof(struct pf_state))
992d48ac80Sdegroote 
1002d48ac80Sdegroote #ifdef PFSYNCDEBUG
1012d48ac80Sdegroote #define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
1022d48ac80Sdegroote int pfsyncdebug;
1032d48ac80Sdegroote #else
1042d48ac80Sdegroote #define DPRINTF(x)
1052d48ac80Sdegroote #endif
1062d48ac80Sdegroote 
1072d48ac80Sdegroote extern int ifqmaxlen; /* XXX */
1082d48ac80Sdegroote 
1092d48ac80Sdegroote struct pfsync_softc	*pfsyncif = NULL;
1102d48ac80Sdegroote 
1112d48ac80Sdegroote int	pfsync_clone_create(struct if_clone *, int);
1122d48ac80Sdegroote int	pfsync_clone_destroy(struct ifnet *);
1132d48ac80Sdegroote void	pfsync_setmtu(struct pfsync_softc *, int);
1142d48ac80Sdegroote int	pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
1152d48ac80Sdegroote 	    struct pf_state_peer *);
1162d48ac80Sdegroote int	pfsync_insert_net_state(struct pfsync_state *, u_int8_t);
1172d48ac80Sdegroote void	pfsync_update_net_tdb(struct pfsync_tdb *);
1182d48ac80Sdegroote int	pfsyncoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
1199b969dc0Sozaki-r 	    const struct rtentry *);
1202d48ac80Sdegroote int	pfsyncioctl(struct ifnet *, u_long, void*);
1212d48ac80Sdegroote void	pfsyncstart(struct ifnet *);
1222d48ac80Sdegroote 
1232d48ac80Sdegroote struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
1242d48ac80Sdegroote int	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
1252d48ac80Sdegroote int	pfsync_sendout(struct pfsync_softc *);
1262d48ac80Sdegroote int	pfsync_tdb_sendout(struct pfsync_softc *);
1272d48ac80Sdegroote int	pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
1282d48ac80Sdegroote void	pfsync_timeout(void *);
1292d48ac80Sdegroote void	pfsync_tdb_timeout(void *);
1302d48ac80Sdegroote void	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
1312d48ac80Sdegroote void	pfsync_bulk_update(void *);
1322d48ac80Sdegroote void	pfsync_bulkfail(void *);
1332d48ac80Sdegroote 
1342d48ac80Sdegroote int	pfsync_sync_ok;
1352d48ac80Sdegroote 
1362d48ac80Sdegroote struct if_clone	pfsync_cloner =
1372d48ac80Sdegroote     IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
1382d48ac80Sdegroote 
1392d48ac80Sdegroote void
pfsyncattach(int npfsync)1402d48ac80Sdegroote pfsyncattach(int npfsync)
1412d48ac80Sdegroote {
1422d48ac80Sdegroote 	if_clone_attach(&pfsync_cloner);
1432d48ac80Sdegroote 
1442d48ac80Sdegroote 	pfsyncstat_percpu = percpu_alloc(sizeof(uint64_t) * PFSYNC_NSTATS);
1452d48ac80Sdegroote }
1462d48ac80Sdegroote 
1472d48ac80Sdegroote int
pfsync_clone_create(struct if_clone * ifc,int unit)1482d48ac80Sdegroote pfsync_clone_create(struct if_clone *ifc, int unit)
1492d48ac80Sdegroote {
1502d48ac80Sdegroote 	struct ifnet *ifp;
1512d48ac80Sdegroote 
1522d48ac80Sdegroote 	if (unit != 0)
1532d48ac80Sdegroote 		return (EINVAL);
1542d48ac80Sdegroote 
1552d48ac80Sdegroote 	pfsync_sync_ok = 1;
1562d48ac80Sdegroote 	if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL)
1572d48ac80Sdegroote 		return (ENOMEM);
1582d48ac80Sdegroote 	memset(pfsyncif, 0, sizeof(*pfsyncif));
1592d48ac80Sdegroote 	pfsyncif->sc_mbuf = NULL;
1602d48ac80Sdegroote 	pfsyncif->sc_mbuf_net = NULL;
1612d48ac80Sdegroote 	pfsyncif->sc_mbuf_tdb = NULL;
1622d48ac80Sdegroote 	pfsyncif->sc_statep.s = NULL;
1632d48ac80Sdegroote 	pfsyncif->sc_statep_net.s = NULL;
1642d48ac80Sdegroote 	pfsyncif->sc_statep_tdb.t = NULL;
1652d48ac80Sdegroote 	pfsyncif->sc_maxupdates = 128;
1662d48ac80Sdegroote 	pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1672d48ac80Sdegroote 	pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
1682d48ac80Sdegroote 	pfsyncif->sc_ureq_received = 0;
1692d48ac80Sdegroote 	pfsyncif->sc_ureq_sent = 0;
1702d48ac80Sdegroote 	pfsyncif->sc_bulk_send_next = NULL;
1712d48ac80Sdegroote 	pfsyncif->sc_bulk_terminator = NULL;
1722d48ac80Sdegroote 	ifp = &pfsyncif->sc_if;
1732d48ac80Sdegroote 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
1742d48ac80Sdegroote 	ifp->if_softc = pfsyncif;
1752d48ac80Sdegroote 	ifp->if_ioctl = pfsyncioctl;
1762d48ac80Sdegroote 	ifp->if_output = pfsyncoutput;
1772d48ac80Sdegroote 	ifp->if_start = pfsyncstart;
1782d48ac80Sdegroote 	ifp->if_type = IFT_PFSYNC;
1792d48ac80Sdegroote 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
1802d48ac80Sdegroote 	ifp->if_hdrlen = PFSYNC_HDRLEN;
1812d48ac80Sdegroote 	pfsync_setmtu(pfsyncif, ETHERMTU);
1822d48ac80Sdegroote 
1832d48ac80Sdegroote 	callout_init(&pfsyncif->sc_tmo, 0);
1842d48ac80Sdegroote 	callout_init(&pfsyncif->sc_tdb_tmo, 0);
1852d48ac80Sdegroote 	callout_init(&pfsyncif->sc_bulk_tmo, 0);
1862d48ac80Sdegroote 	callout_init(&pfsyncif->sc_bulkfail_tmo, 0);
1872d48ac80Sdegroote 	callout_setfunc(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif);
1882d48ac80Sdegroote 	callout_setfunc(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif);
1892d48ac80Sdegroote 	callout_setfunc(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif);
1902d48ac80Sdegroote 	callout_setfunc(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif);
1912d48ac80Sdegroote 
1922d48ac80Sdegroote 	if_attach(ifp);
1932d48ac80Sdegroote 	if_alloc_sadl(ifp);
1942d48ac80Sdegroote 
19558e86755Sjoerg 	bpf_attach(&pfsyncif->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
1962d48ac80Sdegroote 
1972d48ac80Sdegroote 	return (0);
1982d48ac80Sdegroote }
1992d48ac80Sdegroote 
2002d48ac80Sdegroote int
pfsync_clone_destroy(struct ifnet * ifp)2012d48ac80Sdegroote pfsync_clone_destroy(struct ifnet *ifp)
2022d48ac80Sdegroote {
20358e86755Sjoerg 	bpf_detach(ifp);
2042d48ac80Sdegroote 	if_detach(ifp);
2052d48ac80Sdegroote 	free(pfsyncif, M_DEVBUF);
2062d48ac80Sdegroote 	pfsyncif = NULL;
2072d48ac80Sdegroote 	return (0);
2082d48ac80Sdegroote }
2092d48ac80Sdegroote 
2102d48ac80Sdegroote /*
2112d48ac80Sdegroote  * Start output on the pfsync interface.
2122d48ac80Sdegroote  */
2132d48ac80Sdegroote void
pfsyncstart(struct ifnet * ifp)2142d48ac80Sdegroote pfsyncstart(struct ifnet *ifp)
2152d48ac80Sdegroote {
2162d48ac80Sdegroote 	struct mbuf *m;
2172d48ac80Sdegroote 	int s;
2182d48ac80Sdegroote 
2192d48ac80Sdegroote 	for (;;) {
2202d48ac80Sdegroote 		s = splnet();
2212d48ac80Sdegroote 		IF_DROP(&ifp->if_snd);
2222d48ac80Sdegroote 		IF_DEQUEUE(&ifp->if_snd, m);
2232d48ac80Sdegroote 		splx(s);
2242d48ac80Sdegroote 
2252d48ac80Sdegroote 		if (m == NULL)
2262d48ac80Sdegroote 			return;
2272d48ac80Sdegroote 		else
2282d48ac80Sdegroote 			m_freem(m);
2292d48ac80Sdegroote 	}
2302d48ac80Sdegroote }
2312d48ac80Sdegroote 
2322d48ac80Sdegroote int
pfsync_alloc_scrub_memory(struct pfsync_state_peer * s,struct pf_state_peer * d)2332d48ac80Sdegroote pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
2342d48ac80Sdegroote     struct pf_state_peer *d)
2352d48ac80Sdegroote {
2362d48ac80Sdegroote 	if (s->scrub.scrub_flag && d->scrub == NULL) {
2372d48ac80Sdegroote 		d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
2382d48ac80Sdegroote 		if (d->scrub == NULL)
2392d48ac80Sdegroote 			return (ENOMEM);
2402d48ac80Sdegroote 		memset(d->scrub, 0, sizeof(*d->scrub));
2412d48ac80Sdegroote 	}
2422d48ac80Sdegroote 
2432d48ac80Sdegroote 	return (0);
2442d48ac80Sdegroote }
2452d48ac80Sdegroote 
2462d48ac80Sdegroote int
pfsync_insert_net_state(struct pfsync_state * sp,u_int8_t chksum_flag)2472d48ac80Sdegroote pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
2482d48ac80Sdegroote {
2492d48ac80Sdegroote 	struct pf_state	*st = NULL;
2502d48ac80Sdegroote 	struct pf_state_key *sk = NULL;
2512d48ac80Sdegroote 	struct pf_rule *r = NULL;
2522d48ac80Sdegroote 	struct pfi_kif	*kif;
2532d48ac80Sdegroote 
2542d48ac80Sdegroote 	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
2552d48ac80Sdegroote 		printf("pfsync_insert_net_state: invalid creator id:"
2562d48ac80Sdegroote 		    " %08x\n", ntohl(sp->creatorid));
2572d48ac80Sdegroote 		return (EINVAL);
2582d48ac80Sdegroote 	}
2592d48ac80Sdegroote 
2602d48ac80Sdegroote 	kif = pfi_kif_get(sp->ifname);
2612d48ac80Sdegroote 	if (kif == NULL) {
2622d48ac80Sdegroote 		if (pf_status.debug >= PF_DEBUG_MISC)
2632d48ac80Sdegroote 			printf("pfsync_insert_net_state: "
2642d48ac80Sdegroote 			    "unknown interface: %s\n", sp->ifname);
2652d48ac80Sdegroote 		/* skip this state */
2662d48ac80Sdegroote 		return (0);
2672d48ac80Sdegroote 	}
2682d48ac80Sdegroote 
2692d48ac80Sdegroote 	/*
2702d48ac80Sdegroote 	 * If the ruleset checksums match, it's safe to associate the state
2712d48ac80Sdegroote 	 * with the rule of that number.
2722d48ac80Sdegroote 	 */
2732d48ac80Sdegroote 	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag &&
2742d48ac80Sdegroote 	    ntohl(sp->rule) <
2752d48ac80Sdegroote 	    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
2762d48ac80Sdegroote 		r = pf_main_ruleset.rules[
2772d48ac80Sdegroote 		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
2782d48ac80Sdegroote 	else
2792d48ac80Sdegroote 		r = &pf_default_rule;
2802d48ac80Sdegroote 
2812d48ac80Sdegroote 	if (!r->max_states || r->states < r->max_states)
2822d48ac80Sdegroote 		st = pool_get(&pf_state_pl, PR_NOWAIT);
2832d48ac80Sdegroote 	if (st == NULL) {
2842d48ac80Sdegroote 		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
2852d48ac80Sdegroote 		return (ENOMEM);
2862d48ac80Sdegroote 	}
2872d48ac80Sdegroote 	memset(st, 0, sizeof(*st));
2882d48ac80Sdegroote 
2892d48ac80Sdegroote 	if ((sk = pf_alloc_state_key(st)) == NULL) {
2902d48ac80Sdegroote 		pool_put(&pf_state_pl, st);
2912d48ac80Sdegroote 		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
2922d48ac80Sdegroote 		return (ENOMEM);
2932d48ac80Sdegroote 	}
2942d48ac80Sdegroote 
2952d48ac80Sdegroote 	/* allocate memory for scrub info */
2962d48ac80Sdegroote 	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
2972d48ac80Sdegroote 	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
2982d48ac80Sdegroote 		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
2992d48ac80Sdegroote 		if (st->src.scrub)
3002d48ac80Sdegroote 			pool_put(&pf_state_scrub_pl, st->src.scrub);
3012d48ac80Sdegroote 		pool_put(&pf_state_pl, st);
3022d48ac80Sdegroote 		pool_put(&pf_state_key_pl, sk);
3032d48ac80Sdegroote 		return (ENOMEM);
3042d48ac80Sdegroote 	}
3052d48ac80Sdegroote 
3062d48ac80Sdegroote 	st->rule.ptr = r;
3072d48ac80Sdegroote 	/* XXX get pointers to nat_rule and anchor */
3082d48ac80Sdegroote 
3092d48ac80Sdegroote 	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
3102d48ac80Sdegroote 	r->states++;
3112d48ac80Sdegroote 
3122d48ac80Sdegroote 	/* fill in the rest of the state entry */
3132d48ac80Sdegroote 	pf_state_host_ntoh(&sp->lan, &sk->lan);
3142d48ac80Sdegroote 	pf_state_host_ntoh(&sp->gwy, &sk->gwy);
3152d48ac80Sdegroote 	pf_state_host_ntoh(&sp->ext, &sk->ext);
3162d48ac80Sdegroote 
3172d48ac80Sdegroote 	pf_state_peer_ntoh(&sp->src, &st->src);
3182d48ac80Sdegroote 	pf_state_peer_ntoh(&sp->dst, &st->dst);
3192d48ac80Sdegroote 
3202d48ac80Sdegroote 	memcpy(&st->rt_addr, &sp->rt_addr, sizeof(st->rt_addr));
3212d48ac80Sdegroote 	st->creation = time_second - ntohl(sp->creation);
3222d48ac80Sdegroote 	st->expire = ntohl(sp->expire) + time_second;
3232d48ac80Sdegroote 
3242d48ac80Sdegroote 	sk->af = sp->af;
3252d48ac80Sdegroote 	sk->proto = sp->proto;
3262d48ac80Sdegroote 	sk->direction = sp->direction;
3272d48ac80Sdegroote 	st->log = sp->log;
3282d48ac80Sdegroote 	st->timeout = sp->timeout;
3292d48ac80Sdegroote 	st->allow_opts = sp->allow_opts;
3302d48ac80Sdegroote 
3312d48ac80Sdegroote 	memcpy(&st->id, sp->id, sizeof(st->id));
3322d48ac80Sdegroote 	st->creatorid = sp->creatorid;
3332d48ac80Sdegroote 	st->sync_flags = PFSTATE_FROMSYNC;
3342d48ac80Sdegroote 
3352d48ac80Sdegroote 	if (pf_insert_state(kif, st)) {
3362d48ac80Sdegroote 		pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3372d48ac80Sdegroote 		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
3382d48ac80Sdegroote 		r->states--;
3392d48ac80Sdegroote 		if (st->dst.scrub)
3402d48ac80Sdegroote 			pool_put(&pf_state_scrub_pl, st->dst.scrub);
3412d48ac80Sdegroote 		if (st->src.scrub)
3422d48ac80Sdegroote 			pool_put(&pf_state_scrub_pl, st->src.scrub);
3432d48ac80Sdegroote 		pool_put(&pf_state_pl, st);
3442d48ac80Sdegroote 		return (EINVAL);
3452d48ac80Sdegroote 	}
3462d48ac80Sdegroote 
3472d48ac80Sdegroote 	return (0);
3482d48ac80Sdegroote }
3492d48ac80Sdegroote 
3502d48ac80Sdegroote void
pfsync_input(struct mbuf * m,int off,int proto)35106fb17b7Smaxv pfsync_input(struct mbuf *m, int off, int proto)
3522d48ac80Sdegroote {
3532d48ac80Sdegroote 	struct ip *ip = mtod(m, struct ip *);
3542d48ac80Sdegroote 	struct pfsync_header *ph;
3552d48ac80Sdegroote 	struct pfsync_softc *sc = pfsyncif;
3562d48ac80Sdegroote 	struct pf_state *st;
3572d48ac80Sdegroote 	struct pf_state_key *sk;
3582d48ac80Sdegroote 	struct pf_state_cmp id_key;
3592d48ac80Sdegroote 	struct pfsync_state *sp;
3602d48ac80Sdegroote 	struct pfsync_state_upd *up;
3612d48ac80Sdegroote 	struct pfsync_state_del *dp;
3622d48ac80Sdegroote 	struct pfsync_state_clr *cp;
3632d48ac80Sdegroote 	struct pfsync_state_upd_req *rup;
3642d48ac80Sdegroote 	struct pfsync_state_bus *bus;
3652d48ac80Sdegroote 	struct in_addr src;
3662d48ac80Sdegroote 	struct mbuf *mp;
3672d48ac80Sdegroote 	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
3682d48ac80Sdegroote 	u_int8_t chksum_flag = 0;
3692d48ac80Sdegroote 
3702d48ac80Sdegroote 	PFSYNC_STATINC(PFSYNC_STAT_IPACKETS);
3712d48ac80Sdegroote 
3722d48ac80Sdegroote 	/* verify that we have a sync interface configured */
3732d48ac80Sdegroote 	if (!sc || !sc->sc_sync_ifp || !pf_status.running)
3742d48ac80Sdegroote 		goto done;
3752d48ac80Sdegroote 
3762d48ac80Sdegroote 	/* verify that the packet came in on the right interface */
3779d07c695Sozaki-r 	if (sc->sc_sync_ifp->if_index != m->m_pkthdr.rcvif_index) {
3782d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_BADIF);
3792d48ac80Sdegroote 		goto done;
3802d48ac80Sdegroote 	}
3812d48ac80Sdegroote 
3822d48ac80Sdegroote 	/* verify that the IP TTL is 255.  */
3832d48ac80Sdegroote 	if (ip->ip_ttl != PFSYNC_DFLTTL) {
3842d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_BADTTL);
3852d48ac80Sdegroote 		goto done;
3862d48ac80Sdegroote 	}
3872d48ac80Sdegroote 
3882d48ac80Sdegroote 	iplen = ip->ip_hl << 2;
3892d48ac80Sdegroote 
3902d48ac80Sdegroote 	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
3912d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_HDROPS);
3922d48ac80Sdegroote 		goto done;
3932d48ac80Sdegroote 	}
3942d48ac80Sdegroote 
3952d48ac80Sdegroote 	if (iplen + sizeof(*ph) > m->m_len) {
3962d48ac80Sdegroote 		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
3972d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_HDROPS);
3982d48ac80Sdegroote 			goto done;
3992d48ac80Sdegroote 		}
4002d48ac80Sdegroote 		ip = mtod(m, struct ip *);
4012d48ac80Sdegroote 	}
4022d48ac80Sdegroote 	ph = (struct pfsync_header *)((char *)ip + iplen);
4032d48ac80Sdegroote 
4042d48ac80Sdegroote 	/* verify the version */
4052d48ac80Sdegroote 	if (ph->version != PFSYNC_VERSION) {
4062d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_BADVER);
4072d48ac80Sdegroote 		goto done;
4082d48ac80Sdegroote 	}
4092d48ac80Sdegroote 
4102d48ac80Sdegroote 	action = ph->action;
4112d48ac80Sdegroote 	count = ph->count;
4122d48ac80Sdegroote 
4132d48ac80Sdegroote 	/* make sure it's a valid action code */
4142d48ac80Sdegroote 	if (action >= PFSYNC_ACT_MAX) {
4152d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_BADACT);
4162d48ac80Sdegroote 		goto done;
4172d48ac80Sdegroote 	}
4182d48ac80Sdegroote 
4192d48ac80Sdegroote 	/* Cheaper to grab this now than having to mess with mbufs later */
4202d48ac80Sdegroote 	src = ip->ip_src;
4212d48ac80Sdegroote 
4222d48ac80Sdegroote 	if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
4232d48ac80Sdegroote 		chksum_flag++;
4242d48ac80Sdegroote 
4252d48ac80Sdegroote 	switch (action) {
4262d48ac80Sdegroote 	case PFSYNC_ACT_CLR: {
4272d48ac80Sdegroote 		struct pf_state *nexts;
4282d48ac80Sdegroote 		struct pf_state_key *nextsk;
4292d48ac80Sdegroote 		struct pfi_kif *kif;
4302d48ac80Sdegroote 		u_int32_t creatorid;
4312d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
4322d48ac80Sdegroote 		    sizeof(*cp), &offp)) == NULL) {
4332d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
4342d48ac80Sdegroote 			return;
4352d48ac80Sdegroote 		}
4362d48ac80Sdegroote 		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
4372d48ac80Sdegroote 		creatorid = cp->creatorid;
4382d48ac80Sdegroote 
4392d48ac80Sdegroote 		s = splsoftnet();
4402d48ac80Sdegroote 		if (cp->ifname[0] == '\0') {
4412d48ac80Sdegroote 			for (st = RB_MIN(pf_state_tree_id, &tree_id);
4422d48ac80Sdegroote 			    st; st = nexts) {
4432d48ac80Sdegroote 				nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
4442d48ac80Sdegroote 				if (st->creatorid == creatorid) {
4452d48ac80Sdegroote 					st->sync_flags |= PFSTATE_FROMSYNC;
4462d48ac80Sdegroote 					pf_unlink_state(st);
4472d48ac80Sdegroote 				}
4482d48ac80Sdegroote 			}
4492d48ac80Sdegroote 		} else {
4502d48ac80Sdegroote 			if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
4512d48ac80Sdegroote 				splx(s);
4522d48ac80Sdegroote 				return;
4532d48ac80Sdegroote 			}
4542d48ac80Sdegroote 			for (sk = RB_MIN(pf_state_tree_lan_ext,
4552d48ac80Sdegroote 			    &pf_statetbl_lan_ext); sk; sk = nextsk) {
4562d48ac80Sdegroote 				nextsk = RB_NEXT(pf_state_tree_lan_ext,
4572d48ac80Sdegroote 				    &pf_statetbl_lan_ext, sk);
4582d48ac80Sdegroote 				TAILQ_FOREACH(st, &sk->states, next) {
4592d48ac80Sdegroote 					if (st->creatorid == creatorid) {
4602d48ac80Sdegroote 						st->sync_flags |=
4612d48ac80Sdegroote 						    PFSTATE_FROMSYNC;
4622d48ac80Sdegroote 						pf_unlink_state(st);
4632d48ac80Sdegroote 					}
4642d48ac80Sdegroote 				}
4652d48ac80Sdegroote 			}
4662d48ac80Sdegroote 		}
4672d48ac80Sdegroote 		splx(s);
4682d48ac80Sdegroote 
4692d48ac80Sdegroote 		break;
4702d48ac80Sdegroote 	}
4712d48ac80Sdegroote 	case PFSYNC_ACT_INS:
4722d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
4732d48ac80Sdegroote 		    count * sizeof(*sp), &offp)) == NULL) {
4742d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
4752d48ac80Sdegroote 			return;
4762d48ac80Sdegroote 		}
4772d48ac80Sdegroote 
4782d48ac80Sdegroote 		s = splsoftnet();
4792d48ac80Sdegroote 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
4802d48ac80Sdegroote 		    i < count; i++, sp++) {
4812d48ac80Sdegroote 			/* check for invalid values */
4822d48ac80Sdegroote 			if (sp->timeout >= PFTM_MAX ||
4832d48ac80Sdegroote 			    sp->src.state > PF_TCPS_PROXY_DST ||
4842d48ac80Sdegroote 			    sp->dst.state > PF_TCPS_PROXY_DST ||
4852d48ac80Sdegroote 			    sp->direction > PF_OUT ||
4862d48ac80Sdegroote 			    (sp->af != AF_INET && sp->af != AF_INET6)) {
4872d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
4882d48ac80Sdegroote 					printf("pfsync_insert: PFSYNC_ACT_INS: "
4892d48ac80Sdegroote 					    "invalid value\n");
4902d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
4912d48ac80Sdegroote 				continue;
4922d48ac80Sdegroote 			}
4932d48ac80Sdegroote 
4942d48ac80Sdegroote 			if ((error = pfsync_insert_net_state(sp,
4952d48ac80Sdegroote 			    chksum_flag))) {
4962d48ac80Sdegroote 				if (error == ENOMEM) {
4972d48ac80Sdegroote 					splx(s);
4982d48ac80Sdegroote 					goto done;
4992d48ac80Sdegroote 				}
5002d48ac80Sdegroote 				continue;
5012d48ac80Sdegroote 			}
5022d48ac80Sdegroote 		}
5032d48ac80Sdegroote 		splx(s);
5042d48ac80Sdegroote 		break;
5052d48ac80Sdegroote 	case PFSYNC_ACT_UPD:
5062d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
5072d48ac80Sdegroote 		    count * sizeof(*sp), &offp)) == NULL) {
5082d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
5092d48ac80Sdegroote 			return;
5102d48ac80Sdegroote 		}
5112d48ac80Sdegroote 
5122d48ac80Sdegroote 		s = splsoftnet();
5132d48ac80Sdegroote 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
5142d48ac80Sdegroote 		    i < count; i++, sp++) {
5152d48ac80Sdegroote 			int flags = PFSYNC_FLAG_STALE;
5162d48ac80Sdegroote 
5172d48ac80Sdegroote 			/* check for invalid values */
5182d48ac80Sdegroote 			if (sp->timeout >= PFTM_MAX ||
5192d48ac80Sdegroote 			    sp->src.state > PF_TCPS_PROXY_DST ||
5202d48ac80Sdegroote 			    sp->dst.state > PF_TCPS_PROXY_DST) {
5212d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
5222d48ac80Sdegroote 					printf("pfsync_insert: PFSYNC_ACT_UPD: "
5232d48ac80Sdegroote 					    "invalid value\n");
5242d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
5252d48ac80Sdegroote 				continue;
5262d48ac80Sdegroote 			}
5272d48ac80Sdegroote 
5282d48ac80Sdegroote 			memcpy(&id_key.id, sp->id, sizeof(id_key.id));
5292d48ac80Sdegroote 			id_key.creatorid = sp->creatorid;
5302d48ac80Sdegroote 
5312d48ac80Sdegroote 			st = pf_find_state_byid(&id_key);
5322d48ac80Sdegroote 			if (st == NULL) {
5332d48ac80Sdegroote 				/* insert the update */
5342d48ac80Sdegroote 				if (pfsync_insert_net_state(sp, chksum_flag)) {
5352d48ac80Sdegroote 					PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
5362d48ac80Sdegroote 				}
5372d48ac80Sdegroote 				continue;
5382d48ac80Sdegroote 			}
5392d48ac80Sdegroote 			sk = st->state_key;
5402d48ac80Sdegroote 			sfail = 0;
5412d48ac80Sdegroote 			if (sk->proto == IPPROTO_TCP) {
5422d48ac80Sdegroote 				/*
5432d48ac80Sdegroote 				 * The state should never go backwards except
5442d48ac80Sdegroote 				 * for syn-proxy states.  Neither should the
5452d48ac80Sdegroote 				 * sequence window slide backwards.
5462d48ac80Sdegroote 				 */
5472d48ac80Sdegroote 				if (st->src.state > sp->src.state &&
5482d48ac80Sdegroote 				    (st->src.state < PF_TCPS_PROXY_SRC ||
5492d48ac80Sdegroote 				    sp->src.state >= PF_TCPS_PROXY_SRC))
5502d48ac80Sdegroote 					sfail = 1;
5512d48ac80Sdegroote 				else if (SEQ_GT(st->src.seqlo,
5522d48ac80Sdegroote 				    ntohl(sp->src.seqlo)))
5532d48ac80Sdegroote 					sfail = 3;
5542d48ac80Sdegroote 				else if (st->dst.state > sp->dst.state) {
5552d48ac80Sdegroote 					/* There might still be useful
5562d48ac80Sdegroote 					 * information about the src state here,
5572d48ac80Sdegroote 					 * so import that part of the update,
5582d48ac80Sdegroote 					 * then "fail" so we send the updated
5592d48ac80Sdegroote 					 * state back to the peer who is missing
5602d48ac80Sdegroote 					 * our what we know. */
5612d48ac80Sdegroote 					pf_state_peer_ntoh(&sp->src, &st->src);
5622d48ac80Sdegroote 					/* XXX do anything with timeouts? */
5632d48ac80Sdegroote 					sfail = 7;
5642d48ac80Sdegroote 					flags = 0;
5652d48ac80Sdegroote 				} else if (st->dst.state >= TCPS_SYN_SENT &&
5662d48ac80Sdegroote 				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
5672d48ac80Sdegroote 					sfail = 4;
5682d48ac80Sdegroote 			} else {
5692d48ac80Sdegroote 				/*
5702d48ac80Sdegroote 				 * Non-TCP protocol state machine always go
5712d48ac80Sdegroote 				 * forwards
5722d48ac80Sdegroote 				 */
5732d48ac80Sdegroote 				if (st->src.state > sp->src.state)
5742d48ac80Sdegroote 					sfail = 5;
5752d48ac80Sdegroote 				else if (st->dst.state > sp->dst.state)
5762d48ac80Sdegroote 					sfail = 6;
5772d48ac80Sdegroote 			}
5782d48ac80Sdegroote 			if (sfail) {
5792d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
5802d48ac80Sdegroote 					printf("pfsync: %s stale update "
5812d48ac80Sdegroote 					    "(%d) id: %016" PRIu64 ""
5822d48ac80Sdegroote 					    "creatorid: %08x\n",
5832d48ac80Sdegroote 					    (sfail < 7 ?  "ignoring"
5842d48ac80Sdegroote 					     : "partial"), sfail,
5852d48ac80Sdegroote 					    be64toh(st->id),
5862d48ac80Sdegroote 					    ntohl(st->creatorid));
5872d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
5882d48ac80Sdegroote 
5892d48ac80Sdegroote 				if (!(sp->sync_flags & PFSTATE_STALE)) {
5902d48ac80Sdegroote 					/* we have a better state, send it */
5912d48ac80Sdegroote 					if (sc->sc_mbuf != NULL && !stale)
5922d48ac80Sdegroote 						pfsync_sendout(sc);
5932d48ac80Sdegroote 					stale++;
5942d48ac80Sdegroote 					if (!st->sync_flags)
5952d48ac80Sdegroote 						pfsync_pack_state(
5962d48ac80Sdegroote 						    PFSYNC_ACT_UPD, st, flags);
5972d48ac80Sdegroote 				}
5982d48ac80Sdegroote 				continue;
5992d48ac80Sdegroote 			}
6002d48ac80Sdegroote 	    		pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
6012d48ac80Sdegroote 			pf_state_peer_ntoh(&sp->src, &st->src);
6022d48ac80Sdegroote 			pf_state_peer_ntoh(&sp->dst, &st->dst);
6032d48ac80Sdegroote 			st->expire = ntohl(sp->expire) + time_second;
6042d48ac80Sdegroote 			st->timeout = sp->timeout;
6052d48ac80Sdegroote 		}
6062d48ac80Sdegroote 		if (stale && sc->sc_mbuf != NULL)
6072d48ac80Sdegroote 			pfsync_sendout(sc);
6082d48ac80Sdegroote 		splx(s);
6092d48ac80Sdegroote 		break;
6102d48ac80Sdegroote 	/*
6112d48ac80Sdegroote 	 * It's not strictly necessary for us to support the "uncompressed"
6122d48ac80Sdegroote 	 * delete action, but it's relatively simple and maintains consistency.
6132d48ac80Sdegroote 	 */
6142d48ac80Sdegroote 	case PFSYNC_ACT_DEL:
6152d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
6162d48ac80Sdegroote 		    count * sizeof(*sp), &offp)) == NULL) {
6172d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
6182d48ac80Sdegroote 			return;
6192d48ac80Sdegroote 		}
6202d48ac80Sdegroote 
6212d48ac80Sdegroote 		s = splsoftnet();
6222d48ac80Sdegroote 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
6232d48ac80Sdegroote 		    i < count; i++, sp++) {
6242d48ac80Sdegroote 			memcpy(&id_key.id, sp->id, sizeof(id_key.id));
6252d48ac80Sdegroote 			id_key.creatorid = sp->creatorid;
6262d48ac80Sdegroote 
6272d48ac80Sdegroote 			st = pf_find_state_byid(&id_key);
6282d48ac80Sdegroote 			if (st == NULL) {
6292d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
6302d48ac80Sdegroote 				continue;
6312d48ac80Sdegroote 			}
6322d48ac80Sdegroote 			st->sync_flags |= PFSTATE_FROMSYNC;
6332d48ac80Sdegroote 			pf_unlink_state(st);
6342d48ac80Sdegroote 		}
6352d48ac80Sdegroote 		splx(s);
6362d48ac80Sdegroote 		break;
6372d48ac80Sdegroote 	case PFSYNC_ACT_UPD_C: {
6382d48ac80Sdegroote 		int update_requested = 0;
6392d48ac80Sdegroote 
6402d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
6412d48ac80Sdegroote 		    count * sizeof(*up), &offp)) == NULL) {
6422d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
6432d48ac80Sdegroote 			return;
6442d48ac80Sdegroote 		}
6452d48ac80Sdegroote 
6462d48ac80Sdegroote 		s = splsoftnet();
6472d48ac80Sdegroote 		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
6482d48ac80Sdegroote 		    i < count; i++, up++) {
6492d48ac80Sdegroote 			/* check for invalid values */
6502d48ac80Sdegroote 			if (up->timeout >= PFTM_MAX ||
6512d48ac80Sdegroote 			    up->src.state > PF_TCPS_PROXY_DST ||
6522d48ac80Sdegroote 			    up->dst.state > PF_TCPS_PROXY_DST) {
6532d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
6542d48ac80Sdegroote 					printf("pfsync_insert: "
6552d48ac80Sdegroote 					    "PFSYNC_ACT_UPD_C: "
6562d48ac80Sdegroote 					    "invalid value\n");
6572d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
6582d48ac80Sdegroote 				continue;
6592d48ac80Sdegroote 			}
6602d48ac80Sdegroote 
6612d48ac80Sdegroote 			memcpy(&id_key.id, up->id, sizeof(id_key.id));
6622d48ac80Sdegroote 			id_key.creatorid = up->creatorid;
6632d48ac80Sdegroote 
6642d48ac80Sdegroote 			st = pf_find_state_byid(&id_key);
6652d48ac80Sdegroote 			if (st == NULL) {
6662d48ac80Sdegroote 				/* We don't have this state. Ask for it. */
6672d48ac80Sdegroote 				error = pfsync_request_update(up, &src);
6682d48ac80Sdegroote 				if (error == ENOMEM) {
6692d48ac80Sdegroote 					splx(s);
6702d48ac80Sdegroote 					goto done;
6712d48ac80Sdegroote 				}
6722d48ac80Sdegroote 				update_requested = 1;
6732d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
6742d48ac80Sdegroote 				continue;
6752d48ac80Sdegroote 			}
6762d48ac80Sdegroote 			sk = st->state_key;
6772d48ac80Sdegroote 			sfail = 0;
6782d48ac80Sdegroote 			if (sk->proto == IPPROTO_TCP) {
6792d48ac80Sdegroote 				/*
6802d48ac80Sdegroote 				 * The state should never go backwards except
6812d48ac80Sdegroote 				 * for syn-proxy states.  Neither should the
6822d48ac80Sdegroote 				 * sequence window slide backwards.
6832d48ac80Sdegroote 				 */
6842d48ac80Sdegroote 				if (st->src.state > up->src.state &&
6852d48ac80Sdegroote 				    (st->src.state < PF_TCPS_PROXY_SRC ||
6862d48ac80Sdegroote 				    up->src.state >= PF_TCPS_PROXY_SRC))
6872d48ac80Sdegroote 					sfail = 1;
6882d48ac80Sdegroote 				else if (st->dst.state > up->dst.state)
6892d48ac80Sdegroote 					sfail = 2;
6902d48ac80Sdegroote 				else if (SEQ_GT(st->src.seqlo,
6912d48ac80Sdegroote 				    ntohl(up->src.seqlo)))
6922d48ac80Sdegroote 					sfail = 3;
6932d48ac80Sdegroote 				else if (st->dst.state >= TCPS_SYN_SENT &&
6942d48ac80Sdegroote 				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
6952d48ac80Sdegroote 					sfail = 4;
6962d48ac80Sdegroote 			} else {
6972d48ac80Sdegroote 				/*
6982d48ac80Sdegroote 				 * Non-TCP protocol state machine always go
6992d48ac80Sdegroote 				 * forwards
7002d48ac80Sdegroote 				 */
7012d48ac80Sdegroote 				if (st->src.state > up->src.state)
7022d48ac80Sdegroote 					sfail = 5;
7032d48ac80Sdegroote 				else if (st->dst.state > up->dst.state)
7042d48ac80Sdegroote 					sfail = 6;
7052d48ac80Sdegroote 			}
7062d48ac80Sdegroote 			if (sfail) {
7072d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
7082d48ac80Sdegroote 					printf("pfsync: ignoring stale update "
7092d48ac80Sdegroote 					    "(%d) id: %016" PRIu64 ""
7102d48ac80Sdegroote 					    "creatorid: %08x\n", sfail,
7112d48ac80Sdegroote 					    be64toh(st->id),
7122d48ac80Sdegroote 					    ntohl(st->creatorid));
7132d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
7142d48ac80Sdegroote 
7152d48ac80Sdegroote 				/* we have a better state, send it out */
7162d48ac80Sdegroote 				if ((!stale || update_requested) &&
7172d48ac80Sdegroote 				    sc->sc_mbuf != NULL) {
7182d48ac80Sdegroote 					pfsync_sendout(sc);
7192d48ac80Sdegroote 					update_requested = 0;
7202d48ac80Sdegroote 				}
7212d48ac80Sdegroote 				stale++;
7222d48ac80Sdegroote 				if (!st->sync_flags)
7232d48ac80Sdegroote 					pfsync_pack_state(PFSYNC_ACT_UPD, st,
7242d48ac80Sdegroote 					    PFSYNC_FLAG_STALE);
7252d48ac80Sdegroote 				continue;
7262d48ac80Sdegroote 			}
7272d48ac80Sdegroote 	    		pfsync_alloc_scrub_memory(&up->dst, &st->dst);
7282d48ac80Sdegroote 			pf_state_peer_ntoh(&up->src, &st->src);
7292d48ac80Sdegroote 			pf_state_peer_ntoh(&up->dst, &st->dst);
7302d48ac80Sdegroote 			st->expire = ntohl(up->expire) + time_second;
7312d48ac80Sdegroote 			st->timeout = up->timeout;
7322d48ac80Sdegroote 		}
7332d48ac80Sdegroote 		if ((update_requested || stale) && sc->sc_mbuf)
7342d48ac80Sdegroote 			pfsync_sendout(sc);
7352d48ac80Sdegroote 		splx(s);
7362d48ac80Sdegroote 		break;
7372d48ac80Sdegroote 	}
7382d48ac80Sdegroote 	case PFSYNC_ACT_DEL_C:
7392d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
7402d48ac80Sdegroote 		    count * sizeof(*dp), &offp)) == NULL) {
7412d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
7422d48ac80Sdegroote 			return;
7432d48ac80Sdegroote 		}
7442d48ac80Sdegroote 
7452d48ac80Sdegroote 		s = splsoftnet();
7462d48ac80Sdegroote 		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
7472d48ac80Sdegroote 		    i < count; i++, dp++) {
7482d48ac80Sdegroote 			memcpy(&id_key.id, dp->id, sizeof(id_key.id));
7492d48ac80Sdegroote 			id_key.creatorid = dp->creatorid;
7502d48ac80Sdegroote 
7512d48ac80Sdegroote 			st = pf_find_state_byid(&id_key);
7522d48ac80Sdegroote 			if (st == NULL) {
7532d48ac80Sdegroote 				PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
7542d48ac80Sdegroote 				continue;
7552d48ac80Sdegroote 			}
7562d48ac80Sdegroote 			st->sync_flags |= PFSTATE_FROMSYNC;
7572d48ac80Sdegroote 			pf_unlink_state(st);
7582d48ac80Sdegroote 		}
7592d48ac80Sdegroote 		splx(s);
7602d48ac80Sdegroote 		break;
7612d48ac80Sdegroote 	case PFSYNC_ACT_INS_F:
7622d48ac80Sdegroote 	case PFSYNC_ACT_DEL_F:
7632d48ac80Sdegroote 		/* not implemented */
7642d48ac80Sdegroote 		break;
7652d48ac80Sdegroote 	case PFSYNC_ACT_UREQ:
7662d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
7672d48ac80Sdegroote 		    count * sizeof(*rup), &offp)) == NULL) {
7682d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
7692d48ac80Sdegroote 			return;
7702d48ac80Sdegroote 		}
7712d48ac80Sdegroote 
7722d48ac80Sdegroote 		s = splsoftnet();
7732d48ac80Sdegroote 		if (sc->sc_mbuf != NULL)
7742d48ac80Sdegroote 			pfsync_sendout(sc);
7752d48ac80Sdegroote 		for (i = 0,
7762d48ac80Sdegroote 		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
7772d48ac80Sdegroote 		    i < count; i++, rup++) {
7782d48ac80Sdegroote 			memcpy(&id_key.id, rup->id, sizeof(id_key.id));
7792d48ac80Sdegroote 			id_key.creatorid = rup->creatorid;
7802d48ac80Sdegroote 
7812d48ac80Sdegroote 			if (id_key.id == 0 && id_key.creatorid == 0) {
7822d48ac80Sdegroote 				sc->sc_ureq_received = time_uptime;
7832d48ac80Sdegroote 				if (sc->sc_bulk_send_next == NULL)
7842d48ac80Sdegroote 					sc->sc_bulk_send_next =
7852d48ac80Sdegroote 					    TAILQ_FIRST(&state_list);
7862d48ac80Sdegroote 				sc->sc_bulk_terminator = sc->sc_bulk_send_next;
7872d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
7882d48ac80Sdegroote 					printf("pfsync: received "
7892d48ac80Sdegroote 					    "bulk update request\n");
7902d48ac80Sdegroote 				pfsync_send_bus(sc, PFSYNC_BUS_START);
7912d48ac80Sdegroote 				callout_schedule(&sc->sc_bulk_tmo, 1 * hz);
7922d48ac80Sdegroote 			} else {
7932d48ac80Sdegroote 				st = pf_find_state_byid(&id_key);
7942d48ac80Sdegroote 				if (st == NULL) {
7952d48ac80Sdegroote 					PFSYNC_STATINC(PFSYNC_STAT_BADSTATE);
7962d48ac80Sdegroote 					continue;
7972d48ac80Sdegroote 				}
7982d48ac80Sdegroote 				if (!st->sync_flags)
7992d48ac80Sdegroote 					pfsync_pack_state(PFSYNC_ACT_UPD,
8002d48ac80Sdegroote 					    st, 0);
8012d48ac80Sdegroote 			}
8022d48ac80Sdegroote 		}
8032d48ac80Sdegroote 		if (sc->sc_mbuf != NULL)
8042d48ac80Sdegroote 			pfsync_sendout(sc);
8052d48ac80Sdegroote 		splx(s);
8062d48ac80Sdegroote 		break;
8072d48ac80Sdegroote 	case PFSYNC_ACT_BUS:
8082d48ac80Sdegroote 		/* If we're not waiting for a bulk update, who cares. */
8092d48ac80Sdegroote 		if (sc->sc_ureq_sent == 0)
8102d48ac80Sdegroote 			break;
8112d48ac80Sdegroote 
8122d48ac80Sdegroote 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
8132d48ac80Sdegroote 		    sizeof(*bus), &offp)) == NULL) {
8142d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_BADLEN);
8152d48ac80Sdegroote 			return;
8162d48ac80Sdegroote 		}
8172d48ac80Sdegroote 		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
8182d48ac80Sdegroote 		switch (bus->status) {
8192d48ac80Sdegroote 		case PFSYNC_BUS_START:
8202d48ac80Sdegroote 			callout_schedule(&sc->sc_bulkfail_tmo,
8212d48ac80Sdegroote 			    pf_pool_limits[PF_LIMIT_STATES].limit /
8222d48ac80Sdegroote 			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
8232d48ac80Sdegroote 			if (pf_status.debug >= PF_DEBUG_MISC)
8242d48ac80Sdegroote 				printf("pfsync: received bulk "
8252d48ac80Sdegroote 				    "update start\n");
8262d48ac80Sdegroote 			break;
8272d48ac80Sdegroote 		case PFSYNC_BUS_END:
8282d48ac80Sdegroote 			if (time_uptime - ntohl(bus->endtime) >=
8292d48ac80Sdegroote 			    sc->sc_ureq_sent) {
8302d48ac80Sdegroote 				/* that's it, we're happy */
8312d48ac80Sdegroote 				sc->sc_ureq_sent = 0;
8322d48ac80Sdegroote 				sc->sc_bulk_tries = 0;
8332d48ac80Sdegroote 				callout_stop(&sc->sc_bulkfail_tmo);
8342d48ac80Sdegroote #if NCARP > 0
8352d48ac80Sdegroote 				if (!pfsync_sync_ok)
8362d48ac80Sdegroote 					carp_suppress_preempt--;
8372d48ac80Sdegroote #endif
8382d48ac80Sdegroote 				pfsync_sync_ok = 1;
8392d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
8402d48ac80Sdegroote 					printf("pfsync: received valid "
8412d48ac80Sdegroote 					    "bulk update end\n");
8422d48ac80Sdegroote 			} else {
8432d48ac80Sdegroote 				if (pf_status.debug >= PF_DEBUG_MISC)
8442d48ac80Sdegroote 					printf("pfsync: received invalid "
8452d48ac80Sdegroote 					    "bulk update end: bad timestamp\n");
8462d48ac80Sdegroote 			}
8472d48ac80Sdegroote 			break;
8482d48ac80Sdegroote 		}
8492d48ac80Sdegroote 		break;
8502d48ac80Sdegroote 	}
8512d48ac80Sdegroote 
8522d48ac80Sdegroote done:
8532d48ac80Sdegroote 	if (m)
8542d48ac80Sdegroote 		m_freem(m);
8552d48ac80Sdegroote }
8562d48ac80Sdegroote 
8572d48ac80Sdegroote int
pfsyncoutput(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,const struct rtentry * rt)8582d48ac80Sdegroote pfsyncoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
8599b969dc0Sozaki-r 	const struct rtentry *rt)
8602d48ac80Sdegroote {
8612d48ac80Sdegroote 	m_freem(m);
8622d48ac80Sdegroote 	return (0);
8632d48ac80Sdegroote }
8642d48ac80Sdegroote 
8652d48ac80Sdegroote /* ARGSUSED */
8662d48ac80Sdegroote int
pfsyncioctl(struct ifnet * ifp,u_long cmd,void * data)8672d48ac80Sdegroote pfsyncioctl(struct ifnet *ifp, u_long cmd, void*  data)
8682d48ac80Sdegroote {
8692d48ac80Sdegroote 	struct lwp *l = curlwp;
8702d48ac80Sdegroote 	struct pfsync_softc *sc = ifp->if_softc;
8712d48ac80Sdegroote 	struct ifreq *ifr = (struct ifreq *)data;
8722d48ac80Sdegroote 	struct ip_moptions *imo = &sc->sc_imo;
8732d48ac80Sdegroote 	struct pfsyncreq pfsyncr;
8742d48ac80Sdegroote 	struct ifnet    *sifp;
8752d48ac80Sdegroote 	int s, error;
8762d48ac80Sdegroote 
8772d48ac80Sdegroote 	switch (cmd) {
8782d48ac80Sdegroote 	case SIOCSIFADDR:
8792d48ac80Sdegroote 	case SIOCAIFADDR:
8802d48ac80Sdegroote 	case SIOCSIFDSTADDR:
8812d48ac80Sdegroote 	case SIOCSIFFLAGS:
8822d48ac80Sdegroote 		if (ifp->if_flags & IFF_UP)
8832d48ac80Sdegroote 			ifp->if_flags |= IFF_RUNNING;
8842d48ac80Sdegroote 		else
8852d48ac80Sdegroote 			ifp->if_flags &= ~IFF_RUNNING;
8862d48ac80Sdegroote 		break;
8872d48ac80Sdegroote 	case SIOCSIFMTU:
8882d48ac80Sdegroote 		if (ifr->ifr_mtu < PFSYNC_MINMTU)
8892d48ac80Sdegroote 			return (EINVAL);
8902d48ac80Sdegroote 		if (ifr->ifr_mtu > MCLBYTES)
8912d48ac80Sdegroote 			ifr->ifr_mtu = MCLBYTES;
8922d48ac80Sdegroote 		s = splnet();
8932d48ac80Sdegroote 		if (ifr->ifr_mtu < ifp->if_mtu)
8942d48ac80Sdegroote 			pfsync_sendout(sc);
8952d48ac80Sdegroote 		pfsync_setmtu(sc, ifr->ifr_mtu);
8962d48ac80Sdegroote 		splx(s);
8972d48ac80Sdegroote 		break;
8982d48ac80Sdegroote 	case SIOCGETPFSYNC:
8992d48ac80Sdegroote 		if ((error = kauth_authorize_network(l->l_cred,
9002d48ac80Sdegroote 		    KAUTH_NETWORK_INTERFACE,
9012d48ac80Sdegroote 		    KAUTH_REQ_NETWORK_INTERFACE_GETPRIV, ifp, (void *)cmd,
9022d48ac80Sdegroote 		    NULL)) != 0)
9032d48ac80Sdegroote 			return (error);
9042d48ac80Sdegroote 		memset(&pfsyncr, 0, sizeof(pfsyncr));
9052d48ac80Sdegroote 		if (sc->sc_sync_ifp)
9062d48ac80Sdegroote 			strlcpy(pfsyncr.pfsyncr_syncdev,
9072d48ac80Sdegroote 			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
9082d48ac80Sdegroote 		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
9092d48ac80Sdegroote 		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
9102d48ac80Sdegroote 		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
9112d48ac80Sdegroote 			return (error);
9122d48ac80Sdegroote 		break;
9132d48ac80Sdegroote 	case SIOCSETPFSYNC:
9142d48ac80Sdegroote 		if ((error = kauth_authorize_network(l->l_cred,
9152d48ac80Sdegroote 		    KAUTH_NETWORK_INTERFACE,
9162d48ac80Sdegroote 		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
9172d48ac80Sdegroote 		    NULL)) != 0)
9182d48ac80Sdegroote 			return (error);
9192d48ac80Sdegroote 		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
9202d48ac80Sdegroote 			return (error);
9212d48ac80Sdegroote 
9222d48ac80Sdegroote 		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
9232d48ac80Sdegroote 			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
9242d48ac80Sdegroote 		else
9252d48ac80Sdegroote 			sc->sc_sync_peer.s_addr =
9262d48ac80Sdegroote 			    pfsyncr.pfsyncr_syncpeer.s_addr;
9272d48ac80Sdegroote 
9282d48ac80Sdegroote 		if (pfsyncr.pfsyncr_maxupdates > 255)
9292d48ac80Sdegroote 			return (EINVAL);
9302d48ac80Sdegroote 		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
9312d48ac80Sdegroote 
9322d48ac80Sdegroote 		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
9332d48ac80Sdegroote 			sc->sc_sync_ifp = NULL;
9342d48ac80Sdegroote 			if (sc->sc_mbuf_net != NULL) {
9352d48ac80Sdegroote 				/* Don't keep stale pfsync packets around. */
9362d48ac80Sdegroote 				s = splnet();
9372d48ac80Sdegroote 				m_freem(sc->sc_mbuf_net);
9382d48ac80Sdegroote 				sc->sc_mbuf_net = NULL;
9392d48ac80Sdegroote 				sc->sc_statep_net.s = NULL;
9402d48ac80Sdegroote 				splx(s);
9412d48ac80Sdegroote 			}
9422d48ac80Sdegroote 			if (imo->imo_num_memberships > 0) {
9432d48ac80Sdegroote 				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
944a10bcd0eSozaki-r 				imo->imo_multicast_if_index = 0;
9452d48ac80Sdegroote 			}
9462d48ac80Sdegroote 			break;
9472d48ac80Sdegroote 		}
9482d48ac80Sdegroote 
9492d48ac80Sdegroote 		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
9502d48ac80Sdegroote 			return (EINVAL);
9512d48ac80Sdegroote 
9522d48ac80Sdegroote 		s = splnet();
9532d48ac80Sdegroote 		if (sifp->if_mtu < sc->sc_if.if_mtu ||
9542d48ac80Sdegroote 		    (sc->sc_sync_ifp != NULL &&
9552d48ac80Sdegroote 		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
9562d48ac80Sdegroote 		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
9572d48ac80Sdegroote 			pfsync_sendout(sc);
9582d48ac80Sdegroote 		sc->sc_sync_ifp = sifp;
9592d48ac80Sdegroote 
9602d48ac80Sdegroote 		pfsync_setmtu(sc, sc->sc_if.if_mtu);
9612d48ac80Sdegroote 
9622d48ac80Sdegroote 		if (imo->imo_num_memberships > 0) {
9632d48ac80Sdegroote 			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
964a10bcd0eSozaki-r 			imo->imo_multicast_if_index = 0;
9652d48ac80Sdegroote 		}
9662d48ac80Sdegroote 
9672d48ac80Sdegroote 		if (sc->sc_sync_ifp &&
9682d48ac80Sdegroote 		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
9692d48ac80Sdegroote 			struct in_addr addr;
9702d48ac80Sdegroote 
9712d48ac80Sdegroote 			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
9722d48ac80Sdegroote 				sc->sc_sync_ifp = NULL;
9732d48ac80Sdegroote 				splx(s);
9742d48ac80Sdegroote 				return (EADDRNOTAVAIL);
9752d48ac80Sdegroote 			}
9762d48ac80Sdegroote 
9772d48ac80Sdegroote 			addr.s_addr = INADDR_PFSYNC_GROUP;
9782d48ac80Sdegroote 
9792d48ac80Sdegroote 			if ((imo->imo_membership[0] =
9802d48ac80Sdegroote 			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
9812d48ac80Sdegroote 				sc->sc_sync_ifp = NULL;
9822d48ac80Sdegroote 				splx(s);
9832d48ac80Sdegroote 				return (ENOBUFS);
9842d48ac80Sdegroote 			}
9852d48ac80Sdegroote 			imo->imo_num_memberships++;
986a10bcd0eSozaki-r 			imo->imo_multicast_if_index = if_get_index(sc->sc_sync_ifp);
9872d48ac80Sdegroote 			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
9882d48ac80Sdegroote 			imo->imo_multicast_loop = 0;
9892d48ac80Sdegroote 		}
9902d48ac80Sdegroote 
9912d48ac80Sdegroote 		if (sc->sc_sync_ifp ||
9922d48ac80Sdegroote 		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
9932d48ac80Sdegroote 			/* Request a full state table update. */
9942d48ac80Sdegroote 			sc->sc_ureq_sent = time_uptime;
9952d48ac80Sdegroote #if NCARP > 0
9962d48ac80Sdegroote 			if (pfsync_sync_ok)
9972d48ac80Sdegroote 				carp_suppress_preempt ++;
9982d48ac80Sdegroote #endif
9992d48ac80Sdegroote 			pfsync_sync_ok = 0;
10002d48ac80Sdegroote 			if (pf_status.debug >= PF_DEBUG_MISC)
10012d48ac80Sdegroote 				printf("pfsync: requesting bulk update\n");
10022d48ac80Sdegroote 			callout_schedule(&sc->sc_bulkfail_tmo, 5 * hz);
10032d48ac80Sdegroote 			error = pfsync_request_update(NULL, NULL);
10042d48ac80Sdegroote 			if (error == ENOMEM) {
10052d48ac80Sdegroote 				splx(s);
10062d48ac80Sdegroote 				return (ENOMEM);
10072d48ac80Sdegroote 			}
10082d48ac80Sdegroote 			pfsync_sendout(sc);
10092d48ac80Sdegroote 		}
10102d48ac80Sdegroote 		splx(s);
10112d48ac80Sdegroote 
10122d48ac80Sdegroote 		break;
10132d48ac80Sdegroote 
10142d48ac80Sdegroote 	default:
10152d48ac80Sdegroote 		return ifioctl_common(ifp, cmd, data);
10162d48ac80Sdegroote 	}
10172d48ac80Sdegroote 
10182d48ac80Sdegroote 	return (0);
10192d48ac80Sdegroote }
10202d48ac80Sdegroote 
10212d48ac80Sdegroote void
pfsync_setmtu(struct pfsync_softc * sc,int mtu_req)10222d48ac80Sdegroote pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
10232d48ac80Sdegroote {
10242d48ac80Sdegroote 	int mtu;
10252d48ac80Sdegroote 
10262d48ac80Sdegroote 	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
10272d48ac80Sdegroote 		mtu = sc->sc_sync_ifp->if_mtu;
10282d48ac80Sdegroote 	else
10292d48ac80Sdegroote 		mtu = mtu_req;
10302d48ac80Sdegroote 
10312d48ac80Sdegroote 	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
10322d48ac80Sdegroote 	    sizeof(struct pfsync_state);
10332d48ac80Sdegroote 	if (sc->sc_maxcount > 254)
10342d48ac80Sdegroote 	    sc->sc_maxcount = 254;
10352d48ac80Sdegroote 	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
10362d48ac80Sdegroote 	    sc->sc_maxcount * sizeof(struct pfsync_state);
10372d48ac80Sdegroote }
10382d48ac80Sdegroote 
10392d48ac80Sdegroote struct mbuf *
pfsync_get_mbuf(struct pfsync_softc * sc,u_int8_t action,void ** sp)10402d48ac80Sdegroote pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
10412d48ac80Sdegroote {
10422d48ac80Sdegroote 	struct pfsync_header *h;
10432d48ac80Sdegroote 	struct mbuf *m;
10442d48ac80Sdegroote 	int len;
10452d48ac80Sdegroote 
10462d48ac80Sdegroote 	MGETHDR(m, M_DONTWAIT, MT_DATA);
10472d48ac80Sdegroote 	if (m == NULL) {
10480b131f18Sthorpej #ifdef __NetBSD__
10490b131f18Sthorpej 		if_statinc(&sc->sc_if, if_oerrors);
10500b131f18Sthorpej #else
10512d48ac80Sdegroote 		sc->sc_if.if_oerrors++;
10520b131f18Sthorpej #endif /* __NetBSD__ */
10532d48ac80Sdegroote 		return (NULL);
10542d48ac80Sdegroote 	}
10552d48ac80Sdegroote 
10562d48ac80Sdegroote 	switch (action) {
10572d48ac80Sdegroote 	case PFSYNC_ACT_CLR:
10582d48ac80Sdegroote 		len = sizeof(struct pfsync_header) +
10592d48ac80Sdegroote 		    sizeof(struct pfsync_state_clr);
10602d48ac80Sdegroote 		break;
10612d48ac80Sdegroote 	case PFSYNC_ACT_UPD_C:
10622d48ac80Sdegroote 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
10632d48ac80Sdegroote 		    sizeof(struct pfsync_header);
10642d48ac80Sdegroote 		break;
10652d48ac80Sdegroote 	case PFSYNC_ACT_DEL_C:
10662d48ac80Sdegroote 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
10672d48ac80Sdegroote 		    sizeof(struct pfsync_header);
10682d48ac80Sdegroote 		break;
10692d48ac80Sdegroote 	case PFSYNC_ACT_UREQ:
10702d48ac80Sdegroote 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
10712d48ac80Sdegroote 		    sizeof(struct pfsync_header);
10722d48ac80Sdegroote 		break;
10732d48ac80Sdegroote 	case PFSYNC_ACT_BUS:
10742d48ac80Sdegroote 		len = sizeof(struct pfsync_header) +
10752d48ac80Sdegroote 		    sizeof(struct pfsync_state_bus);
10762d48ac80Sdegroote 		break;
10772d48ac80Sdegroote 	case PFSYNC_ACT_TDB_UPD:
10782d48ac80Sdegroote 		len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
10792d48ac80Sdegroote 		    sizeof(struct pfsync_header);
10802d48ac80Sdegroote 		break;
10812d48ac80Sdegroote 	default:
10822d48ac80Sdegroote 		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
10832d48ac80Sdegroote 		    sizeof(struct pfsync_header);
10842d48ac80Sdegroote 		break;
10852d48ac80Sdegroote 	}
10862d48ac80Sdegroote 
10872d48ac80Sdegroote 	if (len > MHLEN) {
10882d48ac80Sdegroote 		MCLGET(m, M_DONTWAIT);
10892d48ac80Sdegroote 		if ((m->m_flags & M_EXT) == 0) {
10902d48ac80Sdegroote 			m_free(m);
10910b131f18Sthorpej #ifdef __NetBSD__
10920b131f18Sthorpej 			if_statinc(&sc->sc_if, if_oerrors);
10930b131f18Sthorpej #else
10942d48ac80Sdegroote 			sc->sc_if.if_oerrors++;
10950b131f18Sthorpej #endif /* __NetBSD__ */
10962d48ac80Sdegroote 			return (NULL);
10972d48ac80Sdegroote 		}
10982d48ac80Sdegroote 		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
10992d48ac80Sdegroote 	} else
1100ae0244dfSmaxv 		m_align(m, len);
11012d48ac80Sdegroote 
1102758ba73eSozaki-r 	m_reset_rcvif(m);
11032d48ac80Sdegroote 	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
11042d48ac80Sdegroote 	h = mtod(m, struct pfsync_header *);
11052d48ac80Sdegroote 	h->version = PFSYNC_VERSION;
11062d48ac80Sdegroote 	h->af = 0;
11072d48ac80Sdegroote 	h->count = 0;
11082d48ac80Sdegroote 	h->action = action;
11092d48ac80Sdegroote 	if (action != PFSYNC_ACT_TDB_UPD)
11102d48ac80Sdegroote 		memcpy(&h->pf_chksum, &pf_status.pf_chksum,
11112d48ac80Sdegroote 		    PF_MD5_DIGEST_LENGTH);
11122d48ac80Sdegroote 
11132d48ac80Sdegroote 	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
11142d48ac80Sdegroote 	if (action == PFSYNC_ACT_TDB_UPD)
11152d48ac80Sdegroote 		callout_schedule(&sc->sc_tdb_tmo, hz);
11162d48ac80Sdegroote 	else
11172d48ac80Sdegroote 		callout_schedule(&sc->sc_tmo, hz);
11182d48ac80Sdegroote 	return (m);
11192d48ac80Sdegroote }
11202d48ac80Sdegroote 
11212d48ac80Sdegroote int
pfsync_pack_state(u_int8_t action,struct pf_state * st,int flags)11222d48ac80Sdegroote pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
11232d48ac80Sdegroote {
11242d48ac80Sdegroote 	struct ifnet *ifp = NULL;
11252d48ac80Sdegroote 	struct pfsync_softc *sc = pfsyncif;
11262d48ac80Sdegroote 	struct pfsync_header *h, *h_net;
11272d48ac80Sdegroote 	struct pfsync_state *sp = NULL;
11282d48ac80Sdegroote 	struct pfsync_state_upd *up = NULL;
11292d48ac80Sdegroote 	struct pfsync_state_del *dp = NULL;
11302d48ac80Sdegroote 	struct pf_state_key *sk = st->state_key;
11312d48ac80Sdegroote 	struct pf_rule *r;
11322d48ac80Sdegroote 	u_long secs;
11332d48ac80Sdegroote 	int s, ret = 0;
11342d48ac80Sdegroote 	u_int8_t i = 255, newaction = 0;
11352d48ac80Sdegroote 
11362d48ac80Sdegroote 	if (sc == NULL)
11372d48ac80Sdegroote 		return (0);
11382d48ac80Sdegroote 	ifp = &sc->sc_if;
11392d48ac80Sdegroote 
11402d48ac80Sdegroote 	/*
11412d48ac80Sdegroote 	 * If a packet falls in the forest and there's nobody around to
11422d48ac80Sdegroote 	 * hear, does it make a sound?
11432d48ac80Sdegroote 	 */
11442d48ac80Sdegroote 	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
11452d48ac80Sdegroote 	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
11462d48ac80Sdegroote 		/* Don't leave any stale pfsync packets hanging around. */
11472d48ac80Sdegroote 		if (sc->sc_mbuf != NULL) {
11482d48ac80Sdegroote 			m_freem(sc->sc_mbuf);
11492d48ac80Sdegroote 			sc->sc_mbuf = NULL;
11502d48ac80Sdegroote 			sc->sc_statep.s = NULL;
11512d48ac80Sdegroote 		}
11522d48ac80Sdegroote 		return (0);
11532d48ac80Sdegroote 	}
11542d48ac80Sdegroote 
11552d48ac80Sdegroote 	if (action >= PFSYNC_ACT_MAX)
11562d48ac80Sdegroote 		return (EINVAL);
11572d48ac80Sdegroote 
11582d48ac80Sdegroote 	s = splnet();
11592d48ac80Sdegroote 	if (sc->sc_mbuf == NULL) {
11602d48ac80Sdegroote 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
11612d48ac80Sdegroote 		    (void *)&sc->sc_statep.s)) == NULL) {
11622d48ac80Sdegroote 			splx(s);
11632d48ac80Sdegroote 			return (ENOMEM);
11642d48ac80Sdegroote 		}
11652d48ac80Sdegroote 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
11662d48ac80Sdegroote 	} else {
11672d48ac80Sdegroote 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
11682d48ac80Sdegroote 		if (h->action != action) {
11692d48ac80Sdegroote 			pfsync_sendout(sc);
11702d48ac80Sdegroote 			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
11712d48ac80Sdegroote 			    (void *)&sc->sc_statep.s)) == NULL) {
11722d48ac80Sdegroote 				splx(s);
11732d48ac80Sdegroote 				return (ENOMEM);
11742d48ac80Sdegroote 			}
11752d48ac80Sdegroote 			h = mtod(sc->sc_mbuf, struct pfsync_header *);
11762d48ac80Sdegroote 		} else {
11772d48ac80Sdegroote 			/*
11782d48ac80Sdegroote 			 * If it's an update, look in the packet to see if
11792d48ac80Sdegroote 			 * we already have an update for the state.
11802d48ac80Sdegroote 			 */
11812d48ac80Sdegroote 			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
11822d48ac80Sdegroote 				struct pfsync_state *usp =
11832d48ac80Sdegroote 				    (void *)((char *)h + PFSYNC_HDRLEN);
11842d48ac80Sdegroote 
11852d48ac80Sdegroote 				for (i = 0; i < h->count; i++) {
11862d48ac80Sdegroote 					if (!memcmp(usp->id, &st->id,
11872d48ac80Sdegroote 					    PFSYNC_ID_LEN) &&
11882d48ac80Sdegroote 					    usp->creatorid == st->creatorid) {
11892d48ac80Sdegroote 						sp = usp;
11902d48ac80Sdegroote 						sp->updates++;
11912d48ac80Sdegroote 						break;
11922d48ac80Sdegroote 					}
11932d48ac80Sdegroote 					usp++;
11942d48ac80Sdegroote 				}
11952d48ac80Sdegroote 			}
11962d48ac80Sdegroote 		}
11972d48ac80Sdegroote 	}
11982d48ac80Sdegroote 
11992d48ac80Sdegroote 	secs = time_second;
12002d48ac80Sdegroote 
12012d48ac80Sdegroote 	st->pfsync_time = time_uptime;
12022d48ac80Sdegroote 
12032d48ac80Sdegroote 	if (sp == NULL) {
12042d48ac80Sdegroote 		/* not a "duplicate" update */
12052d48ac80Sdegroote 		i = 255;
12062d48ac80Sdegroote 		sp = sc->sc_statep.s++;
12072d48ac80Sdegroote 		sc->sc_mbuf->m_pkthdr.len =
12082d48ac80Sdegroote 		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
12092d48ac80Sdegroote 		h->count++;
12102d48ac80Sdegroote 		memset(sp, 0, sizeof(*sp));
12112d48ac80Sdegroote 
12122d48ac80Sdegroote 		memcpy(sp->id, &st->id, sizeof(sp->id));
12132d48ac80Sdegroote 		sp->creatorid = st->creatorid;
12142d48ac80Sdegroote 
12152d48ac80Sdegroote 		strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
12162d48ac80Sdegroote 		pf_state_host_hton(&sk->lan, &sp->lan);
12172d48ac80Sdegroote 		pf_state_host_hton(&sk->gwy, &sp->gwy);
12182d48ac80Sdegroote 		pf_state_host_hton(&sk->ext, &sp->ext);
12192d48ac80Sdegroote 
12202d48ac80Sdegroote 		memcpy(&sp->rt_addr, &st->rt_addr, sizeof(sp->rt_addr));
12212d48ac80Sdegroote 
12222d48ac80Sdegroote 		sp->creation = htonl(secs - st->creation);
12232d48ac80Sdegroote 		pf_state_counter_hton(st->packets[0], sp->packets[0]);
12242d48ac80Sdegroote 		pf_state_counter_hton(st->packets[1], sp->packets[1]);
12252d48ac80Sdegroote 		pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
12262d48ac80Sdegroote 		pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
12272d48ac80Sdegroote 		if ((r = st->rule.ptr) == NULL)
12282d48ac80Sdegroote 			sp->rule = htonl(-1);
12292d48ac80Sdegroote 		else
12302d48ac80Sdegroote 			sp->rule = htonl(r->nr);
12312d48ac80Sdegroote 		if ((r = st->anchor.ptr) == NULL)
12322d48ac80Sdegroote 			sp->anchor = htonl(-1);
12332d48ac80Sdegroote 		else
12342d48ac80Sdegroote 			sp->anchor = htonl(r->nr);
12352d48ac80Sdegroote 		sp->af = sk->af;
12362d48ac80Sdegroote 		sp->proto = sk->proto;
12372d48ac80Sdegroote 		sp->direction = sk->direction;
12382d48ac80Sdegroote 		sp->log = st->log;
12392d48ac80Sdegroote 		sp->allow_opts = st->allow_opts;
12402d48ac80Sdegroote 		sp->timeout = st->timeout;
12412d48ac80Sdegroote 
12422d48ac80Sdegroote 		if (flags & PFSYNC_FLAG_STALE)
12432d48ac80Sdegroote 			sp->sync_flags |= PFSTATE_STALE;
12442d48ac80Sdegroote 	}
12452d48ac80Sdegroote 
12462d48ac80Sdegroote 	pf_state_peer_hton(&st->src, &sp->src);
12472d48ac80Sdegroote 	pf_state_peer_hton(&st->dst, &sp->dst);
12482d48ac80Sdegroote 
12492d48ac80Sdegroote 	if (st->expire <= secs)
12502d48ac80Sdegroote 		sp->expire = htonl(0);
12512d48ac80Sdegroote 	else
12522d48ac80Sdegroote 		sp->expire = htonl(st->expire - secs);
12532d48ac80Sdegroote 
12542d48ac80Sdegroote 	/* do we need to build "compressed" actions for network transfer? */
12552d48ac80Sdegroote 	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
12562d48ac80Sdegroote 		switch (action) {
12572d48ac80Sdegroote 		case PFSYNC_ACT_UPD:
12582d48ac80Sdegroote 			newaction = PFSYNC_ACT_UPD_C;
12592d48ac80Sdegroote 			break;
12602d48ac80Sdegroote 		case PFSYNC_ACT_DEL:
12612d48ac80Sdegroote 			newaction = PFSYNC_ACT_DEL_C;
12622d48ac80Sdegroote 			break;
12632d48ac80Sdegroote 		default:
12642d48ac80Sdegroote 			/* by default we just send the uncompressed states */
12652d48ac80Sdegroote 			break;
12662d48ac80Sdegroote 		}
12672d48ac80Sdegroote 	}
12682d48ac80Sdegroote 
12692d48ac80Sdegroote 	if (newaction) {
12702d48ac80Sdegroote 		if (sc->sc_mbuf_net == NULL) {
12712d48ac80Sdegroote 			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
12722d48ac80Sdegroote 			    (void *)&sc->sc_statep_net.s)) == NULL) {
12732d48ac80Sdegroote 				splx(s);
12742d48ac80Sdegroote 				return (ENOMEM);
12752d48ac80Sdegroote 			}
12762d48ac80Sdegroote 		}
12772d48ac80Sdegroote 		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
12782d48ac80Sdegroote 
12792d48ac80Sdegroote 		switch (newaction) {
12802d48ac80Sdegroote 		case PFSYNC_ACT_UPD_C:
12812d48ac80Sdegroote 			if (i != 255) {
12822d48ac80Sdegroote 				up = (void *)((char *)h_net +
12832d48ac80Sdegroote 				    PFSYNC_HDRLEN + (i * sizeof(*up)));
12842d48ac80Sdegroote 				up->updates++;
12852d48ac80Sdegroote 			} else {
12862d48ac80Sdegroote 				h_net->count++;
12872d48ac80Sdegroote 				sc->sc_mbuf_net->m_pkthdr.len =
12882d48ac80Sdegroote 				    sc->sc_mbuf_net->m_len += sizeof(*up);
12892d48ac80Sdegroote 				up = sc->sc_statep_net.u++;
12902d48ac80Sdegroote 
12912d48ac80Sdegroote 				memset(up, 0, sizeof(*up));
12922d48ac80Sdegroote 				memcpy(up->id, &st->id, sizeof(up->id));
12932d48ac80Sdegroote 				up->creatorid = st->creatorid;
12942d48ac80Sdegroote 			}
12952d48ac80Sdegroote 			up->timeout = st->timeout;
12962d48ac80Sdegroote 			up->expire = sp->expire;
12972d48ac80Sdegroote 			up->src = sp->src;
12982d48ac80Sdegroote 			up->dst = sp->dst;
12992d48ac80Sdegroote 			break;
13002d48ac80Sdegroote 		case PFSYNC_ACT_DEL_C:
13012d48ac80Sdegroote 			sc->sc_mbuf_net->m_pkthdr.len =
13022d48ac80Sdegroote 			    sc->sc_mbuf_net->m_len += sizeof(*dp);
13032d48ac80Sdegroote 			dp = sc->sc_statep_net.d++;
13042d48ac80Sdegroote 			h_net->count++;
13052d48ac80Sdegroote 
13062d48ac80Sdegroote 			memset(dp, 0, sizeof(*dp));
13072d48ac80Sdegroote 			memcpy(dp->id, &st->id, sizeof(dp->id));
13082d48ac80Sdegroote 			dp->creatorid = st->creatorid;
13092d48ac80Sdegroote 			break;
13102d48ac80Sdegroote 		}
13112d48ac80Sdegroote 	}
13122d48ac80Sdegroote 
13132d48ac80Sdegroote 	if (h->count == sc->sc_maxcount ||
13142d48ac80Sdegroote 	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
13152d48ac80Sdegroote 		ret = pfsync_sendout(sc);
13162d48ac80Sdegroote 
13172d48ac80Sdegroote 	splx(s);
13182d48ac80Sdegroote 	return (ret);
13192d48ac80Sdegroote }
13202d48ac80Sdegroote 
13212d48ac80Sdegroote /* This must be called in splnet() */
13222d48ac80Sdegroote int
pfsync_request_update(struct pfsync_state_upd * up,struct in_addr * src)13232d48ac80Sdegroote pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
13242d48ac80Sdegroote {
13252d48ac80Sdegroote 	struct pfsync_header *h;
13262d48ac80Sdegroote 	struct pfsync_softc *sc = pfsyncif;
13272d48ac80Sdegroote 	struct pfsync_state_upd_req *rup;
13282d48ac80Sdegroote 	int ret = 0;
13292d48ac80Sdegroote 
13302d48ac80Sdegroote 	if (sc == NULL)
13312d48ac80Sdegroote 		return (0);
13322d48ac80Sdegroote 
13332d48ac80Sdegroote 	if (sc->sc_mbuf == NULL) {
13342d48ac80Sdegroote 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
13352d48ac80Sdegroote 		    (void *)&sc->sc_statep.s)) == NULL)
13362d48ac80Sdegroote 			return (ENOMEM);
13372d48ac80Sdegroote 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
13382d48ac80Sdegroote 	} else {
13392d48ac80Sdegroote 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
13402d48ac80Sdegroote 		if (h->action != PFSYNC_ACT_UREQ) {
13412d48ac80Sdegroote 			pfsync_sendout(sc);
13422d48ac80Sdegroote 			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
13432d48ac80Sdegroote 			    (void *)&sc->sc_statep.s)) == NULL)
13442d48ac80Sdegroote 				return (ENOMEM);
13452d48ac80Sdegroote 			h = mtod(sc->sc_mbuf, struct pfsync_header *);
13462d48ac80Sdegroote 		}
13472d48ac80Sdegroote 	}
13482d48ac80Sdegroote 
13492d48ac80Sdegroote 	if (src != NULL)
13502d48ac80Sdegroote 		sc->sc_sendaddr = *src;
13512d48ac80Sdegroote 	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
13522d48ac80Sdegroote 	h->count++;
13532d48ac80Sdegroote 	rup = sc->sc_statep.r++;
13542d48ac80Sdegroote 	memset(rup, 0, sizeof(*rup));
13552d48ac80Sdegroote 	if (up != NULL) {
13562d48ac80Sdegroote 		memcpy(rup->id, up->id, sizeof(rup->id));
13572d48ac80Sdegroote 		rup->creatorid = up->creatorid;
13582d48ac80Sdegroote 	}
13592d48ac80Sdegroote 
13602d48ac80Sdegroote 	if (h->count == sc->sc_maxcount)
13612d48ac80Sdegroote 		ret = pfsync_sendout(sc);
13622d48ac80Sdegroote 
13632d48ac80Sdegroote 	return (ret);
13642d48ac80Sdegroote }
13652d48ac80Sdegroote 
13662d48ac80Sdegroote int
pfsync_clear_states(u_int32_t creatorid,char * ifname)13672d48ac80Sdegroote pfsync_clear_states(u_int32_t creatorid, char *ifname)
13682d48ac80Sdegroote {
13692d48ac80Sdegroote 	struct pfsync_softc *sc = pfsyncif;
13702d48ac80Sdegroote 	struct pfsync_state_clr *cp;
13712d48ac80Sdegroote 	int s, ret;
13722d48ac80Sdegroote 
13732d48ac80Sdegroote 	if (sc == NULL)
13742d48ac80Sdegroote 		return (0);
13752d48ac80Sdegroote 
13762d48ac80Sdegroote 	s = splnet();
13772d48ac80Sdegroote 	if (sc->sc_mbuf != NULL)
13782d48ac80Sdegroote 		pfsync_sendout(sc);
13792d48ac80Sdegroote 	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
13802d48ac80Sdegroote 	    (void *)&sc->sc_statep.c)) == NULL) {
13812d48ac80Sdegroote 		splx(s);
13822d48ac80Sdegroote 		return (ENOMEM);
13832d48ac80Sdegroote 	}
13842d48ac80Sdegroote 	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
13852d48ac80Sdegroote 	cp = sc->sc_statep.c;
13862d48ac80Sdegroote 	cp->creatorid = creatorid;
13872d48ac80Sdegroote 	if (ifname != NULL)
13882d48ac80Sdegroote 		strlcpy(cp->ifname, ifname, IFNAMSIZ);
13892d48ac80Sdegroote 
13902d48ac80Sdegroote 	ret = (pfsync_sendout(sc));
13912d48ac80Sdegroote 	splx(s);
13922d48ac80Sdegroote 	return (ret);
13932d48ac80Sdegroote }
13942d48ac80Sdegroote 
13952d48ac80Sdegroote void
pfsync_timeout(void * v)13962d48ac80Sdegroote pfsync_timeout(void *v)
13972d48ac80Sdegroote {
13982d48ac80Sdegroote 	struct pfsync_softc *sc = v;
13992d48ac80Sdegroote 	int s;
14002d48ac80Sdegroote 
14012d48ac80Sdegroote 	s = splnet();
14022d48ac80Sdegroote 	pfsync_sendout(sc);
14032d48ac80Sdegroote 	splx(s);
14042d48ac80Sdegroote }
14052d48ac80Sdegroote 
14062d48ac80Sdegroote void
pfsync_tdb_timeout(void * v)14072d48ac80Sdegroote pfsync_tdb_timeout(void *v)
14082d48ac80Sdegroote {
14092d48ac80Sdegroote 	struct pfsync_softc *sc = v;
14102d48ac80Sdegroote 	int s;
14112d48ac80Sdegroote 
14122d48ac80Sdegroote 	s = splnet();
14132d48ac80Sdegroote 	pfsync_tdb_sendout(sc);
14142d48ac80Sdegroote 	splx(s);
14152d48ac80Sdegroote }
14162d48ac80Sdegroote 
14172d48ac80Sdegroote /* This must be called in splnet() */
14182d48ac80Sdegroote void
pfsync_send_bus(struct pfsync_softc * sc,u_int8_t status)14192d48ac80Sdegroote pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
14202d48ac80Sdegroote {
14212d48ac80Sdegroote 	struct pfsync_state_bus *bus;
14222d48ac80Sdegroote 
14232d48ac80Sdegroote 	if (sc->sc_mbuf != NULL)
14242d48ac80Sdegroote 		pfsync_sendout(sc);
14252d48ac80Sdegroote 
14262d48ac80Sdegroote 	if (pfsync_sync_ok &&
14272d48ac80Sdegroote 	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
14282d48ac80Sdegroote 	    (void *)&sc->sc_statep.b)) != NULL) {
14292d48ac80Sdegroote 		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
14302d48ac80Sdegroote 		bus = sc->sc_statep.b;
14312d48ac80Sdegroote 		bus->creatorid = pf_status.hostid;
14322d48ac80Sdegroote 		bus->status = status;
14332d48ac80Sdegroote 		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
14342d48ac80Sdegroote 		pfsync_sendout(sc);
14352d48ac80Sdegroote 	}
14362d48ac80Sdegroote }
14372d48ac80Sdegroote 
14382d48ac80Sdegroote void
pfsync_bulk_update(void * v)14392d48ac80Sdegroote pfsync_bulk_update(void *v)
14402d48ac80Sdegroote {
14412d48ac80Sdegroote 	struct pfsync_softc *sc = v;
14422d48ac80Sdegroote 	int s, i = 0;
14432d48ac80Sdegroote 	struct pf_state *state;
14442d48ac80Sdegroote 
14452d48ac80Sdegroote 	s = splnet();
14462d48ac80Sdegroote 	if (sc->sc_mbuf != NULL)
14472d48ac80Sdegroote 		pfsync_sendout(sc);
14482d48ac80Sdegroote 
14492d48ac80Sdegroote 	/*
14502d48ac80Sdegroote 	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
14512d48ac80Sdegroote 	 * been sent since the latest request was made.
14522d48ac80Sdegroote 	 */
14532d48ac80Sdegroote 	state = sc->sc_bulk_send_next;
14542d48ac80Sdegroote 	if (state)
14552d48ac80Sdegroote 		do {
14562d48ac80Sdegroote 			/* send state update if syncable and not already sent */
14572d48ac80Sdegroote 			if (!state->sync_flags
14582d48ac80Sdegroote 			    && state->timeout < PFTM_MAX
14592d48ac80Sdegroote 			    && state->pfsync_time <= sc->sc_ureq_received) {
14602d48ac80Sdegroote 				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
14612d48ac80Sdegroote 				i++;
14622d48ac80Sdegroote 			}
14632d48ac80Sdegroote 
14642d48ac80Sdegroote 			/* figure next state to send */
14652d48ac80Sdegroote 			state = TAILQ_NEXT(state, entry_list);
14662d48ac80Sdegroote 
14672d48ac80Sdegroote 			/* wrap to start of list if we hit the end */
14682d48ac80Sdegroote 			if (!state)
14692d48ac80Sdegroote 				state = TAILQ_FIRST(&state_list);
14702d48ac80Sdegroote 		} while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
14712d48ac80Sdegroote 		    state != sc->sc_bulk_terminator);
14722d48ac80Sdegroote 
14732d48ac80Sdegroote 	if (!state || state == sc->sc_bulk_terminator) {
14742d48ac80Sdegroote 		/* we're done */
14752d48ac80Sdegroote 		pfsync_send_bus(sc, PFSYNC_BUS_END);
14762d48ac80Sdegroote 		sc->sc_ureq_received = 0;
14772d48ac80Sdegroote 		sc->sc_bulk_send_next = NULL;
14782d48ac80Sdegroote 		sc->sc_bulk_terminator = NULL;
14792d48ac80Sdegroote 		callout_stop(&sc->sc_bulk_tmo);
14802d48ac80Sdegroote 		if (pf_status.debug >= PF_DEBUG_MISC)
14812d48ac80Sdegroote 			printf("pfsync: bulk update complete\n");
14822d48ac80Sdegroote 	} else {
14832d48ac80Sdegroote 		/* look again for more in a bit */
14842d48ac80Sdegroote 		callout_schedule(&sc->sc_bulk_tmo, 1);
14852d48ac80Sdegroote 		sc->sc_bulk_send_next = state;
14862d48ac80Sdegroote 	}
14872d48ac80Sdegroote 	if (sc->sc_mbuf != NULL)
14882d48ac80Sdegroote 		pfsync_sendout(sc);
14892d48ac80Sdegroote 	splx(s);
14902d48ac80Sdegroote }
14912d48ac80Sdegroote 
14922d48ac80Sdegroote void
pfsync_bulkfail(void * v)14932d48ac80Sdegroote pfsync_bulkfail(void *v)
14942d48ac80Sdegroote {
14952d48ac80Sdegroote 	struct pfsync_softc *sc = v;
14962d48ac80Sdegroote 	int s, error;
14972d48ac80Sdegroote 
14982d48ac80Sdegroote 	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
14992d48ac80Sdegroote 		/* Try again in a bit */
15002d48ac80Sdegroote 		callout_schedule(&sc->sc_bulkfail_tmo, 5 * hz);
15012d48ac80Sdegroote 		s = splnet();
15022d48ac80Sdegroote 		error = pfsync_request_update(NULL, NULL);
15032d48ac80Sdegroote 		if (error == ENOMEM) {
15042d48ac80Sdegroote 			if (pf_status.debug >= PF_DEBUG_MISC)
15052d48ac80Sdegroote 				printf("pfsync: cannot allocate mbufs for "
15062d48ac80Sdegroote 				    "bulk update\n");
15072d48ac80Sdegroote 		} else
15082d48ac80Sdegroote 			pfsync_sendout(sc);
15092d48ac80Sdegroote 		splx(s);
15102d48ac80Sdegroote 	} else {
15112d48ac80Sdegroote 		/* Pretend like the transfer was ok */
15122d48ac80Sdegroote 		sc->sc_ureq_sent = 0;
15132d48ac80Sdegroote 		sc->sc_bulk_tries = 0;
15142d48ac80Sdegroote #if NCARP > 0
15152d48ac80Sdegroote 		if (!pfsync_sync_ok)
15162d48ac80Sdegroote 			carp_suppress_preempt --;
15172d48ac80Sdegroote #endif
15182d48ac80Sdegroote 		pfsync_sync_ok = 1;
15192d48ac80Sdegroote 		if (pf_status.debug >= PF_DEBUG_MISC)
15202d48ac80Sdegroote 			printf("pfsync: failed to receive "
15212d48ac80Sdegroote 			    "bulk update status\n");
15222d48ac80Sdegroote 		callout_stop(&sc->sc_bulkfail_tmo);
15232d48ac80Sdegroote 	}
15242d48ac80Sdegroote }
15252d48ac80Sdegroote 
15262d48ac80Sdegroote /* This must be called in splnet() */
15272d48ac80Sdegroote int
pfsync_sendout(struct pfsync_softc * sc)15282d48ac80Sdegroote pfsync_sendout(struct pfsync_softc *sc)
15292d48ac80Sdegroote {
15302d48ac80Sdegroote 	struct ifnet *ifp = &sc->sc_if;
15312d48ac80Sdegroote 	struct mbuf *m;
15322d48ac80Sdegroote 
15332d48ac80Sdegroote 	callout_stop(&sc->sc_tmo);
15342d48ac80Sdegroote 
15352d48ac80Sdegroote 	if (sc->sc_mbuf == NULL)
15362d48ac80Sdegroote 		return (0);
15372d48ac80Sdegroote 	m = sc->sc_mbuf;
15382d48ac80Sdegroote 	sc->sc_mbuf = NULL;
15392d48ac80Sdegroote 	sc->sc_statep.s = NULL;
15402d48ac80Sdegroote 
15418517c9d1Smsaitoh 	bpf_mtap(ifp, m, BPF_D_OUT);
15422d48ac80Sdegroote 
15432d48ac80Sdegroote 	if (sc->sc_mbuf_net) {
15442d48ac80Sdegroote 		m_freem(m);
15452d48ac80Sdegroote 		m = sc->sc_mbuf_net;
15462d48ac80Sdegroote 		sc->sc_mbuf_net = NULL;
15472d48ac80Sdegroote 		sc->sc_statep_net.s = NULL;
15482d48ac80Sdegroote 	}
15492d48ac80Sdegroote 
15502d48ac80Sdegroote 	return pfsync_sendout_mbuf(sc, m);
15512d48ac80Sdegroote }
15522d48ac80Sdegroote 
15532d48ac80Sdegroote int
pfsync_tdb_sendout(struct pfsync_softc * sc)15542d48ac80Sdegroote pfsync_tdb_sendout(struct pfsync_softc *sc)
15552d48ac80Sdegroote {
15562d48ac80Sdegroote 	struct ifnet *ifp = &sc->sc_if;
15572d48ac80Sdegroote 	struct mbuf *m;
15582d48ac80Sdegroote 
15592d48ac80Sdegroote 	callout_stop(&sc->sc_tdb_tmo);
15602d48ac80Sdegroote 
15612d48ac80Sdegroote 	if (sc->sc_mbuf_tdb == NULL)
15622d48ac80Sdegroote 		return (0);
15632d48ac80Sdegroote 	m = sc->sc_mbuf_tdb;
15642d48ac80Sdegroote 	sc->sc_mbuf_tdb = NULL;
15652d48ac80Sdegroote 	sc->sc_statep_tdb.t = NULL;
15662d48ac80Sdegroote 
1567cd2cf070Smsaitoh 	bpf_mtap(ifp, m, BPF_D_OUT);
15682d48ac80Sdegroote 
15692d48ac80Sdegroote 	return pfsync_sendout_mbuf(sc, m);
15702d48ac80Sdegroote }
15712d48ac80Sdegroote 
15722d48ac80Sdegroote int
pfsync_sendout_mbuf(struct pfsync_softc * sc,struct mbuf * m)15732d48ac80Sdegroote pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
15742d48ac80Sdegroote {
15752d48ac80Sdegroote 	struct sockaddr sa;
15762d48ac80Sdegroote 	struct ip *ip;
15772d48ac80Sdegroote 
15782d48ac80Sdegroote 	if (sc->sc_sync_ifp ||
15792d48ac80Sdegroote 	    sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
15802d48ac80Sdegroote 		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
15812d48ac80Sdegroote 		if (m == NULL) {
15822d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_ONOMEM);
15832d48ac80Sdegroote 			return (0);
15842d48ac80Sdegroote 		}
15852d48ac80Sdegroote 		ip = mtod(m, struct ip *);
15862d48ac80Sdegroote 		ip->ip_v = IPVERSION;
15872d48ac80Sdegroote 		ip->ip_hl = sizeof(*ip) >> 2;
15882d48ac80Sdegroote 		ip->ip_tos = IPTOS_LOWDELAY;
15892d48ac80Sdegroote 		ip->ip_len = htons(m->m_pkthdr.len);
1590*4196a59bSchristos 		ip->ip_id = ip_randomid();
15912d48ac80Sdegroote 		ip->ip_off = htons(IP_DF);
15922d48ac80Sdegroote 		ip->ip_ttl = PFSYNC_DFLTTL;
15932d48ac80Sdegroote 		ip->ip_p = IPPROTO_PFSYNC;
15942d48ac80Sdegroote 		ip->ip_sum = 0;
15952d48ac80Sdegroote 
15962d48ac80Sdegroote 		memset(&sa, 0, sizeof(sa));
15972d48ac80Sdegroote 		ip->ip_src.s_addr = INADDR_ANY;
15982d48ac80Sdegroote 
15992d48ac80Sdegroote 		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
16002d48ac80Sdegroote 			m->m_flags |= M_MCAST;
16012d48ac80Sdegroote 		ip->ip_dst = sc->sc_sendaddr;
16022d48ac80Sdegroote 		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
16032d48ac80Sdegroote 
16042d48ac80Sdegroote 		PFSYNC_STATINC(PFSYNC_STAT_OPACKETS);
16052d48ac80Sdegroote 
16062d48ac80Sdegroote 		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) {
16072d48ac80Sdegroote 			PFSYNC_STATINC(PFSYNC_STAT_OERRORS);
16082d48ac80Sdegroote 		}
16092d48ac80Sdegroote 	} else
16102d48ac80Sdegroote 		m_freem(m);
16112d48ac80Sdegroote 
16122d48ac80Sdegroote 	return (0);
16132d48ac80Sdegroote }
16142d48ac80Sdegroote 
16152d48ac80Sdegroote static int
sysctl_net_inet_pfsync_stats(SYSCTLFN_ARGS)16162d48ac80Sdegroote sysctl_net_inet_pfsync_stats(SYSCTLFN_ARGS)
16172d48ac80Sdegroote {
16182d48ac80Sdegroote 
16192d48ac80Sdegroote 	return (NETSTAT_SYSCTL(pfsyncstat_percpu, PFSYNC_NSTATS));
16202d48ac80Sdegroote }
16212d48ac80Sdegroote 
16222d48ac80Sdegroote SYSCTL_SETUP(sysctl_net_inet_pfsync_setup, "sysctl net.inet.pfsync subtree setup")
16232d48ac80Sdegroote {
16242d48ac80Sdegroote 
16252d48ac80Sdegroote 	sysctl_createv(clog, 0, NULL, NULL,
16262d48ac80Sdegroote 		       CTLFLAG_PERMANENT,
16272d48ac80Sdegroote 		       CTLTYPE_NODE, "net", NULL,
16282d48ac80Sdegroote 		       NULL, 0, NULL, 0,
16292d48ac80Sdegroote 		       CTL_NET, CTL_EOL);
16302d48ac80Sdegroote 	sysctl_createv(clog, 0, NULL, NULL,
16312d48ac80Sdegroote 		       CTLFLAG_PERMANENT,
16322d48ac80Sdegroote 		       CTLTYPE_NODE, "inet", NULL,
16332d48ac80Sdegroote 		       NULL, 0, NULL, 0,
16342d48ac80Sdegroote 		       CTL_NET, PF_INET, CTL_EOL);
16352d48ac80Sdegroote 	sysctl_createv(clog, 0, NULL, NULL,
16362d48ac80Sdegroote 		       CTLFLAG_PERMANENT,
16372d48ac80Sdegroote 		       CTLTYPE_NODE, "pfsync",
16382d48ac80Sdegroote 		       SYSCTL_DESCR("pfsync related settings"),
16392d48ac80Sdegroote 		       NULL, 0, NULL, 0,
16402d48ac80Sdegroote 		       CTL_NET, PF_INET, IPPROTO_PFSYNC, CTL_EOL);
16412d48ac80Sdegroote 	sysctl_createv(clog, 0, NULL, NULL,
16422d48ac80Sdegroote 		       CTLFLAG_PERMANENT|CTLFLAG_READONLY,
16432d48ac80Sdegroote 		       CTLTYPE_STRUCT, "stats",
16442d48ac80Sdegroote 			   SYSCTL_DESCR("pfsync statistics"),
16452d48ac80Sdegroote 		       sysctl_net_inet_pfsync_stats, 0, NULL, 0,
16462d48ac80Sdegroote 		       CTL_NET, PF_INET, IPPROTO_PFSYNC,
16472d48ac80Sdegroote 	       CTL_CREATE, CTL_EOL);
16482d48ac80Sdegroote }
1649