xref: /dflybsd-src/sys/net/pf/if_pfsync.c (revision b272101acc636ac635f83d03265ef6a44a3ba51a)
102742ec6SJoerg Sonnenberger /*
202742ec6SJoerg Sonnenberger  * Copyright (c) 2002 Michael Shalayeff
302742ec6SJoerg Sonnenberger  * All rights reserved.
402742ec6SJoerg Sonnenberger  *
502742ec6SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
602742ec6SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
702742ec6SJoerg Sonnenberger  * are met:
802742ec6SJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
902742ec6SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
1002742ec6SJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
1102742ec6SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
1202742ec6SJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
1302742ec6SJoerg Sonnenberger  *
1402742ec6SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1502742ec6SJoerg Sonnenberger  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1602742ec6SJoerg Sonnenberger  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1702742ec6SJoerg Sonnenberger  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
1802742ec6SJoerg Sonnenberger  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1902742ec6SJoerg Sonnenberger  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2002742ec6SJoerg Sonnenberger  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2102742ec6SJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2202742ec6SJoerg Sonnenberger  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2302742ec6SJoerg Sonnenberger  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2402742ec6SJoerg Sonnenberger  * THE POSSIBILITY OF SUCH DAMAGE.
253a0038bfSMatthew Dillon  *
263a0038bfSMatthew Dillon  * $OpenBSD: if_pfsync.c,v 1.98 2008/06/29 08:42:15 mcbride Exp $
2702742ec6SJoerg Sonnenberger  */
2802742ec6SJoerg Sonnenberger 
29c3c8c553SJan Lentfer #include "opt_inet.h"
30c3c8c553SJan Lentfer #include "opt_inet6.h"
315992bdfcSSepherosa Ziehau #include "opt_carp.h"
322b00f643SSascha Wildner #include "use_bpf.h"
3302742ec6SJoerg Sonnenberger 
3402742ec6SJoerg Sonnenberger #include <sys/param.h>
35c3c8c553SJan Lentfer #include <sys/endian.h>
3602742ec6SJoerg Sonnenberger #include <sys/proc.h>
37*2b3f93eaSMatthew Dillon #include <sys/caps.h>
3802742ec6SJoerg Sonnenberger #include <sys/systm.h>
3902742ec6SJoerg Sonnenberger #include <sys/time.h>
4002742ec6SJoerg Sonnenberger #include <sys/mbuf.h>
4102742ec6SJoerg Sonnenberger #include <sys/socket.h>
4202742ec6SJoerg Sonnenberger #include <sys/kernel.h>
43c3c8c553SJan Lentfer #include <sys/malloc.h>
44c3c8c553SJan Lentfer #include <sys/module.h>
45ef15d469SSepherosa Ziehau #include <sys/msgport2.h>
46c3c8c553SJan Lentfer #include <sys/sockio.h>
47c3c8c553SJan Lentfer #include <sys/thread2.h>
48c3c8c553SJan Lentfer 
49c3c8c553SJan Lentfer #include <machine/inttypes.h>
5002742ec6SJoerg Sonnenberger 
5102742ec6SJoerg Sonnenberger #include <net/if.h>
5202742ec6SJoerg Sonnenberger #include <net/if_types.h>
53ef9870ecSSepherosa Ziehau #include <net/ifq_var.h>
5402742ec6SJoerg Sonnenberger #include <net/route.h>
5502742ec6SJoerg Sonnenberger #include <net/bpf.h>
56ef15d469SSepherosa Ziehau #include <net/netisr2.h>
57ef15d469SSepherosa Ziehau #include <net/netmsg2.h>
5870224baaSJan Lentfer #include <netinet/in.h>
5970224baaSJan Lentfer #include <netinet/if_ether.h>
60315a7da3SJan Lentfer #include <netinet/ip_carp.h>
6170224baaSJan Lentfer #include <netinet/tcp.h>
6270224baaSJan Lentfer #include <netinet/tcp_seq.h>
6302742ec6SJoerg Sonnenberger 
6402742ec6SJoerg Sonnenberger #ifdef	INET
6502742ec6SJoerg Sonnenberger #include <netinet/in_systm.h>
6602742ec6SJoerg Sonnenberger #include <netinet/in_var.h>
6702742ec6SJoerg Sonnenberger #include <netinet/ip.h>
6802742ec6SJoerg Sonnenberger #include <netinet/ip_var.h>
6902742ec6SJoerg Sonnenberger #endif
7002742ec6SJoerg Sonnenberger 
7102742ec6SJoerg Sonnenberger #ifdef INET6
7202742ec6SJoerg Sonnenberger #include <netinet6/nd6.h>
7302742ec6SJoerg Sonnenberger #endif /* INET6 */
7402742ec6SJoerg Sonnenberger 
75c3c8c553SJan Lentfer #include <net/pf/pfvar.h>
76c3c8c553SJan Lentfer #include <net/pf/if_pfsync.h>
7702742ec6SJoerg Sonnenberger 
78c3c8c553SJan Lentfer #define	PFSYNCNAME	"pfsync"
7902742ec6SJoerg Sonnenberger 
8002742ec6SJoerg Sonnenberger #define PFSYNC_MINMTU	\
8102742ec6SJoerg Sonnenberger     (sizeof(struct pfsync_header) + sizeof(struct pf_state))
8202742ec6SJoerg Sonnenberger 
8302742ec6SJoerg Sonnenberger #ifdef PFSYNCDEBUG
84c3c8c553SJan Lentfer #define DPRINTF(x)    do { if (pfsyncdebug) kprintf x ; } while (0)
8502742ec6SJoerg Sonnenberger int pfsyncdebug;
8602742ec6SJoerg Sonnenberger #else
8702742ec6SJoerg Sonnenberger #define DPRINTF(x)
8802742ec6SJoerg Sonnenberger #endif
8902742ec6SJoerg Sonnenberger 
9070224baaSJan Lentfer struct pfsync_softc	*pfsyncif = NULL;
9102742ec6SJoerg Sonnenberger struct pfsyncstats	 pfsyncstats;
9202742ec6SJoerg Sonnenberger 
9370224baaSJan Lentfer void	pfsyncattach(int);
94a7e9152eSSepherosa Ziehau static int	pfsync_clone_destroy(struct ifnet *);
95bb54c3a2SAaron LI static int	pfsync_clone_create(struct if_clone *, int, caddr_t, caddr_t);
9602742ec6SJoerg Sonnenberger void	pfsync_setmtu(struct pfsync_softc *, int);
9770224baaSJan Lentfer int	pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
9870224baaSJan Lentfer 	    struct pf_state_peer *);
9902742ec6SJoerg Sonnenberger int	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
10002742ec6SJoerg Sonnenberger 	    struct rtentry *);
101c3c8c553SJan Lentfer int	pfsyncioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
102f0a26983SSepherosa Ziehau void	pfsyncstart(struct ifnet *, struct ifaltq_subque *);
10302742ec6SJoerg Sonnenberger 
10402742ec6SJoerg Sonnenberger struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
10502742ec6SJoerg Sonnenberger int	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
10602742ec6SJoerg Sonnenberger int	pfsync_sendout(struct pfsync_softc *);
10770224baaSJan Lentfer int	pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
10802742ec6SJoerg Sonnenberger void	pfsync_timeout(void *);
10902742ec6SJoerg Sonnenberger void	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
11002742ec6SJoerg Sonnenberger void	pfsync_bulk_update(void *);
11102742ec6SJoerg Sonnenberger void	pfsync_bulkfail(void *);
11202742ec6SJoerg Sonnenberger 
113ef15d469SSepherosa Ziehau static struct in_multi *pfsync_in_addmulti(struct ifnet *);
114ef15d469SSepherosa Ziehau static void pfsync_in_delmulti(struct in_multi *);
115ef15d469SSepherosa Ziehau 
116c3c8c553SJan Lentfer static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
117c3c8c553SJan Lentfer static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
118c3c8c553SJan Lentfer 
11970224baaSJan Lentfer int	pfsync_sync_ok;
12002742ec6SJoerg Sonnenberger 
12170224baaSJan Lentfer struct if_clone	pfsync_cloner =
122c3c8c553SJan Lentfer     IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy, 1 ,1);
12370224baaSJan Lentfer 
124bb54c3a2SAaron LI 
12570224baaSJan Lentfer void
pfsyncattach(int npfsync)12670224baaSJan Lentfer pfsyncattach(int npfsync)
12702742ec6SJoerg Sonnenberger {
12870224baaSJan Lentfer 	if_clone_attach(&pfsync_cloner);
12902742ec6SJoerg Sonnenberger }
130bb54c3a2SAaron LI 
131c3c8c553SJan Lentfer static int
pfsync_clone_create(struct if_clone * ifc,int unit,caddr_t params __unused,caddr_t data __unused)132bb54c3a2SAaron LI pfsync_clone_create(struct if_clone *ifc, int unit,
133bb54c3a2SAaron LI 		    caddr_t params __unused, caddr_t data __unused)
13402742ec6SJoerg Sonnenberger {
135c3c8c553SJan Lentfer 	struct pfsync_softc *sc;
13602742ec6SJoerg Sonnenberger 	struct ifnet *ifp;
13702742ec6SJoerg Sonnenberger 
1382a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
1392a7a2b1cSJan Lentfer 
14002742ec6SJoerg Sonnenberger 	pfsync_sync_ok = 1;
141c8f430baSAaron LI 
142c8f430baSAaron LI 	sc = kmalloc(sizeof(*sc), M_PFSYNC, M_WAITOK | M_ZERO);
143c3c8c553SJan Lentfer 	sc->sc_mbuf = NULL;
144c3c8c553SJan Lentfer 	sc->sc_mbuf_net = NULL;
145c3c8c553SJan Lentfer 	sc->sc_mbuf_tdb = NULL;
146c3c8c553SJan Lentfer 	sc->sc_statep.s = NULL;
147c3c8c553SJan Lentfer 	sc->sc_statep_net.s = NULL;
148c3c8c553SJan Lentfer 	sc->sc_statep_tdb.t = NULL;
149c3c8c553SJan Lentfer 	sc->sc_maxupdates = 128;
150c3c8c553SJan Lentfer 	sc->sc_sync_peer.s_addr =htonl(INADDR_PFSYNC_GROUP);
151c3c8c553SJan Lentfer 	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
152c3c8c553SJan Lentfer 	sc->sc_ureq_received = 0;
153c3c8c553SJan Lentfer 	sc->sc_ureq_sent = 0;
154c3c8c553SJan Lentfer 	sc->sc_bulk_send_next = NULL;
155c3c8c553SJan Lentfer 	sc->sc_bulk_terminator = NULL;
1563a0038bfSMatthew Dillon 	sc->sc_bulk_send_cpu = 0;
1573a0038bfSMatthew Dillon 	sc->sc_bulk_terminator_cpu = 0;
158ed1f0be2SJan Lentfer 	sc->sc_imo.imo_max_memberships = IP_MAX_MEMBERSHIPS;
1592a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
160c8f430baSAaron LI 
161c3c8c553SJan Lentfer 	ifp = &sc->sc_if;
162c3c8c553SJan Lentfer 	if_initname(ifp, ifc->ifc_name, unit);
16302742ec6SJoerg Sonnenberger 	ifp->if_ioctl = pfsyncioctl;
16402742ec6SJoerg Sonnenberger 	ifp->if_output = pfsyncoutput;
16502742ec6SJoerg Sonnenberger 	ifp->if_start = pfsyncstart;
16602742ec6SJoerg Sonnenberger 	ifp->if_type = IFT_PFSYNC;
167ef9870ecSSepherosa Ziehau 	ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
16802742ec6SJoerg Sonnenberger 	ifp->if_hdrlen = PFSYNC_HDRLEN;
169c3c8c553SJan Lentfer 	ifp->if_baudrate = IF_Mbps(100);
170c3c8c553SJan Lentfer 	ifp->if_softc = sc;
171c8f430baSAaron LI 
172c3c8c553SJan Lentfer 	pfsync_setmtu(sc, MCLBYTES);
173c3c8c553SJan Lentfer 	callout_init(&sc->sc_tmo);
174ed1f0be2SJan Lentfer 	/* callout_init(&sc->sc_tdb_tmo); XXX we don't support tdb (yet) */
175c3c8c553SJan Lentfer 	callout_init(&sc->sc_bulk_tmo);
176c3c8c553SJan Lentfer 	callout_init(&sc->sc_bulkfail_tmo);
177c8f430baSAaron LI 
178ed1f0be2SJan Lentfer 	if_attach(ifp, NULL);
1792b00f643SSascha Wildner #if NBPF > 0
180c8f430baSAaron LI 	bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
181c8f430baSAaron LI #endif
18202742ec6SJoerg Sonnenberger 
1832b00f643SSascha Wildner #ifdef CARP
18470224baaSJan Lentfer 	if_addgroup(ifp, "carp");
18570224baaSJan Lentfer #endif
186ed1f0be2SJan Lentfer 
1872a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
188c8f430baSAaron LI 	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
1892a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
190c8f430baSAaron LI 
19170224baaSJan Lentfer 	return (0);
19270224baaSJan Lentfer }
19370224baaSJan Lentfer 
194a7e9152eSSepherosa Ziehau static int
pfsync_clone_destroy(struct ifnet * ifp)19570224baaSJan Lentfer pfsync_clone_destroy(struct ifnet *ifp)
19670224baaSJan Lentfer {
197c4705c47SSepherosa Ziehau 	struct netmsg_base msg;
198c4705c47SSepherosa Ziehau 
1992a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
2002a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
201ed1f0be2SJan Lentfer 
202ed1f0be2SJan Lentfer 	struct pfsync_softc *sc = ifp->if_softc;
203ed1f0be2SJan Lentfer 	callout_stop(&sc->sc_tmo);
204ed1f0be2SJan Lentfer 	/* callout_stop(&sc->sc_tdb_tmo); XXX we don't support tdb (yet) */
205ed1f0be2SJan Lentfer 	callout_stop(&sc->sc_bulk_tmo);
206ed1f0be2SJan Lentfer 	callout_stop(&sc->sc_bulkfail_tmo);
2072b00f643SSascha Wildner #ifdef CARP
208ed1f0be2SJan Lentfer 	if (!pfsync_sync_ok)
209ed1f0be2SJan Lentfer 		carp_group_demote_adj(&sc->sc_if, -1);
210ed1f0be2SJan Lentfer #endif
211c4705c47SSepherosa Ziehau 
212c4705c47SSepherosa Ziehau 	/* Unpend async sendouts. */
213c4705c47SSepherosa Ziehau 	netmsg_init(&msg, NULL, &curthread->td_msgport, 0, netmsg_sync_handler);
214c4705c47SSepherosa Ziehau 	netisr_domsg(&msg, 0);
215c4705c47SSepherosa Ziehau 
2162b00f643SSascha Wildner #if NBPF > 0
21770224baaSJan Lentfer 	bpfdetach(ifp);
21870224baaSJan Lentfer #endif
21970224baaSJan Lentfer 	if_detach(ifp);
2202a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
221ed1f0be2SJan Lentfer 	LIST_REMOVE(sc, sc_next);
222ed1f0be2SJan Lentfer 	kfree(sc, M_PFSYNC);
223ed1f0be2SJan Lentfer 	lwkt_reltoken(&pf_token);
224ed1f0be2SJan Lentfer 
225a7e9152eSSepherosa Ziehau 	return 0;
22602742ec6SJoerg Sonnenberger }
22702742ec6SJoerg Sonnenberger 
22802742ec6SJoerg Sonnenberger /*
22902742ec6SJoerg Sonnenberger  * Start output on the pfsync interface.
23002742ec6SJoerg Sonnenberger  */
23102742ec6SJoerg Sonnenberger void
pfsyncstart(struct ifnet * ifp,struct ifaltq_subque * ifsq)232f0a26983SSepherosa Ziehau pfsyncstart(struct ifnet *ifp, struct ifaltq_subque *ifsq)
23302742ec6SJoerg Sonnenberger {
234f0a26983SSepherosa Ziehau 	ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
235f0a26983SSepherosa Ziehau 	ifsq_purge(ifsq);
23602742ec6SJoerg Sonnenberger }
23702742ec6SJoerg Sonnenberger 
23802742ec6SJoerg Sonnenberger int
pfsync_alloc_scrub_memory(struct pfsync_state_peer * s,struct pf_state_peer * d)23970224baaSJan Lentfer pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
24070224baaSJan Lentfer     struct pf_state_peer *d)
24170224baaSJan Lentfer {
24270224baaSJan Lentfer 	if (s->scrub.scrub_flag && d->scrub == NULL) {
2431186cbc0SJan Lentfer 		d->scrub = kmalloc(sizeof(struct pf_state_scrub), M_PFSYNC, M_NOWAIT|M_ZERO);
2441186cbc0SJan Lentfer 
24570224baaSJan Lentfer 		if (d->scrub == NULL)
24670224baaSJan Lentfer 			return (ENOMEM);
24770224baaSJan Lentfer 	}
24870224baaSJan Lentfer 
24970224baaSJan Lentfer 	return (0);
25070224baaSJan Lentfer }
25170224baaSJan Lentfer 
252ed1f0be2SJan Lentfer void
pfsync_state_export(struct pfsync_state * sp,struct pf_state * st)253ed1f0be2SJan Lentfer pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
254ed1f0be2SJan Lentfer {
255ed1f0be2SJan Lentfer 	bzero(sp, sizeof(struct pfsync_state));
256ed1f0be2SJan Lentfer 
257ed1f0be2SJan Lentfer 	/* copy from state key */
258ed1f0be2SJan Lentfer 	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
259ed1f0be2SJan Lentfer 	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
260ed1f0be2SJan Lentfer 	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
261ed1f0be2SJan Lentfer 	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
262ed1f0be2SJan Lentfer 	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
263ed1f0be2SJan Lentfer 	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
264ed1f0be2SJan Lentfer 	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
265ed1f0be2SJan Lentfer 	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
266ed1f0be2SJan Lentfer 	sp->proto = st->key[PF_SK_WIRE]->proto;
267ed1f0be2SJan Lentfer 	sp->af = st->key[PF_SK_WIRE]->af;
268ed1f0be2SJan Lentfer 
269ed1f0be2SJan Lentfer 	/* copy from state */
270ed1f0be2SJan Lentfer 	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
271ed1f0be2SJan Lentfer 	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
272ed1f0be2SJan Lentfer 	sp->creation = htonl(time_second - st->creation);
273ed1f0be2SJan Lentfer 	sp->expire = pf_state_expires(st);
274ed1f0be2SJan Lentfer 	if (sp->expire <= time_second)
275ed1f0be2SJan Lentfer 		sp->expire = htonl(0);
276ed1f0be2SJan Lentfer 	else
277ed1f0be2SJan Lentfer 		sp->expire = htonl(sp->expire - time_second);
278ed1f0be2SJan Lentfer 
279ed1f0be2SJan Lentfer 	sp->direction = st->direction;
280ed1f0be2SJan Lentfer 	sp->log = st->log;
2815f2a38e8SMatthew Dillon 	sp->cpuid = st->cpuid;
2825f2a38e8SMatthew Dillon 	sp->pickup_mode = st->pickup_mode;
283ed1f0be2SJan Lentfer 	sp->timeout = st->timeout;
284ed1f0be2SJan Lentfer 	sp->state_flags = st->state_flags;
285ed1f0be2SJan Lentfer 	if (st->src_node)
286ed1f0be2SJan Lentfer 		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
287ed1f0be2SJan Lentfer 	if (st->nat_src_node)
288ed1f0be2SJan Lentfer 		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
289ed1f0be2SJan Lentfer 
290ed1f0be2SJan Lentfer 	bcopy(&st->id, &sp->id, sizeof(sp->id));
291ed1f0be2SJan Lentfer 	sp->creatorid = st->creatorid;
292ed1f0be2SJan Lentfer 	pf_state_peer_hton(&st->src, &sp->src);
293ed1f0be2SJan Lentfer 	pf_state_peer_hton(&st->dst, &sp->dst);
294ed1f0be2SJan Lentfer 
295ed1f0be2SJan Lentfer 	if (st->rule.ptr == NULL)
296ed1f0be2SJan Lentfer 		sp->rule = htonl(-1);
297ed1f0be2SJan Lentfer 	else
298ed1f0be2SJan Lentfer 		sp->rule = htonl(st->rule.ptr->nr);
299ed1f0be2SJan Lentfer 	if (st->anchor.ptr == NULL)
300ed1f0be2SJan Lentfer 		sp->anchor = htonl(-1);
301ed1f0be2SJan Lentfer 	else
302ed1f0be2SJan Lentfer 		sp->anchor = htonl(st->anchor.ptr->nr);
303ed1f0be2SJan Lentfer 	if (st->nat_rule.ptr == NULL)
304ed1f0be2SJan Lentfer 		sp->nat_rule = htonl(-1);
305ed1f0be2SJan Lentfer 	else
306ed1f0be2SJan Lentfer 		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
307ed1f0be2SJan Lentfer 
308ed1f0be2SJan Lentfer 	pf_state_counter_hton(st->packets[0], sp->packets[0]);
309ed1f0be2SJan Lentfer 	pf_state_counter_hton(st->packets[1], sp->packets[1]);
310ed1f0be2SJan Lentfer 	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
311ed1f0be2SJan Lentfer 	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
312ed1f0be2SJan Lentfer 
313ed1f0be2SJan Lentfer }
314ed1f0be2SJan Lentfer 
31570224baaSJan Lentfer int
pfsync_state_import(struct pfsync_state * sp,u_int8_t flags)316ed1f0be2SJan Lentfer pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
31702742ec6SJoerg Sonnenberger {
31802742ec6SJoerg Sonnenberger 	struct pf_state	*st = NULL;
319ed1f0be2SJan Lentfer 	struct pf_state_key *skw = NULL, *sks = NULL;
32002742ec6SJoerg Sonnenberger 	struct pf_rule *r = NULL;
32102742ec6SJoerg Sonnenberger 	struct pfi_kif	*kif;
322ed1f0be2SJan Lentfer 	int pool_flags;
323ed1f0be2SJan Lentfer 	int error;
32402742ec6SJoerg Sonnenberger 
32502742ec6SJoerg Sonnenberger 	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
326c3c8c553SJan Lentfer 		kprintf("pfsync_insert_net_state: invalid creator id:"
32770224baaSJan Lentfer 		    " %08x\n", ntohl(sp->creatorid));
32802742ec6SJoerg Sonnenberger 		return (EINVAL);
32902742ec6SJoerg Sonnenberger 	}
33002742ec6SJoerg Sonnenberger 
331ed1f0be2SJan Lentfer 	if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
33202742ec6SJoerg Sonnenberger 		if (pf_status.debug >= PF_DEBUG_MISC)
333c3c8c553SJan Lentfer 			kprintf("pfsync_insert_net_state: "
33402742ec6SJoerg Sonnenberger 			    "unknown interface: %s\n", sp->ifname);
335ed1f0be2SJan Lentfer 		if (flags & PFSYNC_SI_IOCTL)
336ed1f0be2SJan Lentfer 			return (EINVAL);
337ed1f0be2SJan Lentfer 		return (0);	/* skip this state */
33802742ec6SJoerg Sonnenberger 	}
33902742ec6SJoerg Sonnenberger 
34002742ec6SJoerg Sonnenberger 	/*
341ed1f0be2SJan Lentfer 	 * If the ruleset checksums match or the state is coming from the ioctl,
342ed1f0be2SJan Lentfer 	 * it's safe to associate the state with the rule of that number.
34302742ec6SJoerg Sonnenberger 	 */
344ed1f0be2SJan Lentfer 	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
345ed1f0be2SJan Lentfer 	    (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
346315a7da3SJan Lentfer 	    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
34770224baaSJan Lentfer 		r = pf_main_ruleset.rules[
34870224baaSJan Lentfer 		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
34970224baaSJan Lentfer 	else
35002742ec6SJoerg Sonnenberger 		r = &pf_default_rule;
35102742ec6SJoerg Sonnenberger 
352ed1f0be2SJan Lentfer 	if ((r->max_states && r->states_cur >= r->max_states))
353ed1f0be2SJan Lentfer 		goto cleanup;
35402742ec6SJoerg Sonnenberger 
355ed1f0be2SJan Lentfer 	if (flags & PFSYNC_SI_IOCTL)
3561186cbc0SJan Lentfer 		pool_flags = M_WAITOK | M_NULLOK | M_ZERO;
357ed1f0be2SJan Lentfer 	else
3581186cbc0SJan Lentfer 		pool_flags = M_WAITOK | M_ZERO;
359ed1f0be2SJan Lentfer 
3601186cbc0SJan Lentfer 	if ((st = kmalloc(sizeof(struct pf_state), M_PFSYNC, pool_flags)) == NULL)
361ed1f0be2SJan Lentfer 		goto cleanup;
36232772c96SMatthew Dillon 	lockinit(&st->lk, "pfstlk", 0, 0);
363ed1f0be2SJan Lentfer 
364ed1f0be2SJan Lentfer 	if ((skw = pf_alloc_state_key(pool_flags)) == NULL)
365ed1f0be2SJan Lentfer 		goto cleanup;
366ed1f0be2SJan Lentfer 
367ed1f0be2SJan Lentfer 	if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0],
368ed1f0be2SJan Lentfer 	    &sp->key[PF_SK_STACK].addr[0], sp->af) ||
369ed1f0be2SJan Lentfer 	    PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1],
370ed1f0be2SJan Lentfer 	    &sp->key[PF_SK_STACK].addr[1], sp->af) ||
371ed1f0be2SJan Lentfer 	    sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] ||
372ed1f0be2SJan Lentfer 	    sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) {
373ed1f0be2SJan Lentfer 		if ((sks = pf_alloc_state_key(pool_flags)) == NULL)
374ed1f0be2SJan Lentfer 			goto cleanup;
375ed1f0be2SJan Lentfer 	} else
376ed1f0be2SJan Lentfer 		sks = skw;
377315a7da3SJan Lentfer 
37870224baaSJan Lentfer 	/* allocate memory for scrub info */
37970224baaSJan Lentfer 	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
380ed1f0be2SJan Lentfer 	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
381ed1f0be2SJan Lentfer 		goto cleanup;
382ed1f0be2SJan Lentfer 
383ed1f0be2SJan Lentfer 	/* copy to state key(s) */
384ed1f0be2SJan Lentfer 	skw->addr[0] = sp->key[PF_SK_WIRE].addr[0];
385ed1f0be2SJan Lentfer 	skw->addr[1] = sp->key[PF_SK_WIRE].addr[1];
386ed1f0be2SJan Lentfer 	skw->port[0] = sp->key[PF_SK_WIRE].port[0];
387ed1f0be2SJan Lentfer 	skw->port[1] = sp->key[PF_SK_WIRE].port[1];
388ed1f0be2SJan Lentfer 	skw->proto = sp->proto;
389ed1f0be2SJan Lentfer 	skw->af = sp->af;
390ed1f0be2SJan Lentfer 	if (sks != skw) {
391ed1f0be2SJan Lentfer 		sks->addr[0] = sp->key[PF_SK_STACK].addr[0];
392ed1f0be2SJan Lentfer 		sks->addr[1] = sp->key[PF_SK_STACK].addr[1];
393ed1f0be2SJan Lentfer 		sks->port[0] = sp->key[PF_SK_STACK].port[0];
394ed1f0be2SJan Lentfer 		sks->port[1] = sp->key[PF_SK_STACK].port[1];
395ed1f0be2SJan Lentfer 		sks->proto = sp->proto;
396ed1f0be2SJan Lentfer 		sks->af = sp->af;
39770224baaSJan Lentfer 	}
39870224baaSJan Lentfer 
399ed1f0be2SJan Lentfer 	/* copy to state */
40002742ec6SJoerg Sonnenberger 	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
40170224baaSJan Lentfer 	st->creation = time_second - ntohl(sp->creation);
402ed1f0be2SJan Lentfer 	st->expire = time_second;
403ed1f0be2SJan Lentfer 	if (sp->expire) {
404ed1f0be2SJan Lentfer 		/* XXX No adaptive scaling. */
405ed1f0be2SJan Lentfer 		st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire);
406ed1f0be2SJan Lentfer 	}
40702742ec6SJoerg Sonnenberger 
408ed1f0be2SJan Lentfer 	st->expire = ntohl(sp->expire) + time_second;
409ed1f0be2SJan Lentfer 	st->direction = sp->direction;
41002742ec6SJoerg Sonnenberger 	st->log = sp->log;
41102742ec6SJoerg Sonnenberger 	st->timeout = sp->timeout;
412ed1f0be2SJan Lentfer 	st->state_flags = sp->state_flags;
413ed1f0be2SJan Lentfer 	if (!(flags & PFSYNC_SI_IOCTL))
414ed1f0be2SJan Lentfer 		st->sync_flags = PFSTATE_FROMSYNC;
41502742ec6SJoerg Sonnenberger 
41602742ec6SJoerg Sonnenberger 	bcopy(sp->id, &st->id, sizeof(st->id));
41702742ec6SJoerg Sonnenberger 	st->creatorid = sp->creatorid;
418ed1f0be2SJan Lentfer 	pf_state_peer_ntoh(&sp->src, &st->src);
419ed1f0be2SJan Lentfer 	pf_state_peer_ntoh(&sp->dst, &st->dst);
42002742ec6SJoerg Sonnenberger 
421ed1f0be2SJan Lentfer 	st->rule.ptr = r;
422ed1f0be2SJan Lentfer 	st->nat_rule.ptr = NULL;
423ed1f0be2SJan Lentfer 	st->anchor.ptr = NULL;
424ed1f0be2SJan Lentfer 	st->rt_kif = NULL;
425ed1f0be2SJan Lentfer 
426ed1f0be2SJan Lentfer 	st->pfsync_time = 0;
427ed1f0be2SJan Lentfer 
428ed1f0be2SJan Lentfer 
429ed1f0be2SJan Lentfer 	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
430ed1f0be2SJan Lentfer 	r->states_cur++;
431ed1f0be2SJan Lentfer 	r->states_tot++;
432ed1f0be2SJan Lentfer 
433ed1f0be2SJan Lentfer 	if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
43470224baaSJan Lentfer 		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
435ed1f0be2SJan Lentfer 		r->states_cur--;
436ed1f0be2SJan Lentfer 		goto cleanup_state;
437ed1f0be2SJan Lentfer 	}
438ed1f0be2SJan Lentfer 
439ed1f0be2SJan Lentfer 	return (0);
440ed1f0be2SJan Lentfer 
441ed1f0be2SJan Lentfer  cleanup:
442ed1f0be2SJan Lentfer 	error = ENOMEM;
443ed1f0be2SJan Lentfer 	if (skw == sks)
444ed1f0be2SJan Lentfer 		sks = NULL;
445ed1f0be2SJan Lentfer 	if (skw != NULL)
4461186cbc0SJan Lentfer 		kfree(skw, M_PFSYNC);
447ed1f0be2SJan Lentfer 	if (sks != NULL)
4481186cbc0SJan Lentfer 		kfree(sks, M_PFSYNC);
449ed1f0be2SJan Lentfer 
450ed1f0be2SJan Lentfer  cleanup_state:	/* pf_state_insert frees the state keys */
451ed1f0be2SJan Lentfer 	if (st) {
45270224baaSJan Lentfer 		if (st->dst.scrub)
4531186cbc0SJan Lentfer 			kfree(st->dst.scrub, M_PFSYNC);
45470224baaSJan Lentfer 		if (st->src.scrub)
4551186cbc0SJan Lentfer 			kfree(st->src.scrub, M_PFSYNC);
4561186cbc0SJan Lentfer 		kfree(st, M_PFSYNC);
45702742ec6SJoerg Sonnenberger 	}
458ed1f0be2SJan Lentfer 	return (error);
45902742ec6SJoerg Sonnenberger }
46002742ec6SJoerg Sonnenberger 
46102742ec6SJoerg Sonnenberger void
pfsync_input(struct mbuf * m,...)46202742ec6SJoerg Sonnenberger pfsync_input(struct mbuf *m, ...)
46302742ec6SJoerg Sonnenberger {
46402742ec6SJoerg Sonnenberger 	struct ip *ip = mtod(m, struct ip *);
46502742ec6SJoerg Sonnenberger 	struct pfsync_header *ph;
46670224baaSJan Lentfer 	struct pfsync_softc *sc = pfsyncif;
46770224baaSJan Lentfer 	struct pf_state *st;
468315a7da3SJan Lentfer 	struct pf_state_key *sk;
469ed1f0be2SJan Lentfer 	struct pf_state_item *si;
470315a7da3SJan Lentfer 	struct pf_state_cmp id_key;
47102742ec6SJoerg Sonnenberger 	struct pfsync_state *sp;
47202742ec6SJoerg Sonnenberger 	struct pfsync_state_upd *up;
47302742ec6SJoerg Sonnenberger 	struct pfsync_state_del *dp;
47402742ec6SJoerg Sonnenberger 	struct pfsync_state_clr *cp;
47502742ec6SJoerg Sonnenberger 	struct pfsync_state_upd_req *rup;
47602742ec6SJoerg Sonnenberger 	struct pfsync_state_bus *bus;
47702742ec6SJoerg Sonnenberger 	struct in_addr src;
47802742ec6SJoerg Sonnenberger 	struct mbuf *mp;
479c3c8c553SJan Lentfer 	int iplen, action, error, i, count, offp, sfail, stale = 0;
480ed1f0be2SJan Lentfer 	u_int8_t flags = 0;
48102742ec6SJoerg Sonnenberger 
4822a7a2b1cSJan Lentfer 	/* This function is not yet called from anywhere */
4832a7a2b1cSJan Lentfer 	/* Still we assume for safety that pf_token must be held */
4842a7a2b1cSJan Lentfer 	ASSERT_LWKT_TOKEN_HELD(&pf_token);
4852a7a2b1cSJan Lentfer 
48602742ec6SJoerg Sonnenberger 	pfsyncstats.pfsyncs_ipackets++;
48702742ec6SJoerg Sonnenberger 
48802742ec6SJoerg Sonnenberger 	/* verify that we have a sync interface configured */
48970224baaSJan Lentfer 	if (!sc || !sc->sc_sync_ifp || !pf_status.running)
49002742ec6SJoerg Sonnenberger 		goto done;
49102742ec6SJoerg Sonnenberger 
49202742ec6SJoerg Sonnenberger 	/* verify that the packet came in on the right interface */
49302742ec6SJoerg Sonnenberger 	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
49402742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_badif++;
49502742ec6SJoerg Sonnenberger 		goto done;
49602742ec6SJoerg Sonnenberger 	}
49702742ec6SJoerg Sonnenberger 
49802742ec6SJoerg Sonnenberger 	/* verify that the IP TTL is 255.  */
49902742ec6SJoerg Sonnenberger 	if (ip->ip_ttl != PFSYNC_DFLTTL) {
50002742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_badttl++;
50102742ec6SJoerg Sonnenberger 		goto done;
50202742ec6SJoerg Sonnenberger 	}
50302742ec6SJoerg Sonnenberger 
50402742ec6SJoerg Sonnenberger 	iplen = ip->ip_hl << 2;
50502742ec6SJoerg Sonnenberger 
50602742ec6SJoerg Sonnenberger 	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
50702742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_hdrops++;
50802742ec6SJoerg Sonnenberger 		goto done;
50902742ec6SJoerg Sonnenberger 	}
51002742ec6SJoerg Sonnenberger 
51102742ec6SJoerg Sonnenberger 	if (iplen + sizeof(*ph) > m->m_len) {
51202742ec6SJoerg Sonnenberger 		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
51302742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_hdrops++;
51402742ec6SJoerg Sonnenberger 			goto done;
51502742ec6SJoerg Sonnenberger 		}
51602742ec6SJoerg Sonnenberger 		ip = mtod(m, struct ip *);
51702742ec6SJoerg Sonnenberger 	}
51802742ec6SJoerg Sonnenberger 	ph = (struct pfsync_header *)((char *)ip + iplen);
51902742ec6SJoerg Sonnenberger 
52002742ec6SJoerg Sonnenberger 	/* verify the version */
52102742ec6SJoerg Sonnenberger 	if (ph->version != PFSYNC_VERSION) {
52202742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_badver++;
52302742ec6SJoerg Sonnenberger 		goto done;
52402742ec6SJoerg Sonnenberger 	}
52502742ec6SJoerg Sonnenberger 
52602742ec6SJoerg Sonnenberger 	action = ph->action;
52702742ec6SJoerg Sonnenberger 	count = ph->count;
52802742ec6SJoerg Sonnenberger 
52902742ec6SJoerg Sonnenberger 	/* make sure it's a valid action code */
53002742ec6SJoerg Sonnenberger 	if (action >= PFSYNC_ACT_MAX) {
53102742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_badact++;
53202742ec6SJoerg Sonnenberger 		goto done;
53302742ec6SJoerg Sonnenberger 	}
53402742ec6SJoerg Sonnenberger 
53502742ec6SJoerg Sonnenberger 	/* Cheaper to grab this now than having to mess with mbufs later */
53602742ec6SJoerg Sonnenberger 	src = ip->ip_src;
53702742ec6SJoerg Sonnenberger 
53870224baaSJan Lentfer 	if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
539ed1f0be2SJan Lentfer 		flags |= PFSYNC_SI_CKSUM;
54070224baaSJan Lentfer 
54102742ec6SJoerg Sonnenberger 	switch (action) {
54202742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_CLR: {
54370224baaSJan Lentfer 		struct pf_state *nexts;
544315a7da3SJan Lentfer 		struct pf_state_key *nextsk;
54502742ec6SJoerg Sonnenberger 		struct pfi_kif *kif;
5463a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
5473a0038bfSMatthew Dillon 		int nn;
5483a0038bfSMatthew Dillon 
54902742ec6SJoerg Sonnenberger 		u_int32_t creatorid;
55002742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
55102742ec6SJoerg Sonnenberger 		    sizeof(*cp), &offp)) == NULL) {
55202742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
55302742ec6SJoerg Sonnenberger 			return;
55402742ec6SJoerg Sonnenberger 		}
55502742ec6SJoerg Sonnenberger 		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
55602742ec6SJoerg Sonnenberger 		creatorid = cp->creatorid;
55702742ec6SJoerg Sonnenberger 
558c3c8c553SJan Lentfer 		crit_enter();
55902742ec6SJoerg Sonnenberger 		if (cp->ifname[0] == '\0') {
5603a0038bfSMatthew Dillon 			lwkt_gettoken(&pf_token);
5613a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
5623a0038bfSMatthew Dillon 				lwkt_setcpu_self(globaldata_find(nn));
5633a0038bfSMatthew Dillon 				for (st = RB_MIN(pf_state_tree_id,
5643a0038bfSMatthew Dillon 						 &tree_id[nn]);
56570224baaSJan Lentfer 				     st; st = nexts) {
5663a0038bfSMatthew Dillon 					nexts = RB_NEXT(pf_state_tree_id,
5673a0038bfSMatthew Dillon 							&tree_id[n], st);
56870224baaSJan Lentfer 					if (st->creatorid == creatorid) {
5693a0038bfSMatthew Dillon 						st->sync_flags |=
5703a0038bfSMatthew Dillon 							PFSTATE_FROMSYNC;
57170224baaSJan Lentfer 						pf_unlink_state(st);
57270224baaSJan Lentfer 					}
57302742ec6SJoerg Sonnenberger 				}
5743a0038bfSMatthew Dillon 			}
5753a0038bfSMatthew Dillon 			lwkt_setcpu_self(save_gd);
5763a0038bfSMatthew Dillon 			lwkt_reltoken(&pf_token);
57702742ec6SJoerg Sonnenberger 		} else {
57870224baaSJan Lentfer 			if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
579c3c8c553SJan Lentfer 				crit_exit();
58070224baaSJan Lentfer 				return;
58102742ec6SJoerg Sonnenberger 			}
582ed1f0be2SJan Lentfer 			/* XXX correct? */
5833a0038bfSMatthew Dillon 			lwkt_gettoken(&pf_token);
5843a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
5853a0038bfSMatthew Dillon 				lwkt_setcpu_self(globaldata_find(nn));
586ed1f0be2SJan Lentfer 				for (sk = RB_MIN(pf_state_tree,
5873a0038bfSMatthew Dillon 						 &pf_statetbl[nn]);
5883a0038bfSMatthew Dillon 				     sk;
5893a0038bfSMatthew Dillon 				     sk = nextsk) {
590ed1f0be2SJan Lentfer 					nextsk = RB_NEXT(pf_state_tree,
5913a0038bfSMatthew Dillon 					    &pf_statetbl[n], sk);
592ed1f0be2SJan Lentfer 					TAILQ_FOREACH(si, &sk->states, entry) {
5933a0038bfSMatthew Dillon 						if (si->s->creatorid ==
5943a0038bfSMatthew Dillon 						    creatorid) {
595ed1f0be2SJan Lentfer 							si->s->sync_flags |=
596315a7da3SJan Lentfer 							    PFSTATE_FROMSYNC;
597ed1f0be2SJan Lentfer 							pf_unlink_state(si->s);
59802742ec6SJoerg Sonnenberger 						}
59902742ec6SJoerg Sonnenberger 					}
60070224baaSJan Lentfer 				}
601315a7da3SJan Lentfer 			}
6023a0038bfSMatthew Dillon 			lwkt_setcpu_self(save_gd);
6033a0038bfSMatthew Dillon 			lwkt_reltoken(&pf_token);
6043a0038bfSMatthew Dillon 		}
605c3c8c553SJan Lentfer 		crit_exit();
60602742ec6SJoerg Sonnenberger 
60702742ec6SJoerg Sonnenberger 		break;
60802742ec6SJoerg Sonnenberger 	}
60902742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_INS:
61002742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
61102742ec6SJoerg Sonnenberger 		    count * sizeof(*sp), &offp)) == NULL) {
61202742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
61302742ec6SJoerg Sonnenberger 			return;
61402742ec6SJoerg Sonnenberger 		}
61502742ec6SJoerg Sonnenberger 
616c3c8c553SJan Lentfer 		crit_enter();
61702742ec6SJoerg Sonnenberger 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
61802742ec6SJoerg Sonnenberger 		    i < count; i++, sp++) {
61902742ec6SJoerg Sonnenberger 			/* check for invalid values */
62002742ec6SJoerg Sonnenberger 			if (sp->timeout >= PFTM_MAX ||
62102742ec6SJoerg Sonnenberger 			    sp->src.state > PF_TCPS_PROXY_DST ||
62202742ec6SJoerg Sonnenberger 			    sp->dst.state > PF_TCPS_PROXY_DST ||
62302742ec6SJoerg Sonnenberger 			    sp->direction > PF_OUT ||
62402742ec6SJoerg Sonnenberger 			    (sp->af != AF_INET && sp->af != AF_INET6)) {
62502742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
626c3c8c553SJan Lentfer 					kprintf("pfsync_insert: PFSYNC_ACT_INS: "
62702742ec6SJoerg Sonnenberger 					    "invalid value\n");
628ed1f0be2SJan Lentfer 				pfsyncstats.pfsyncs_badval++;
62902742ec6SJoerg Sonnenberger 				continue;
63002742ec6SJoerg Sonnenberger 			}
63102742ec6SJoerg Sonnenberger 
632ed1f0be2SJan Lentfer 			if ((error = pfsync_state_import(sp, flags))) {
63302742ec6SJoerg Sonnenberger 				if (error == ENOMEM) {
634c3c8c553SJan Lentfer 					crit_exit();
63502742ec6SJoerg Sonnenberger 					goto done;
63602742ec6SJoerg Sonnenberger 				}
63702742ec6SJoerg Sonnenberger 			}
63802742ec6SJoerg Sonnenberger 		}
639c3c8c553SJan Lentfer 		crit_exit();
64002742ec6SJoerg Sonnenberger 		break;
64102742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_UPD:
64202742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
64302742ec6SJoerg Sonnenberger 		    count * sizeof(*sp), &offp)) == NULL) {
64402742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
64502742ec6SJoerg Sonnenberger 			return;
64602742ec6SJoerg Sonnenberger 		}
64702742ec6SJoerg Sonnenberger 
648c3c8c553SJan Lentfer 		crit_enter();
64902742ec6SJoerg Sonnenberger 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
65002742ec6SJoerg Sonnenberger 		    i < count; i++, sp++) {
65170224baaSJan Lentfer 			int flags = PFSYNC_FLAG_STALE;
65270224baaSJan Lentfer 
65302742ec6SJoerg Sonnenberger 			/* check for invalid values */
65402742ec6SJoerg Sonnenberger 			if (sp->timeout >= PFTM_MAX ||
65502742ec6SJoerg Sonnenberger 			    sp->src.state > PF_TCPS_PROXY_DST ||
65602742ec6SJoerg Sonnenberger 			    sp->dst.state > PF_TCPS_PROXY_DST) {
65702742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
658c3c8c553SJan Lentfer 					kprintf("pfsync_insert: PFSYNC_ACT_UPD: "
65902742ec6SJoerg Sonnenberger 					    "invalid value\n");
660ed1f0be2SJan Lentfer 				pfsyncstats.pfsyncs_badval++;
66102742ec6SJoerg Sonnenberger 				continue;
66202742ec6SJoerg Sonnenberger 			}
66302742ec6SJoerg Sonnenberger 
664315a7da3SJan Lentfer 			bcopy(sp->id, &id_key.id, sizeof(id_key.id));
665315a7da3SJan Lentfer 			id_key.creatorid = sp->creatorid;
66602742ec6SJoerg Sonnenberger 
667315a7da3SJan Lentfer 			st = pf_find_state_byid(&id_key);
66802742ec6SJoerg Sonnenberger 			if (st == NULL) {
66902742ec6SJoerg Sonnenberger 				/* insert the update */
670ed1f0be2SJan Lentfer 				if (pfsync_state_import(sp, flags))
67102742ec6SJoerg Sonnenberger 					pfsyncstats.pfsyncs_badstate++;
67202742ec6SJoerg Sonnenberger 				continue;
67302742ec6SJoerg Sonnenberger 			}
674ed1f0be2SJan Lentfer 			sk = st->key[PF_SK_WIRE];	/* XXX right one? */
67570224baaSJan Lentfer 			sfail = 0;
676315a7da3SJan Lentfer 			if (sk->proto == IPPROTO_TCP) {
67770224baaSJan Lentfer 				/*
67870224baaSJan Lentfer 				 * The state should never go backwards except
67970224baaSJan Lentfer 				 * for syn-proxy states.  Neither should the
68070224baaSJan Lentfer 				 * sequence window slide backwards.
68170224baaSJan Lentfer 				 */
68270224baaSJan Lentfer 				if (st->src.state > sp->src.state &&
68370224baaSJan Lentfer 				    (st->src.state < PF_TCPS_PROXY_SRC ||
68470224baaSJan Lentfer 				    sp->src.state >= PF_TCPS_PROXY_SRC))
68570224baaSJan Lentfer 					sfail = 1;
68670224baaSJan Lentfer 				else if (SEQ_GT(st->src.seqlo,
68770224baaSJan Lentfer 				    ntohl(sp->src.seqlo)))
68870224baaSJan Lentfer 					sfail = 3;
68970224baaSJan Lentfer 				else if (st->dst.state > sp->dst.state) {
69070224baaSJan Lentfer 					/* There might still be useful
69170224baaSJan Lentfer 					 * information about the src state here,
69270224baaSJan Lentfer 					 * so import that part of the update,
69370224baaSJan Lentfer 					 * then "fail" so we send the updated
69470224baaSJan Lentfer 					 * state back to the peer who is missing
69570224baaSJan Lentfer 					 * our what we know. */
69670224baaSJan Lentfer 					pf_state_peer_ntoh(&sp->src, &st->src);
69770224baaSJan Lentfer 					/* XXX do anything with timeouts? */
69870224baaSJan Lentfer 					sfail = 7;
69970224baaSJan Lentfer 					flags = 0;
70070224baaSJan Lentfer 				} else if (st->dst.state >= TCPS_SYN_SENT &&
70170224baaSJan Lentfer 				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
70270224baaSJan Lentfer 					sfail = 4;
70370224baaSJan Lentfer 			} else {
70470224baaSJan Lentfer 				/*
70570224baaSJan Lentfer 				 * Non-TCP protocol state machine always go
70670224baaSJan Lentfer 				 * forwards
70770224baaSJan Lentfer 				 */
70870224baaSJan Lentfer 				if (st->src.state > sp->src.state)
70970224baaSJan Lentfer 					sfail = 5;
71070224baaSJan Lentfer 				else if (st->dst.state > sp->dst.state)
71170224baaSJan Lentfer 					sfail = 6;
71270224baaSJan Lentfer 			}
71370224baaSJan Lentfer 			if (sfail) {
71470224baaSJan Lentfer 				if (pf_status.debug >= PF_DEBUG_MISC)
715c3c8c553SJan Lentfer 					kprintf("pfsync: %s stale update "
7168dfe42a9SSascha Wildner 					    "(%d) id: %016jx "
71770224baaSJan Lentfer 					    "creatorid: %08x\n",
71870224baaSJan Lentfer 					    (sfail < 7 ?  "ignoring"
71970224baaSJan Lentfer 					     : "partial"), sfail,
7208dfe42a9SSascha Wildner 					    (uintmax_t)be64toh(st->id),
72170224baaSJan Lentfer 					    ntohl(st->creatorid));
722ed1f0be2SJan Lentfer 				pfsyncstats.pfsyncs_stale++;
72370224baaSJan Lentfer 
72470224baaSJan Lentfer 				if (!(sp->sync_flags & PFSTATE_STALE)) {
72570224baaSJan Lentfer 					/* we have a better state, send it */
72670224baaSJan Lentfer 					if (sc->sc_mbuf != NULL && !stale)
72770224baaSJan Lentfer 						pfsync_sendout(sc);
72870224baaSJan Lentfer 					stale++;
72970224baaSJan Lentfer 					if (!st->sync_flags)
73070224baaSJan Lentfer 						pfsync_pack_state(
73170224baaSJan Lentfer 						    PFSYNC_ACT_UPD, st, flags);
73270224baaSJan Lentfer 				}
73370224baaSJan Lentfer 				continue;
73470224baaSJan Lentfer 			}
73570224baaSJan Lentfer 			pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
73602742ec6SJoerg Sonnenberger 			pf_state_peer_ntoh(&sp->src, &st->src);
73702742ec6SJoerg Sonnenberger 			pf_state_peer_ntoh(&sp->dst, &st->dst);
73802742ec6SJoerg Sonnenberger 			st->expire = ntohl(sp->expire) + time_second;
73902742ec6SJoerg Sonnenberger 			st->timeout = sp->timeout;
74002742ec6SJoerg Sonnenberger 		}
74170224baaSJan Lentfer 		if (stale && sc->sc_mbuf != NULL)
74270224baaSJan Lentfer 			pfsync_sendout(sc);
743c3c8c553SJan Lentfer 		crit_exit();
74402742ec6SJoerg Sonnenberger 		break;
74502742ec6SJoerg Sonnenberger 	/*
74602742ec6SJoerg Sonnenberger 	 * It's not strictly necessary for us to support the "uncompressed"
74702742ec6SJoerg Sonnenberger 	 * delete action, but it's relatively simple and maintains consistency.
74802742ec6SJoerg Sonnenberger 	 */
74902742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_DEL:
75002742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
75102742ec6SJoerg Sonnenberger 		    count * sizeof(*sp), &offp)) == NULL) {
75202742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
75302742ec6SJoerg Sonnenberger 			return;
75402742ec6SJoerg Sonnenberger 		}
75502742ec6SJoerg Sonnenberger 
756c3c8c553SJan Lentfer 		crit_enter();
75702742ec6SJoerg Sonnenberger 		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
75802742ec6SJoerg Sonnenberger 		    i < count; i++, sp++) {
759315a7da3SJan Lentfer 			bcopy(sp->id, &id_key.id, sizeof(id_key.id));
760315a7da3SJan Lentfer 			id_key.creatorid = sp->creatorid;
76102742ec6SJoerg Sonnenberger 
762315a7da3SJan Lentfer 			st = pf_find_state_byid(&id_key);
76302742ec6SJoerg Sonnenberger 			if (st == NULL) {
76402742ec6SJoerg Sonnenberger 				pfsyncstats.pfsyncs_badstate++;
76502742ec6SJoerg Sonnenberger 				continue;
76602742ec6SJoerg Sonnenberger 			}
76702742ec6SJoerg Sonnenberger 			st->sync_flags |= PFSTATE_FROMSYNC;
76870224baaSJan Lentfer 			pf_unlink_state(st);
76902742ec6SJoerg Sonnenberger 		}
770c3c8c553SJan Lentfer 		crit_exit();
77102742ec6SJoerg Sonnenberger 		break;
77202742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_UPD_C: {
77302742ec6SJoerg Sonnenberger 		int update_requested = 0;
77402742ec6SJoerg Sonnenberger 
77502742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
77602742ec6SJoerg Sonnenberger 		    count * sizeof(*up), &offp)) == NULL) {
77702742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
77802742ec6SJoerg Sonnenberger 			return;
77902742ec6SJoerg Sonnenberger 		}
78002742ec6SJoerg Sonnenberger 
781c3c8c553SJan Lentfer 		crit_enter();
78202742ec6SJoerg Sonnenberger 		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
78302742ec6SJoerg Sonnenberger 		    i < count; i++, up++) {
78402742ec6SJoerg Sonnenberger 			/* check for invalid values */
78502742ec6SJoerg Sonnenberger 			if (up->timeout >= PFTM_MAX ||
78602742ec6SJoerg Sonnenberger 			    up->src.state > PF_TCPS_PROXY_DST ||
78702742ec6SJoerg Sonnenberger 			    up->dst.state > PF_TCPS_PROXY_DST) {
78802742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
789c3c8c553SJan Lentfer 					kprintf("pfsync_insert: "
79002742ec6SJoerg Sonnenberger 					    "PFSYNC_ACT_UPD_C: "
79102742ec6SJoerg Sonnenberger 					    "invalid value\n");
792ed1f0be2SJan Lentfer 				pfsyncstats.pfsyncs_badval++;
79302742ec6SJoerg Sonnenberger 				continue;
79402742ec6SJoerg Sonnenberger 			}
79502742ec6SJoerg Sonnenberger 
796315a7da3SJan Lentfer 			bcopy(up->id, &id_key.id, sizeof(id_key.id));
797315a7da3SJan Lentfer 			id_key.creatorid = up->creatorid;
79802742ec6SJoerg Sonnenberger 
799315a7da3SJan Lentfer 			st = pf_find_state_byid(&id_key);
80002742ec6SJoerg Sonnenberger 			if (st == NULL) {
80102742ec6SJoerg Sonnenberger 				/* We don't have this state. Ask for it. */
80270224baaSJan Lentfer 				error = pfsync_request_update(up, &src);
80370224baaSJan Lentfer 				if (error == ENOMEM) {
804c3c8c553SJan Lentfer 					crit_exit();
80570224baaSJan Lentfer 					goto done;
80670224baaSJan Lentfer 				}
80702742ec6SJoerg Sonnenberger 				update_requested = 1;
80802742ec6SJoerg Sonnenberger 				pfsyncstats.pfsyncs_badstate++;
80902742ec6SJoerg Sonnenberger 				continue;
81002742ec6SJoerg Sonnenberger 			}
811ed1f0be2SJan Lentfer 			sk = st->key[PF_SK_WIRE]; /* XXX right one? */
81270224baaSJan Lentfer 			sfail = 0;
813315a7da3SJan Lentfer 			if (sk->proto == IPPROTO_TCP) {
81470224baaSJan Lentfer 				/*
81570224baaSJan Lentfer 				 * The state should never go backwards except
81670224baaSJan Lentfer 				 * for syn-proxy states.  Neither should the
81770224baaSJan Lentfer 				 * sequence window slide backwards.
81870224baaSJan Lentfer 				 */
81970224baaSJan Lentfer 				if (st->src.state > up->src.state &&
82070224baaSJan Lentfer 				    (st->src.state < PF_TCPS_PROXY_SRC ||
82170224baaSJan Lentfer 				    up->src.state >= PF_TCPS_PROXY_SRC))
82270224baaSJan Lentfer 					sfail = 1;
82370224baaSJan Lentfer 				else if (st->dst.state > up->dst.state)
82470224baaSJan Lentfer 					sfail = 2;
82570224baaSJan Lentfer 				else if (SEQ_GT(st->src.seqlo,
82670224baaSJan Lentfer 				    ntohl(up->src.seqlo)))
82770224baaSJan Lentfer 					sfail = 3;
82870224baaSJan Lentfer 				else if (st->dst.state >= TCPS_SYN_SENT &&
82970224baaSJan Lentfer 				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
83070224baaSJan Lentfer 					sfail = 4;
83170224baaSJan Lentfer 			} else {
83270224baaSJan Lentfer 				/*
83370224baaSJan Lentfer 				 * Non-TCP protocol state machine always go
83470224baaSJan Lentfer 				 * forwards
83570224baaSJan Lentfer 				 */
83670224baaSJan Lentfer 				if (st->src.state > up->src.state)
83770224baaSJan Lentfer 					sfail = 5;
83870224baaSJan Lentfer 				else if (st->dst.state > up->dst.state)
83970224baaSJan Lentfer 					sfail = 6;
84070224baaSJan Lentfer 			}
84170224baaSJan Lentfer 			if (sfail) {
84270224baaSJan Lentfer 				if (pf_status.debug >= PF_DEBUG_MISC)
843c3c8c553SJan Lentfer 					kprintf("pfsync: ignoring stale update "
84478775ca5SSascha Wildner 					    "(%d) id: %016" PRIx64 " "
84570224baaSJan Lentfer 					    "creatorid: %08x\n", sfail,
846c3c8c553SJan Lentfer 					    be64toh(st->id),
84770224baaSJan Lentfer 					    ntohl(st->creatorid));
848ed1f0be2SJan Lentfer 				pfsyncstats.pfsyncs_stale++;
84970224baaSJan Lentfer 
85070224baaSJan Lentfer 				/* we have a better state, send it out */
85170224baaSJan Lentfer 				if ((!stale || update_requested) &&
85270224baaSJan Lentfer 				    sc->sc_mbuf != NULL) {
85370224baaSJan Lentfer 					pfsync_sendout(sc);
85470224baaSJan Lentfer 					update_requested = 0;
85570224baaSJan Lentfer 				}
85670224baaSJan Lentfer 				stale++;
85770224baaSJan Lentfer 				if (!st->sync_flags)
85870224baaSJan Lentfer 					pfsync_pack_state(PFSYNC_ACT_UPD, st,
85970224baaSJan Lentfer 					    PFSYNC_FLAG_STALE);
86070224baaSJan Lentfer 				continue;
86170224baaSJan Lentfer 			}
86270224baaSJan Lentfer 			pfsync_alloc_scrub_memory(&up->dst, &st->dst);
86302742ec6SJoerg Sonnenberger 			pf_state_peer_ntoh(&up->src, &st->src);
86402742ec6SJoerg Sonnenberger 			pf_state_peer_ntoh(&up->dst, &st->dst);
86502742ec6SJoerg Sonnenberger 			st->expire = ntohl(up->expire) + time_second;
86602742ec6SJoerg Sonnenberger 			st->timeout = up->timeout;
86702742ec6SJoerg Sonnenberger 		}
86870224baaSJan Lentfer 		if ((update_requested || stale) && sc->sc_mbuf)
86902742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
870c3c8c553SJan Lentfer 		crit_exit();
87102742ec6SJoerg Sonnenberger 		break;
87202742ec6SJoerg Sonnenberger 	}
87302742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_DEL_C:
87402742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
87502742ec6SJoerg Sonnenberger 		    count * sizeof(*dp), &offp)) == NULL) {
87602742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
87702742ec6SJoerg Sonnenberger 			return;
87802742ec6SJoerg Sonnenberger 		}
87902742ec6SJoerg Sonnenberger 
880c3c8c553SJan Lentfer 		crit_enter();
88102742ec6SJoerg Sonnenberger 		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
88202742ec6SJoerg Sonnenberger 		    i < count; i++, dp++) {
883315a7da3SJan Lentfer 			bcopy(dp->id, &id_key.id, sizeof(id_key.id));
884315a7da3SJan Lentfer 			id_key.creatorid = dp->creatorid;
88502742ec6SJoerg Sonnenberger 
886315a7da3SJan Lentfer 			st = pf_find_state_byid(&id_key);
88702742ec6SJoerg Sonnenberger 			if (st == NULL) {
88802742ec6SJoerg Sonnenberger 				pfsyncstats.pfsyncs_badstate++;
88902742ec6SJoerg Sonnenberger 				continue;
89002742ec6SJoerg Sonnenberger 			}
89102742ec6SJoerg Sonnenberger 			st->sync_flags |= PFSTATE_FROMSYNC;
89270224baaSJan Lentfer 			pf_unlink_state(st);
89302742ec6SJoerg Sonnenberger 		}
894c3c8c553SJan Lentfer 		crit_exit();
89502742ec6SJoerg Sonnenberger 		break;
89602742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_INS_F:
89702742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_DEL_F:
89802742ec6SJoerg Sonnenberger 		/* not implemented */
89902742ec6SJoerg Sonnenberger 		break;
90002742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_UREQ:
90102742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
90202742ec6SJoerg Sonnenberger 		    count * sizeof(*rup), &offp)) == NULL) {
90302742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
90402742ec6SJoerg Sonnenberger 			return;
90502742ec6SJoerg Sonnenberger 		}
90602742ec6SJoerg Sonnenberger 
907c3c8c553SJan Lentfer 		crit_enter();
90802742ec6SJoerg Sonnenberger 		if (sc->sc_mbuf != NULL)
90902742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
91002742ec6SJoerg Sonnenberger 		for (i = 0,
91102742ec6SJoerg Sonnenberger 		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
91202742ec6SJoerg Sonnenberger 		    i < count; i++, rup++) {
913315a7da3SJan Lentfer 			bcopy(rup->id, &id_key.id, sizeof(id_key.id));
914315a7da3SJan Lentfer 			id_key.creatorid = rup->creatorid;
91502742ec6SJoerg Sonnenberger 
916315a7da3SJan Lentfer 			if (id_key.id == 0 && id_key.creatorid == 0) {
917c3c8c553SJan Lentfer 				sc->sc_ureq_received = mycpu->gd_time_seconds;
9183a0038bfSMatthew Dillon 				if (sc->sc_bulk_send_next == NULL) {
9193a0038bfSMatthew Dillon 					if (++sc->sc_bulk_send_cpu >= ncpus)
9203a0038bfSMatthew Dillon 						sc->sc_bulk_send_cpu = 0;
92170224baaSJan Lentfer 					sc->sc_bulk_send_next =
9223a0038bfSMatthew Dillon 					    TAILQ_FIRST(&state_list[sc->sc_bulk_send_cpu]);
9233a0038bfSMatthew Dillon 				}
9243a0038bfSMatthew Dillon 				sc->sc_bulk_terminator =
9253a0038bfSMatthew Dillon 					sc->sc_bulk_send_next;
9263a0038bfSMatthew Dillon 				sc->sc_bulk_terminator_cpu =
9273a0038bfSMatthew Dillon 					sc->sc_bulk_send_cpu;
92802742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
929c3c8c553SJan Lentfer 					kprintf("pfsync: received "
93002742ec6SJoerg Sonnenberger 					    "bulk update request\n");
93102742ec6SJoerg Sonnenberger 				pfsync_send_bus(sc, PFSYNC_BUS_START);
9322a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
933ed1f0be2SJan Lentfer 				callout_init(&sc->sc_bulk_tmo);
9342a7a2b1cSJan Lentfer 				lwkt_gettoken(&pf_token);
93502742ec6SJoerg Sonnenberger 			} else {
936315a7da3SJan Lentfer 				st = pf_find_state_byid(&id_key);
93702742ec6SJoerg Sonnenberger 				if (st == NULL) {
93802742ec6SJoerg Sonnenberger 					pfsyncstats.pfsyncs_badstate++;
93902742ec6SJoerg Sonnenberger 					continue;
94002742ec6SJoerg Sonnenberger 				}
94170224baaSJan Lentfer 				if (!st->sync_flags)
94270224baaSJan Lentfer 					pfsync_pack_state(PFSYNC_ACT_UPD,
94370224baaSJan Lentfer 					    st, 0);
94402742ec6SJoerg Sonnenberger 			}
94502742ec6SJoerg Sonnenberger 		}
94602742ec6SJoerg Sonnenberger 		if (sc->sc_mbuf != NULL)
94702742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
948c3c8c553SJan Lentfer 		crit_exit();
94902742ec6SJoerg Sonnenberger 		break;
95002742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_BUS:
95102742ec6SJoerg Sonnenberger 		/* If we're not waiting for a bulk update, who cares. */
95202742ec6SJoerg Sonnenberger 		if (sc->sc_ureq_sent == 0)
95302742ec6SJoerg Sonnenberger 			break;
95402742ec6SJoerg Sonnenberger 
95502742ec6SJoerg Sonnenberger 		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
95602742ec6SJoerg Sonnenberger 		    sizeof(*bus), &offp)) == NULL) {
95702742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_badlen++;
95802742ec6SJoerg Sonnenberger 			return;
95902742ec6SJoerg Sonnenberger 		}
96002742ec6SJoerg Sonnenberger 		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
96102742ec6SJoerg Sonnenberger 		switch (bus->status) {
96202742ec6SJoerg Sonnenberger 		case PFSYNC_BUS_START:
9632a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
964c3c8c553SJan Lentfer 			callout_reset(&sc->sc_bulkfail_tmo,
96502742ec6SJoerg Sonnenberger 			    pf_pool_limits[PF_LIMIT_STATES].limit /
966c3c8c553SJan Lentfer 			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
967c3c8c553SJan Lentfer 			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
9682a7a2b1cSJan Lentfer 			lwkt_gettoken(&pf_token);
96902742ec6SJoerg Sonnenberger 			if (pf_status.debug >= PF_DEBUG_MISC)
970c3c8c553SJan Lentfer 				kprintf("pfsync: received bulk "
97102742ec6SJoerg Sonnenberger 				    "update start\n");
97202742ec6SJoerg Sonnenberger 			break;
97302742ec6SJoerg Sonnenberger 		case PFSYNC_BUS_END:
974c3c8c553SJan Lentfer 			if (mycpu->gd_time_seconds - ntohl(bus->endtime) >=
97502742ec6SJoerg Sonnenberger 			    sc->sc_ureq_sent) {
97602742ec6SJoerg Sonnenberger 				/* that's it, we're happy */
97702742ec6SJoerg Sonnenberger 				sc->sc_ureq_sent = 0;
97802742ec6SJoerg Sonnenberger 				sc->sc_bulk_tries = 0;
9792a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
980c3c8c553SJan Lentfer 				callout_stop(&sc->sc_bulkfail_tmo);
9812a7a2b1cSJan Lentfer 				lwkt_gettoken(&pf_token);
9822b00f643SSascha Wildner #ifdef CARP
9832a7a2b1cSJan Lentfer 				if (!pfsync_sync_ok) {
9842a7a2b1cSJan Lentfer 					lwkt_reltoken(&pf_token);
98570224baaSJan Lentfer 					carp_group_demote_adj(&sc->sc_if, -1);
9862a7a2b1cSJan Lentfer 					lwkt_gettoken(&pf_token);
9872a7a2b1cSJan Lentfer 				}
98870224baaSJan Lentfer #endif
98902742ec6SJoerg Sonnenberger 				pfsync_sync_ok = 1;
99002742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
991c3c8c553SJan Lentfer 					kprintf("pfsync: received valid "
99202742ec6SJoerg Sonnenberger 					    "bulk update end\n");
99302742ec6SJoerg Sonnenberger 			} else {
99402742ec6SJoerg Sonnenberger 				if (pf_status.debug >= PF_DEBUG_MISC)
995c3c8c553SJan Lentfer 					kprintf("pfsync: received invalid "
99602742ec6SJoerg Sonnenberger 					    "bulk update end: bad timestamp\n");
99702742ec6SJoerg Sonnenberger 			}
99802742ec6SJoerg Sonnenberger 			break;
99902742ec6SJoerg Sonnenberger 		}
100002742ec6SJoerg Sonnenberger 		break;
100102742ec6SJoerg Sonnenberger 	}
100202742ec6SJoerg Sonnenberger 
100302742ec6SJoerg Sonnenberger done:
100402742ec6SJoerg Sonnenberger 	if (m)
100502742ec6SJoerg Sonnenberger 		m_freem(m);
100602742ec6SJoerg Sonnenberger }
100702742ec6SJoerg Sonnenberger 
100802742ec6SJoerg Sonnenberger int
pfsyncoutput(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)100902742ec6SJoerg Sonnenberger pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
101002742ec6SJoerg Sonnenberger 	struct rtentry *rt)
101102742ec6SJoerg Sonnenberger {
101202742ec6SJoerg Sonnenberger 	m_freem(m);
101302742ec6SJoerg Sonnenberger 	return (0);
101402742ec6SJoerg Sonnenberger }
101502742ec6SJoerg Sonnenberger 
101602742ec6SJoerg Sonnenberger /* ARGSUSED */
101702742ec6SJoerg Sonnenberger int
pfsyncioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)1018c3c8c553SJan Lentfer pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
101902742ec6SJoerg Sonnenberger {
102002742ec6SJoerg Sonnenberger 	struct pfsync_softc *sc = ifp->if_softc;
102102742ec6SJoerg Sonnenberger 	struct ifreq *ifr = (struct ifreq *)data;
102202742ec6SJoerg Sonnenberger 	struct ip_moptions *imo = &sc->sc_imo;
102302742ec6SJoerg Sonnenberger 	struct pfsyncreq pfsyncr;
102402742ec6SJoerg Sonnenberger 	struct ifnet    *sifp;
1025c3c8c553SJan Lentfer 	int error;
102602742ec6SJoerg Sonnenberger 
10272a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
10282a7a2b1cSJan Lentfer 
102902742ec6SJoerg Sonnenberger 	switch (cmd) {
103002742ec6SJoerg Sonnenberger 	case SIOCSIFADDR:
103102742ec6SJoerg Sonnenberger 	case SIOCAIFADDR:
103202742ec6SJoerg Sonnenberger 	case SIOCSIFDSTADDR:
103302742ec6SJoerg Sonnenberger 	case SIOCSIFFLAGS:
103402742ec6SJoerg Sonnenberger 		if (ifp->if_flags & IFF_UP)
103502742ec6SJoerg Sonnenberger 			ifp->if_flags |= IFF_RUNNING;
103602742ec6SJoerg Sonnenberger 		else
103702742ec6SJoerg Sonnenberger 			ifp->if_flags &= ~IFF_RUNNING;
103802742ec6SJoerg Sonnenberger 		break;
103902742ec6SJoerg Sonnenberger 	case SIOCSIFMTU:
10402a7a2b1cSJan Lentfer 		if (ifr->ifr_mtu < PFSYNC_MINMTU) {
10412a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
104202742ec6SJoerg Sonnenberger 			return (EINVAL);
10432a7a2b1cSJan Lentfer 		}
104402742ec6SJoerg Sonnenberger 		if (ifr->ifr_mtu > MCLBYTES)
104502742ec6SJoerg Sonnenberger 			ifr->ifr_mtu = MCLBYTES;
1046c3c8c553SJan Lentfer 		crit_enter();
104702742ec6SJoerg Sonnenberger 		if (ifr->ifr_mtu < ifp->if_mtu)
104802742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
104902742ec6SJoerg Sonnenberger 		pfsync_setmtu(sc, ifr->ifr_mtu);
1050c3c8c553SJan Lentfer 		crit_exit();
105102742ec6SJoerg Sonnenberger 		break;
105202742ec6SJoerg Sonnenberger 	case SIOCGETPFSYNC:
105302742ec6SJoerg Sonnenberger 		bzero(&pfsyncr, sizeof(pfsyncr));
105402742ec6SJoerg Sonnenberger 		if (sc->sc_sync_ifp)
105570224baaSJan Lentfer 			strlcpy(pfsyncr.pfsyncr_syncdev,
105602742ec6SJoerg Sonnenberger 			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
105770224baaSJan Lentfer 		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
105802742ec6SJoerg Sonnenberger 		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
10592a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
106002742ec6SJoerg Sonnenberger 		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
106102742ec6SJoerg Sonnenberger 			return (error);
10622a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
106302742ec6SJoerg Sonnenberger 		break;
106402742ec6SJoerg Sonnenberger 	case SIOCSETPFSYNC:
1065*2b3f93eaSMatthew Dillon 		error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
1066*2b3f93eaSMatthew Dillon 					    __SYSCAP_NULLCRED);
1067*2b3f93eaSMatthew Dillon 		if (error) {
10682a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
106902742ec6SJoerg Sonnenberger 			return (error);
10702a7a2b1cSJan Lentfer 		}
10712a7a2b1cSJan Lentfer 		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) {
10722a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
107302742ec6SJoerg Sonnenberger 			return (error);
10742a7a2b1cSJan Lentfer 		}
107502742ec6SJoerg Sonnenberger 
107670224baaSJan Lentfer 		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
107770224baaSJan Lentfer 			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
107870224baaSJan Lentfer 		else
107970224baaSJan Lentfer 			sc->sc_sync_peer.s_addr =
108070224baaSJan Lentfer 			    pfsyncr.pfsyncr_syncpeer.s_addr;
108170224baaSJan Lentfer 
10822a7a2b1cSJan Lentfer 		if (pfsyncr.pfsyncr_maxupdates > 255) {
10832a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
108402742ec6SJoerg Sonnenberger 			return (EINVAL);
10852a7a2b1cSJan Lentfer 		}
108602742ec6SJoerg Sonnenberger 		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
108702742ec6SJoerg Sonnenberger 
108870224baaSJan Lentfer 		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
108902742ec6SJoerg Sonnenberger 			sc->sc_sync_ifp = NULL;
109002742ec6SJoerg Sonnenberger 			if (sc->sc_mbuf_net != NULL) {
109102742ec6SJoerg Sonnenberger 				/* Don't keep stale pfsync packets around. */
1092c3c8c553SJan Lentfer 				crit_enter();
109302742ec6SJoerg Sonnenberger 				m_freem(sc->sc_mbuf_net);
109402742ec6SJoerg Sonnenberger 				sc->sc_mbuf_net = NULL;
109502742ec6SJoerg Sonnenberger 				sc->sc_statep_net.s = NULL;
1096c3c8c553SJan Lentfer 				crit_exit();
109770224baaSJan Lentfer 			}
109870224baaSJan Lentfer 			if (imo->imo_num_memberships > 0) {
1099ef15d469SSepherosa Ziehau 				pfsync_in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
110070224baaSJan Lentfer 				imo->imo_multicast_ifp = NULL;
110102742ec6SJoerg Sonnenberger 			}
110202742ec6SJoerg Sonnenberger 			break;
110302742ec6SJoerg Sonnenberger 		}
110402742ec6SJoerg Sonnenberger 
1105b4051e25SSepherosa Ziehau 		/*
1106b4051e25SSepherosa Ziehau 		 * XXX not that MPSAFE; pfsync needs serious rework
1107b4051e25SSepherosa Ziehau 		 */
1108b4051e25SSepherosa Ziehau 		ifnet_deserialize_all(ifp);
1109b4051e25SSepherosa Ziehau 		ifnet_lock();
1110b4051e25SSepherosa Ziehau 		sifp = ifunit(pfsyncr.pfsyncr_syncdev);
1111b4051e25SSepherosa Ziehau 		ifnet_unlock();
1112b4051e25SSepherosa Ziehau 		ifnet_serialize_all(ifp);
1113b4051e25SSepherosa Ziehau 
1114b4051e25SSepherosa Ziehau 		if (sifp == NULL) {
11152a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
111670224baaSJan Lentfer 			return (EINVAL);
11172a7a2b1cSJan Lentfer 		}
111870224baaSJan Lentfer 
1119c3c8c553SJan Lentfer 		crit_enter();
112002742ec6SJoerg Sonnenberger 		if (sifp->if_mtu < sc->sc_if.if_mtu ||
112102742ec6SJoerg Sonnenberger 		    (sc->sc_sync_ifp != NULL &&
112202742ec6SJoerg Sonnenberger 		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
112302742ec6SJoerg Sonnenberger 		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
112402742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
112502742ec6SJoerg Sonnenberger 		sc->sc_sync_ifp = sifp;
112602742ec6SJoerg Sonnenberger 
112702742ec6SJoerg Sonnenberger 		pfsync_setmtu(sc, sc->sc_if.if_mtu);
112802742ec6SJoerg Sonnenberger 
112902742ec6SJoerg Sonnenberger 		if (imo->imo_num_memberships > 0) {
1130ef15d469SSepherosa Ziehau 			pfsync_in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
113102742ec6SJoerg Sonnenberger 			imo->imo_multicast_ifp = NULL;
113202742ec6SJoerg Sonnenberger 		}
113302742ec6SJoerg Sonnenberger 
113470224baaSJan Lentfer 		if (sc->sc_sync_ifp &&
113570224baaSJan Lentfer 		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
113670224baaSJan Lentfer 			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
113770224baaSJan Lentfer 				sc->sc_sync_ifp = NULL;
11382a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
1139c3c8c553SJan Lentfer 				crit_exit();
114070224baaSJan Lentfer 				return (EADDRNOTAVAIL);
114170224baaSJan Lentfer 			}
114270224baaSJan Lentfer 
114302742ec6SJoerg Sonnenberger 			if ((imo->imo_membership[0] =
1144ef15d469SSepherosa Ziehau 			    pfsync_in_addmulti(sc->sc_sync_ifp)) == NULL) {
114570224baaSJan Lentfer 				sc->sc_sync_ifp = NULL;
11462a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
1147c3c8c553SJan Lentfer 				crit_exit();
114802742ec6SJoerg Sonnenberger 				return (ENOBUFS);
114902742ec6SJoerg Sonnenberger 			}
115002742ec6SJoerg Sonnenberger 			imo->imo_num_memberships++;
115102742ec6SJoerg Sonnenberger 			imo->imo_multicast_ifp = sc->sc_sync_ifp;
115202742ec6SJoerg Sonnenberger 			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
115302742ec6SJoerg Sonnenberger 			imo->imo_multicast_loop = 0;
115470224baaSJan Lentfer 		}
115502742ec6SJoerg Sonnenberger 
115670224baaSJan Lentfer 		if (sc->sc_sync_ifp ||
115770224baaSJan Lentfer 		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
115802742ec6SJoerg Sonnenberger 			/* Request a full state table update. */
1159c3c8c553SJan Lentfer 			sc->sc_ureq_sent = mycpu->gd_time_seconds;
11602b00f643SSascha Wildner #ifdef CARP
116170224baaSJan Lentfer 			if (pfsync_sync_ok)
116270224baaSJan Lentfer 				carp_group_demote_adj(&sc->sc_if, 1);
116370224baaSJan Lentfer #endif
116402742ec6SJoerg Sonnenberger 			pfsync_sync_ok = 0;
116502742ec6SJoerg Sonnenberger 			if (pf_status.debug >= PF_DEBUG_MISC)
1166c3c8c553SJan Lentfer 				kprintf("pfsync: requesting bulk update\n");
11672a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
1168c3c8c553SJan Lentfer 			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1169c3c8c553SJan Lentfer 			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
11702a7a2b1cSJan Lentfer 			lwkt_gettoken(&pf_token);
117170224baaSJan Lentfer 			error = pfsync_request_update(NULL, NULL);
117270224baaSJan Lentfer 			if (error == ENOMEM) {
11732a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
1174c3c8c553SJan Lentfer 				crit_exit();
117570224baaSJan Lentfer 				return (ENOMEM);
117670224baaSJan Lentfer 			}
117702742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
117802742ec6SJoerg Sonnenberger 		}
1179c3c8c553SJan Lentfer 		crit_exit();
118002742ec6SJoerg Sonnenberger 
118102742ec6SJoerg Sonnenberger 		break;
118202742ec6SJoerg Sonnenberger 
118302742ec6SJoerg Sonnenberger 	default:
11842a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
118502742ec6SJoerg Sonnenberger 		return (ENOTTY);
118602742ec6SJoerg Sonnenberger 	}
118702742ec6SJoerg Sonnenberger 
11882a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
118902742ec6SJoerg Sonnenberger 	return (0);
119002742ec6SJoerg Sonnenberger }
119102742ec6SJoerg Sonnenberger 
119202742ec6SJoerg Sonnenberger void
pfsync_setmtu(struct pfsync_softc * sc,int mtu_req)119302742ec6SJoerg Sonnenberger pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
119402742ec6SJoerg Sonnenberger {
119502742ec6SJoerg Sonnenberger 	int mtu;
119602742ec6SJoerg Sonnenberger 
119702742ec6SJoerg Sonnenberger 	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
119802742ec6SJoerg Sonnenberger 		mtu = sc->sc_sync_ifp->if_mtu;
119902742ec6SJoerg Sonnenberger 	else
120002742ec6SJoerg Sonnenberger 		mtu = mtu_req;
120102742ec6SJoerg Sonnenberger 
120202742ec6SJoerg Sonnenberger 	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
120302742ec6SJoerg Sonnenberger 	    sizeof(struct pfsync_state);
120402742ec6SJoerg Sonnenberger 	if (sc->sc_maxcount > 254)
120502742ec6SJoerg Sonnenberger 	    sc->sc_maxcount = 254;
120602742ec6SJoerg Sonnenberger 	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
120702742ec6SJoerg Sonnenberger 	    sc->sc_maxcount * sizeof(struct pfsync_state);
120802742ec6SJoerg Sonnenberger }
120902742ec6SJoerg Sonnenberger 
121002742ec6SJoerg Sonnenberger struct mbuf *
pfsync_get_mbuf(struct pfsync_softc * sc,u_int8_t action,void ** sp)121102742ec6SJoerg Sonnenberger pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
121202742ec6SJoerg Sonnenberger {
121302742ec6SJoerg Sonnenberger 	struct pfsync_header *h;
121402742ec6SJoerg Sonnenberger 	struct mbuf *m;
121502742ec6SJoerg Sonnenberger 	int len;
121602742ec6SJoerg Sonnenberger 
12172a7a2b1cSJan Lentfer 	ASSERT_LWKT_TOKEN_HELD(&pf_token);
12182a7a2b1cSJan Lentfer 
1219c3c8c553SJan Lentfer 	MGETHDR(m, M_WAITOK, MT_DATA);
122002742ec6SJoerg Sonnenberger 
122102742ec6SJoerg Sonnenberger 	switch (action) {
122202742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_CLR:
122302742ec6SJoerg Sonnenberger 		len = sizeof(struct pfsync_header) +
122402742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_state_clr);
122502742ec6SJoerg Sonnenberger 		break;
122602742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_UPD_C:
122702742ec6SJoerg Sonnenberger 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
122802742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_header);
122902742ec6SJoerg Sonnenberger 		break;
123002742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_DEL_C:
123102742ec6SJoerg Sonnenberger 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
123202742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_header);
123302742ec6SJoerg Sonnenberger 		break;
123402742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_UREQ:
123502742ec6SJoerg Sonnenberger 		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
123602742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_header);
123702742ec6SJoerg Sonnenberger 		break;
123802742ec6SJoerg Sonnenberger 	case PFSYNC_ACT_BUS:
123902742ec6SJoerg Sonnenberger 		len = sizeof(struct pfsync_header) +
124002742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_state_bus);
124102742ec6SJoerg Sonnenberger 		break;
1242315a7da3SJan Lentfer 	case PFSYNC_ACT_TDB_UPD:
1243315a7da3SJan Lentfer 		len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
1244315a7da3SJan Lentfer 		    sizeof(struct pfsync_header);
1245315a7da3SJan Lentfer 		break;
124602742ec6SJoerg Sonnenberger 	default:
124702742ec6SJoerg Sonnenberger 		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
124802742ec6SJoerg Sonnenberger 		    sizeof(struct pfsync_header);
124902742ec6SJoerg Sonnenberger 		break;
125002742ec6SJoerg Sonnenberger 	}
125102742ec6SJoerg Sonnenberger 
125202742ec6SJoerg Sonnenberger 	if (len > MHLEN) {
1253c3c8c553SJan Lentfer 		MCLGET(m, M_WAITOK);
12543f7b7260SSascha Wildner 		m->m_data += rounddown2(MCLBYTES - len, sizeof(long));
125502742ec6SJoerg Sonnenberger 	} else
125602742ec6SJoerg Sonnenberger 		MH_ALIGN(m, len);
125702742ec6SJoerg Sonnenberger 
125802742ec6SJoerg Sonnenberger 	m->m_pkthdr.rcvif = NULL;
125902742ec6SJoerg Sonnenberger 	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
126002742ec6SJoerg Sonnenberger 	h = mtod(m, struct pfsync_header *);
126102742ec6SJoerg Sonnenberger 	h->version = PFSYNC_VERSION;
126202742ec6SJoerg Sonnenberger 	h->af = 0;
126302742ec6SJoerg Sonnenberger 	h->count = 0;
126402742ec6SJoerg Sonnenberger 	h->action = action;
126502742ec6SJoerg Sonnenberger 
126602742ec6SJoerg Sonnenberger 	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
12672a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
1268c3c8c553SJan Lentfer 	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1269c3c8c553SJan Lentfer 	    LIST_FIRST(&pfsync_list));
12702a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
127102742ec6SJoerg Sonnenberger 	return (m);
127202742ec6SJoerg Sonnenberger }
127302742ec6SJoerg Sonnenberger 
127402742ec6SJoerg Sonnenberger int
pfsync_pack_state(u_int8_t action,struct pf_state * st,int flags)127570224baaSJan Lentfer pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
127602742ec6SJoerg Sonnenberger {
127770224baaSJan Lentfer 	struct ifnet *ifp = NULL;
127870224baaSJan Lentfer 	struct pfsync_softc *sc = pfsyncif;
127902742ec6SJoerg Sonnenberger 	struct pfsync_header *h, *h_net;
128002742ec6SJoerg Sonnenberger 	struct pfsync_state *sp = NULL;
128102742ec6SJoerg Sonnenberger 	struct pfsync_state_upd *up = NULL;
128202742ec6SJoerg Sonnenberger 	struct pfsync_state_del *dp = NULL;
1283c3c8c553SJan Lentfer 	int ret = 0;
128402742ec6SJoerg Sonnenberger 	u_int8_t i = 255, newaction = 0;
128502742ec6SJoerg Sonnenberger 
128670224baaSJan Lentfer 	if (sc == NULL)
128770224baaSJan Lentfer 		return (0);
128870224baaSJan Lentfer 	ifp = &sc->sc_if;
128970224baaSJan Lentfer 
129002742ec6SJoerg Sonnenberger 	/*
129102742ec6SJoerg Sonnenberger 	 * If a packet falls in the forest and there's nobody around to
129202742ec6SJoerg Sonnenberger 	 * hear, does it make a sound?
129302742ec6SJoerg Sonnenberger 	 */
129470224baaSJan Lentfer 	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
129570224baaSJan Lentfer 	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
129602742ec6SJoerg Sonnenberger 		/* Don't leave any stale pfsync packets hanging around. */
129702742ec6SJoerg Sonnenberger 		if (sc->sc_mbuf != NULL) {
129802742ec6SJoerg Sonnenberger 			m_freem(sc->sc_mbuf);
129902742ec6SJoerg Sonnenberger 			sc->sc_mbuf = NULL;
130002742ec6SJoerg Sonnenberger 			sc->sc_statep.s = NULL;
130102742ec6SJoerg Sonnenberger 		}
130202742ec6SJoerg Sonnenberger 		return (0);
130302742ec6SJoerg Sonnenberger 	}
130402742ec6SJoerg Sonnenberger 
130502742ec6SJoerg Sonnenberger 	if (action >= PFSYNC_ACT_MAX)
130602742ec6SJoerg Sonnenberger 		return (EINVAL);
130702742ec6SJoerg Sonnenberger 
1308c3c8c553SJan Lentfer 	crit_enter();
130902742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf == NULL) {
131002742ec6SJoerg Sonnenberger 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
131102742ec6SJoerg Sonnenberger 		    (void *)&sc->sc_statep.s)) == NULL) {
1312c3c8c553SJan Lentfer 			crit_exit();
131302742ec6SJoerg Sonnenberger 			return (ENOMEM);
131402742ec6SJoerg Sonnenberger 		}
131502742ec6SJoerg Sonnenberger 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
131602742ec6SJoerg Sonnenberger 	} else {
131702742ec6SJoerg Sonnenberger 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
131802742ec6SJoerg Sonnenberger 		if (h->action != action) {
131902742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
132002742ec6SJoerg Sonnenberger 			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
132102742ec6SJoerg Sonnenberger 			    (void *)&sc->sc_statep.s)) == NULL) {
1322c3c8c553SJan Lentfer 				crit_exit();
132302742ec6SJoerg Sonnenberger 				return (ENOMEM);
132402742ec6SJoerg Sonnenberger 			}
132502742ec6SJoerg Sonnenberger 			h = mtod(sc->sc_mbuf, struct pfsync_header *);
132602742ec6SJoerg Sonnenberger 		} else {
132702742ec6SJoerg Sonnenberger 			/*
132802742ec6SJoerg Sonnenberger 			 * If it's an update, look in the packet to see if
132902742ec6SJoerg Sonnenberger 			 * we already have an update for the state.
133002742ec6SJoerg Sonnenberger 			 */
133102742ec6SJoerg Sonnenberger 			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
133202742ec6SJoerg Sonnenberger 				struct pfsync_state *usp =
133302742ec6SJoerg Sonnenberger 				    (void *)((char *)h + PFSYNC_HDRLEN);
133402742ec6SJoerg Sonnenberger 
133502742ec6SJoerg Sonnenberger 				for (i = 0; i < h->count; i++) {
133602742ec6SJoerg Sonnenberger 					if (!memcmp(usp->id, &st->id,
133702742ec6SJoerg Sonnenberger 					    PFSYNC_ID_LEN) &&
133802742ec6SJoerg Sonnenberger 					    usp->creatorid == st->creatorid) {
133902742ec6SJoerg Sonnenberger 						sp = usp;
134002742ec6SJoerg Sonnenberger 						sp->updates++;
134102742ec6SJoerg Sonnenberger 						break;
134202742ec6SJoerg Sonnenberger 					}
134302742ec6SJoerg Sonnenberger 					usp++;
134402742ec6SJoerg Sonnenberger 				}
134502742ec6SJoerg Sonnenberger 			}
134602742ec6SJoerg Sonnenberger 		}
134702742ec6SJoerg Sonnenberger 	}
134802742ec6SJoerg Sonnenberger 
13493598cc14SSascha Wildner 	st->pfsync_time = mycpu->gd_time_seconds;
135002742ec6SJoerg Sonnenberger 
135102742ec6SJoerg Sonnenberger 	if (sp == NULL) {
135202742ec6SJoerg Sonnenberger 		/* not a "duplicate" update */
135302742ec6SJoerg Sonnenberger 		i = 255;
135402742ec6SJoerg Sonnenberger 		sp = sc->sc_statep.s++;
135502742ec6SJoerg Sonnenberger 		sc->sc_mbuf->m_pkthdr.len =
135602742ec6SJoerg Sonnenberger 		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
135702742ec6SJoerg Sonnenberger 		h->count++;
135802742ec6SJoerg Sonnenberger 		bzero(sp, sizeof(*sp));
135902742ec6SJoerg Sonnenberger 
1360ed1f0be2SJan Lentfer 		pfsync_state_export(sp, st);
136102742ec6SJoerg Sonnenberger 
136270224baaSJan Lentfer 		if (flags & PFSYNC_FLAG_STALE)
136370224baaSJan Lentfer 			sp->sync_flags |= PFSTATE_STALE;
1364ed1f0be2SJan Lentfer 	} else {
136502742ec6SJoerg Sonnenberger 		pf_state_peer_hton(&st->src, &sp->src);
136602742ec6SJoerg Sonnenberger 		pf_state_peer_hton(&st->dst, &sp->dst);
136702742ec6SJoerg Sonnenberger 
1368ed1f0be2SJan Lentfer 		if (st->expire <= time_second)
136902742ec6SJoerg Sonnenberger 			sp->expire = htonl(0);
137002742ec6SJoerg Sonnenberger 		else
1371ed1f0be2SJan Lentfer 			sp->expire = htonl(st->expire - time_second);
1372ed1f0be2SJan Lentfer 	}
137302742ec6SJoerg Sonnenberger 
137402742ec6SJoerg Sonnenberger 	/* do we need to build "compressed" actions for network transfer? */
137570224baaSJan Lentfer 	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
137602742ec6SJoerg Sonnenberger 		switch (action) {
137702742ec6SJoerg Sonnenberger 		case PFSYNC_ACT_UPD:
137802742ec6SJoerg Sonnenberger 			newaction = PFSYNC_ACT_UPD_C;
137902742ec6SJoerg Sonnenberger 			break;
138002742ec6SJoerg Sonnenberger 		case PFSYNC_ACT_DEL:
138102742ec6SJoerg Sonnenberger 			newaction = PFSYNC_ACT_DEL_C;
138202742ec6SJoerg Sonnenberger 			break;
138302742ec6SJoerg Sonnenberger 		default:
138402742ec6SJoerg Sonnenberger 			/* by default we just send the uncompressed states */
138502742ec6SJoerg Sonnenberger 			break;
138602742ec6SJoerg Sonnenberger 		}
138702742ec6SJoerg Sonnenberger 	}
138802742ec6SJoerg Sonnenberger 
138902742ec6SJoerg Sonnenberger 	if (newaction) {
139002742ec6SJoerg Sonnenberger 		if (sc->sc_mbuf_net == NULL) {
139102742ec6SJoerg Sonnenberger 			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
139202742ec6SJoerg Sonnenberger 			    (void *)&sc->sc_statep_net.s)) == NULL) {
1393c3c8c553SJan Lentfer 				crit_exit();
139402742ec6SJoerg Sonnenberger 				return (ENOMEM);
139502742ec6SJoerg Sonnenberger 			}
139602742ec6SJoerg Sonnenberger 		}
139702742ec6SJoerg Sonnenberger 		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
139802742ec6SJoerg Sonnenberger 
139902742ec6SJoerg Sonnenberger 		switch (newaction) {
140002742ec6SJoerg Sonnenberger 		case PFSYNC_ACT_UPD_C:
140102742ec6SJoerg Sonnenberger 			if (i != 255) {
140202742ec6SJoerg Sonnenberger 				up = (void *)((char *)h_net +
140302742ec6SJoerg Sonnenberger 				    PFSYNC_HDRLEN + (i * sizeof(*up)));
140402742ec6SJoerg Sonnenberger 				up->updates++;
140502742ec6SJoerg Sonnenberger 			} else {
140602742ec6SJoerg Sonnenberger 				h_net->count++;
140702742ec6SJoerg Sonnenberger 				sc->sc_mbuf_net->m_pkthdr.len =
140802742ec6SJoerg Sonnenberger 				    sc->sc_mbuf_net->m_len += sizeof(*up);
140902742ec6SJoerg Sonnenberger 				up = sc->sc_statep_net.u++;
141002742ec6SJoerg Sonnenberger 
141102742ec6SJoerg Sonnenberger 				bzero(up, sizeof(*up));
141202742ec6SJoerg Sonnenberger 				bcopy(&st->id, up->id, sizeof(up->id));
141302742ec6SJoerg Sonnenberger 				up->creatorid = st->creatorid;
141402742ec6SJoerg Sonnenberger 			}
141502742ec6SJoerg Sonnenberger 			up->timeout = st->timeout;
141602742ec6SJoerg Sonnenberger 			up->expire = sp->expire;
141702742ec6SJoerg Sonnenberger 			up->src = sp->src;
141802742ec6SJoerg Sonnenberger 			up->dst = sp->dst;
141902742ec6SJoerg Sonnenberger 			break;
142002742ec6SJoerg Sonnenberger 		case PFSYNC_ACT_DEL_C:
142102742ec6SJoerg Sonnenberger 			sc->sc_mbuf_net->m_pkthdr.len =
142202742ec6SJoerg Sonnenberger 			    sc->sc_mbuf_net->m_len += sizeof(*dp);
142302742ec6SJoerg Sonnenberger 			dp = sc->sc_statep_net.d++;
142402742ec6SJoerg Sonnenberger 			h_net->count++;
142502742ec6SJoerg Sonnenberger 
142602742ec6SJoerg Sonnenberger 			bzero(dp, sizeof(*dp));
142702742ec6SJoerg Sonnenberger 			bcopy(&st->id, dp->id, sizeof(dp->id));
142802742ec6SJoerg Sonnenberger 			dp->creatorid = st->creatorid;
142902742ec6SJoerg Sonnenberger 			break;
143002742ec6SJoerg Sonnenberger 		}
143102742ec6SJoerg Sonnenberger 	}
143202742ec6SJoerg Sonnenberger 
143302742ec6SJoerg Sonnenberger 	if (h->count == sc->sc_maxcount ||
143402742ec6SJoerg Sonnenberger 	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
143502742ec6SJoerg Sonnenberger 		ret = pfsync_sendout(sc);
143602742ec6SJoerg Sonnenberger 
1437c3c8c553SJan Lentfer 	crit_exit();
143802742ec6SJoerg Sonnenberger 	return (ret);
143902742ec6SJoerg Sonnenberger }
144002742ec6SJoerg Sonnenberger 
144102742ec6SJoerg Sonnenberger int
pfsync_request_update(struct pfsync_state_upd * up,struct in_addr * src)144202742ec6SJoerg Sonnenberger pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
144302742ec6SJoerg Sonnenberger {
144402742ec6SJoerg Sonnenberger 	struct pfsync_header *h;
144570224baaSJan Lentfer 	struct pfsync_softc *sc = pfsyncif;
144602742ec6SJoerg Sonnenberger 	struct pfsync_state_upd_req *rup;
1447cc6e5672SJoerg Sonnenberger 	int ret = 0;
144802742ec6SJoerg Sonnenberger 
144970224baaSJan Lentfer 	if (sc == NULL)
145070224baaSJan Lentfer 		return (0);
145170224baaSJan Lentfer 
145202742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf == NULL) {
145302742ec6SJoerg Sonnenberger 		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
145470224baaSJan Lentfer 		    (void *)&sc->sc_statep.s)) == NULL)
145502742ec6SJoerg Sonnenberger 			return (ENOMEM);
145602742ec6SJoerg Sonnenberger 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
145702742ec6SJoerg Sonnenberger 	} else {
145802742ec6SJoerg Sonnenberger 		h = mtod(sc->sc_mbuf, struct pfsync_header *);
145902742ec6SJoerg Sonnenberger 		if (h->action != PFSYNC_ACT_UREQ) {
146002742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
146102742ec6SJoerg Sonnenberger 			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
146270224baaSJan Lentfer 			    (void *)&sc->sc_statep.s)) == NULL)
146302742ec6SJoerg Sonnenberger 				return (ENOMEM);
146402742ec6SJoerg Sonnenberger 			h = mtod(sc->sc_mbuf, struct pfsync_header *);
146502742ec6SJoerg Sonnenberger 		}
146602742ec6SJoerg Sonnenberger 	}
146702742ec6SJoerg Sonnenberger 
146802742ec6SJoerg Sonnenberger 	if (src != NULL)
146902742ec6SJoerg Sonnenberger 		sc->sc_sendaddr = *src;
147002742ec6SJoerg Sonnenberger 	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
147102742ec6SJoerg Sonnenberger 	h->count++;
147202742ec6SJoerg Sonnenberger 	rup = sc->sc_statep.r++;
147302742ec6SJoerg Sonnenberger 	bzero(rup, sizeof(*rup));
147402742ec6SJoerg Sonnenberger 	if (up != NULL) {
147502742ec6SJoerg Sonnenberger 		bcopy(up->id, rup->id, sizeof(rup->id));
147602742ec6SJoerg Sonnenberger 		rup->creatorid = up->creatorid;
147702742ec6SJoerg Sonnenberger 	}
147802742ec6SJoerg Sonnenberger 
147902742ec6SJoerg Sonnenberger 	if (h->count == sc->sc_maxcount)
148002742ec6SJoerg Sonnenberger 		ret = pfsync_sendout(sc);
148102742ec6SJoerg Sonnenberger 
148202742ec6SJoerg Sonnenberger 	return (ret);
148302742ec6SJoerg Sonnenberger }
148402742ec6SJoerg Sonnenberger 
148502742ec6SJoerg Sonnenberger int
pfsync_clear_states(u_int32_t creatorid,char * ifname)148602742ec6SJoerg Sonnenberger pfsync_clear_states(u_int32_t creatorid, char *ifname)
148702742ec6SJoerg Sonnenberger {
148870224baaSJan Lentfer 	struct pfsync_softc *sc = pfsyncif;
148902742ec6SJoerg Sonnenberger 	struct pfsync_state_clr *cp;
1490c3c8c553SJan Lentfer 	int ret;
149102742ec6SJoerg Sonnenberger 
149270224baaSJan Lentfer 	if (sc == NULL)
149370224baaSJan Lentfer 		return (0);
149470224baaSJan Lentfer 
1495c3c8c553SJan Lentfer 	crit_enter();
149602742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf != NULL)
149702742ec6SJoerg Sonnenberger 		pfsync_sendout(sc);
149802742ec6SJoerg Sonnenberger 	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
149902742ec6SJoerg Sonnenberger 	    (void *)&sc->sc_statep.c)) == NULL) {
1500c3c8c553SJan Lentfer 		crit_exit();
150102742ec6SJoerg Sonnenberger 		return (ENOMEM);
150202742ec6SJoerg Sonnenberger 	}
150302742ec6SJoerg Sonnenberger 	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
150402742ec6SJoerg Sonnenberger 	cp = sc->sc_statep.c;
150502742ec6SJoerg Sonnenberger 	cp->creatorid = creatorid;
150602742ec6SJoerg Sonnenberger 	if (ifname != NULL)
150702742ec6SJoerg Sonnenberger 		strlcpy(cp->ifname, ifname, IFNAMSIZ);
150802742ec6SJoerg Sonnenberger 
150902742ec6SJoerg Sonnenberger 	ret = (pfsync_sendout(sc));
1510c3c8c553SJan Lentfer 	crit_exit();
151102742ec6SJoerg Sonnenberger 	return (ret);
151202742ec6SJoerg Sonnenberger }
151302742ec6SJoerg Sonnenberger 
151402742ec6SJoerg Sonnenberger void
pfsync_timeout(void * v)151502742ec6SJoerg Sonnenberger pfsync_timeout(void *v)
151602742ec6SJoerg Sonnenberger {
151702742ec6SJoerg Sonnenberger 	struct pfsync_softc *sc = v;
151802742ec6SJoerg Sonnenberger 
1519c3c8c553SJan Lentfer 	crit_enter();
152002742ec6SJoerg Sonnenberger 	pfsync_sendout(sc);
1521c3c8c553SJan Lentfer 	crit_exit();
152202742ec6SJoerg Sonnenberger }
152302742ec6SJoerg Sonnenberger 
152402742ec6SJoerg Sonnenberger void
pfsync_send_bus(struct pfsync_softc * sc,u_int8_t status)152502742ec6SJoerg Sonnenberger pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
152602742ec6SJoerg Sonnenberger {
152702742ec6SJoerg Sonnenberger 	struct pfsync_state_bus *bus;
152802742ec6SJoerg Sonnenberger 
152902742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf != NULL)
153002742ec6SJoerg Sonnenberger 		pfsync_sendout(sc);
153102742ec6SJoerg Sonnenberger 
153202742ec6SJoerg Sonnenberger 	if (pfsync_sync_ok &&
153302742ec6SJoerg Sonnenberger 	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
153402742ec6SJoerg Sonnenberger 	    (void *)&sc->sc_statep.b)) != NULL) {
153502742ec6SJoerg Sonnenberger 		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
153602742ec6SJoerg Sonnenberger 		bus = sc->sc_statep.b;
153702742ec6SJoerg Sonnenberger 		bus->creatorid = pf_status.hostid;
153802742ec6SJoerg Sonnenberger 		bus->status = status;
1539c3c8c553SJan Lentfer 		bus->endtime = htonl(mycpu->gd_time_seconds - sc->sc_ureq_received);
154002742ec6SJoerg Sonnenberger 		pfsync_sendout(sc);
154102742ec6SJoerg Sonnenberger 	}
154202742ec6SJoerg Sonnenberger }
154302742ec6SJoerg Sonnenberger 
154402742ec6SJoerg Sonnenberger void
pfsync_bulk_update(void * v)154502742ec6SJoerg Sonnenberger pfsync_bulk_update(void *v)
154602742ec6SJoerg Sonnenberger {
154702742ec6SJoerg Sonnenberger 	struct pfsync_softc *sc = v;
1548c3c8c553SJan Lentfer 	int i = 0;
15493a0038bfSMatthew Dillon 	int cpu;
155002742ec6SJoerg Sonnenberger 	struct pf_state *state;
155102742ec6SJoerg Sonnenberger 
15522a7a2b1cSJan Lentfer 	ASSERT_LWKT_TOKEN_HELD(&pf_token);
15532a7a2b1cSJan Lentfer 
1554c3c8c553SJan Lentfer 	crit_enter();
155502742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf != NULL)
155602742ec6SJoerg Sonnenberger 		pfsync_sendout(sc);
155702742ec6SJoerg Sonnenberger 
155802742ec6SJoerg Sonnenberger 	/*
155902742ec6SJoerg Sonnenberger 	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
156002742ec6SJoerg Sonnenberger 	 * been sent since the latest request was made.
156102742ec6SJoerg Sonnenberger 	 */
156270224baaSJan Lentfer 	state = sc->sc_bulk_send_next;
15633a0038bfSMatthew Dillon 	cpu = sc->sc_bulk_send_cpu;
156470224baaSJan Lentfer 	if (state)
156570224baaSJan Lentfer 		do {
156670224baaSJan Lentfer 			/* send state update if syncable and not already sent */
156770224baaSJan Lentfer 			if (!state->sync_flags
156870224baaSJan Lentfer 			    && state->timeout < PFTM_MAX
156970224baaSJan Lentfer 			    && state->pfsync_time <= sc->sc_ureq_received) {
157070224baaSJan Lentfer 				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
157170224baaSJan Lentfer 				i++;
157270224baaSJan Lentfer 			}
157370224baaSJan Lentfer 
157470224baaSJan Lentfer 			/* figure next state to send */
1575315a7da3SJan Lentfer 			state = TAILQ_NEXT(state, entry_list);
157670224baaSJan Lentfer 
157770224baaSJan Lentfer 			/* wrap to start of list if we hit the end */
15783a0038bfSMatthew Dillon 			if (state == NULL) {
15793a0038bfSMatthew Dillon 				if (++cpu >= ncpus)
15803a0038bfSMatthew Dillon 					cpu = 0;
15813a0038bfSMatthew Dillon 				state = TAILQ_FIRST(&state_list[cpu]);
15823a0038bfSMatthew Dillon 			}
158370224baaSJan Lentfer 		} while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
15843a0038bfSMatthew Dillon 		    cpu != sc->sc_bulk_terminator_cpu &&
158570224baaSJan Lentfer 		    state != sc->sc_bulk_terminator);
158670224baaSJan Lentfer 
15873a0038bfSMatthew Dillon 	if (state == NULL || (cpu == sc->sc_bulk_terminator_cpu &&
15883a0038bfSMatthew Dillon 			      state == sc->sc_bulk_terminator)) {
158902742ec6SJoerg Sonnenberger 		/* we're done */
159002742ec6SJoerg Sonnenberger 		pfsync_send_bus(sc, PFSYNC_BUS_END);
159102742ec6SJoerg Sonnenberger 		sc->sc_ureq_received = 0;
159270224baaSJan Lentfer 		sc->sc_bulk_send_next = NULL;
159370224baaSJan Lentfer 		sc->sc_bulk_terminator = NULL;
15943a0038bfSMatthew Dillon 		sc->sc_bulk_send_cpu = 0;
15953a0038bfSMatthew Dillon 		sc->sc_bulk_terminator_cpu = 0;
15962a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
1597c3c8c553SJan Lentfer 		callout_stop(&sc->sc_bulk_tmo);
15982a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
159902742ec6SJoerg Sonnenberger 		if (pf_status.debug >= PF_DEBUG_MISC)
1600c3c8c553SJan Lentfer 			kprintf("pfsync: bulk update complete\n");
160102742ec6SJoerg Sonnenberger 	} else {
160202742ec6SJoerg Sonnenberger 		/* look again for more in a bit */
16032a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
1604c3c8c553SJan Lentfer 		callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1605c3c8c553SJan Lentfer 			    LIST_FIRST(&pfsync_list));
16062a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
160770224baaSJan Lentfer 		sc->sc_bulk_send_next = state;
16083a0038bfSMatthew Dillon 		sc->sc_bulk_send_cpu = cpu;
160902742ec6SJoerg Sonnenberger 	}
161002742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf != NULL)
161102742ec6SJoerg Sonnenberger 		pfsync_sendout(sc);
1612c3c8c553SJan Lentfer 	crit_exit();
161302742ec6SJoerg Sonnenberger }
161402742ec6SJoerg Sonnenberger 
161502742ec6SJoerg Sonnenberger void
pfsync_bulkfail(void * v)161602742ec6SJoerg Sonnenberger pfsync_bulkfail(void *v)
161702742ec6SJoerg Sonnenberger {
161802742ec6SJoerg Sonnenberger 	struct pfsync_softc *sc = v;
1619c3c8c553SJan Lentfer 	int error;
162002742ec6SJoerg Sonnenberger 
16212a7a2b1cSJan Lentfer 	ASSERT_LWKT_TOKEN_HELD(&pf_token);
16222a7a2b1cSJan Lentfer 
162302742ec6SJoerg Sonnenberger 	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
162402742ec6SJoerg Sonnenberger 		/* Try again in a bit */
16252a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
1626c3c8c553SJan Lentfer 		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1627c3c8c553SJan Lentfer 		    LIST_FIRST(&pfsync_list));
16282a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
1629c3c8c553SJan Lentfer 		crit_enter();
163070224baaSJan Lentfer 		error = pfsync_request_update(NULL, NULL);
163170224baaSJan Lentfer 		if (error == ENOMEM) {
163270224baaSJan Lentfer 			if (pf_status.debug >= PF_DEBUG_MISC)
1633c3c8c553SJan Lentfer 				kprintf("pfsync: cannot allocate mbufs for "
163470224baaSJan Lentfer 				    "bulk update\n");
163570224baaSJan Lentfer 		} else
163602742ec6SJoerg Sonnenberger 			pfsync_sendout(sc);
1637c3c8c553SJan Lentfer 		crit_exit();
163802742ec6SJoerg Sonnenberger 	} else {
163902742ec6SJoerg Sonnenberger 		/* Pretend like the transfer was ok */
164002742ec6SJoerg Sonnenberger 		sc->sc_ureq_sent = 0;
164102742ec6SJoerg Sonnenberger 		sc->sc_bulk_tries = 0;
16422b00f643SSascha Wildner #ifdef CARP
164370224baaSJan Lentfer 		if (!pfsync_sync_ok)
164470224baaSJan Lentfer 			carp_group_demote_adj(&sc->sc_if, -1);
164570224baaSJan Lentfer #endif
164602742ec6SJoerg Sonnenberger 		pfsync_sync_ok = 1;
164702742ec6SJoerg Sonnenberger 		if (pf_status.debug >= PF_DEBUG_MISC)
1648c3c8c553SJan Lentfer 			kprintf("pfsync: failed to receive "
164902742ec6SJoerg Sonnenberger 			    "bulk update status\n");
16502a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
1651c3c8c553SJan Lentfer 		callout_stop(&sc->sc_bulkfail_tmo);
16522a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
165302742ec6SJoerg Sonnenberger 	}
165402742ec6SJoerg Sonnenberger }
165502742ec6SJoerg Sonnenberger 
1656c4705c47SSepherosa Ziehau static void
pfsync_sendout_handler(netmsg_t nmsg)1657c4705c47SSepherosa Ziehau pfsync_sendout_handler(netmsg_t nmsg)
1658c4705c47SSepherosa Ziehau {
1659c4705c47SSepherosa Ziehau 	struct netmsg_genpkt *msg = (struct netmsg_genpkt *)nmsg;
1660c4705c47SSepherosa Ziehau 
1661c4705c47SSepherosa Ziehau 	pfsync_sendout_mbuf(msg->arg1, msg->m);
1662c4705c47SSepherosa Ziehau }
1663c4705c47SSepherosa Ziehau 
166402742ec6SJoerg Sonnenberger int
pfsync_sendout(struct pfsync_softc * sc)16653bf25ce1SSascha Wildner pfsync_sendout(struct pfsync_softc *sc)
166602742ec6SJoerg Sonnenberger {
16672b00f643SSascha Wildner #if NBPF > 0
166802742ec6SJoerg Sonnenberger 	struct ifnet *ifp = &sc->sc_if;
166970224baaSJan Lentfer #endif
167002742ec6SJoerg Sonnenberger 	struct mbuf *m;
1671c4705c47SSepherosa Ziehau 	struct netmsg_genpkt *msg;
167202742ec6SJoerg Sonnenberger 
16732a7a2b1cSJan Lentfer 	ASSERT_LWKT_TOKEN_HELD(&pf_token);
16742a7a2b1cSJan Lentfer 
16752a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
1676c3c8c553SJan Lentfer 	callout_stop(&sc->sc_tmo);
16772a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
167802742ec6SJoerg Sonnenberger 
167902742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf == NULL)
168002742ec6SJoerg Sonnenberger 		return (0);
168102742ec6SJoerg Sonnenberger 	m = sc->sc_mbuf;
168202742ec6SJoerg Sonnenberger 	sc->sc_mbuf = NULL;
168302742ec6SJoerg Sonnenberger 	sc->sc_statep.s = NULL;
168402742ec6SJoerg Sonnenberger 
16852b00f643SSascha Wildner #if NBPF > 0
16862a7a2b1cSJan Lentfer 	if (ifp->if_bpf) {
1687fda7d388SSepherosa Ziehau 		bpf_gettoken();
1688fda7d388SSepherosa Ziehau 		if (ifp->if_bpf)
16892b00f643SSascha Wildner 			bpf_mtap(ifp->if_bpf, m);
1690fda7d388SSepherosa Ziehau 		bpf_reltoken();
16912a7a2b1cSJan Lentfer 	}
169270224baaSJan Lentfer #endif
169302742ec6SJoerg Sonnenberger 
169402742ec6SJoerg Sonnenberger 	if (sc->sc_mbuf_net) {
169502742ec6SJoerg Sonnenberger 		m_freem(m);
169602742ec6SJoerg Sonnenberger 		m = sc->sc_mbuf_net;
169702742ec6SJoerg Sonnenberger 		sc->sc_mbuf_net = NULL;
169802742ec6SJoerg Sonnenberger 		sc->sc_statep_net.s = NULL;
169902742ec6SJoerg Sonnenberger 	}
170002742ec6SJoerg Sonnenberger 
1701c4705c47SSepherosa Ziehau 	msg = &m->m_hdr.mh_genmsg;
1702c4705c47SSepherosa Ziehau 	netmsg_init(&msg->base, NULL, &netisr_apanic_rport, 0,
1703c4705c47SSepherosa Ziehau 	    pfsync_sendout_handler);
1704c4705c47SSepherosa Ziehau 	msg->m = m;
1705c4705c47SSepherosa Ziehau 	msg->arg1 = sc;
1706c4705c47SSepherosa Ziehau 	netisr_sendmsg(&msg->base, 0);
1707c4705c47SSepherosa Ziehau 
1708c4705c47SSepherosa Ziehau 	return (0);
170970224baaSJan Lentfer }
171002742ec6SJoerg Sonnenberger 
171170224baaSJan Lentfer int
pfsync_sendout_mbuf(struct pfsync_softc * sc,struct mbuf * m)171270224baaSJan Lentfer pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
171370224baaSJan Lentfer {
171470224baaSJan Lentfer 	struct sockaddr sa;
171570224baaSJan Lentfer 	struct ip *ip;
171670224baaSJan Lentfer 
171770224baaSJan Lentfer 	if (sc->sc_sync_ifp ||
171870224baaSJan Lentfer 	    sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1719c3c8c553SJan Lentfer 		M_PREPEND(m, sizeof(struct ip), M_WAITOK);
172002742ec6SJoerg Sonnenberger 		ip = mtod(m, struct ip *);
172102742ec6SJoerg Sonnenberger 		ip->ip_v = IPVERSION;
172202742ec6SJoerg Sonnenberger 		ip->ip_hl = sizeof(*ip) >> 2;
172302742ec6SJoerg Sonnenberger 		ip->ip_tos = IPTOS_LOWDELAY;
172470224baaSJan Lentfer 		ip->ip_len = htons(m->m_pkthdr.len);
172570224baaSJan Lentfer 		ip->ip_id = htons(ip_randomid());
172670224baaSJan Lentfer 		ip->ip_off = htons(IP_DF);
172702742ec6SJoerg Sonnenberger 		ip->ip_ttl = PFSYNC_DFLTTL;
172802742ec6SJoerg Sonnenberger 		ip->ip_p = IPPROTO_PFSYNC;
172902742ec6SJoerg Sonnenberger 		ip->ip_sum = 0;
173002742ec6SJoerg Sonnenberger 
173102742ec6SJoerg Sonnenberger 		bzero(&sa, sizeof(sa));
173270224baaSJan Lentfer 		ip->ip_src.s_addr = INADDR_ANY;
173302742ec6SJoerg Sonnenberger 
173470224baaSJan Lentfer 		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
173502742ec6SJoerg Sonnenberger 			m->m_flags |= M_MCAST;
173602742ec6SJoerg Sonnenberger 		ip->ip_dst = sc->sc_sendaddr;
173770224baaSJan Lentfer 		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
173802742ec6SJoerg Sonnenberger 
173902742ec6SJoerg Sonnenberger 		pfsyncstats.pfsyncs_opackets++;
174002742ec6SJoerg Sonnenberger 
174102742ec6SJoerg Sonnenberger 		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
174202742ec6SJoerg Sonnenberger 			pfsyncstats.pfsyncs_oerrors++;
174302742ec6SJoerg Sonnenberger 	} else
174402742ec6SJoerg Sonnenberger 		m_freem(m);
174502742ec6SJoerg Sonnenberger 
174602742ec6SJoerg Sonnenberger 	return (0);
174702742ec6SJoerg Sonnenberger }
174802742ec6SJoerg Sonnenberger 
17492a7a2b1cSJan Lentfer static int
pfsync_modevent(module_t mod,int type,void * data)17502a7a2b1cSJan Lentfer pfsync_modevent(module_t mod, int type, void *data)
17512a7a2b1cSJan Lentfer {
17522a7a2b1cSJan Lentfer 	int error = 0;
17532a7a2b1cSJan Lentfer 
1754ed1f0be2SJan Lentfer 	struct pfsync_softc	*pfs_if, *tmp;
1755ed1f0be2SJan Lentfer 
17562a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
17572a7a2b1cSJan Lentfer 
17582a7a2b1cSJan Lentfer 	switch (type) {
17592a7a2b1cSJan Lentfer 	case MOD_LOAD:
17602a7a2b1cSJan Lentfer 		LIST_INIT(&pfsync_list);
17612a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
17622a7a2b1cSJan Lentfer 		if_clone_attach(&pfsync_cloner);
17632a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
1764ed1f0be2SJan Lentfer 		/* Override the function pointer for pf_ioctl.c */
17652a7a2b1cSJan Lentfer 		break;
17662a7a2b1cSJan Lentfer 
17672a7a2b1cSJan Lentfer 	case MOD_UNLOAD:
17682a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
17692a7a2b1cSJan Lentfer 		if_clone_detach(&pfsync_cloner);
17702a7a2b1cSJan Lentfer 		lwkt_gettoken(&pf_token);
1771ed1f0be2SJan Lentfer 		LIST_FOREACH_MUTABLE(pfs_if, &pfsync_list, sc_next, tmp) {
1772ed1f0be2SJan Lentfer 			pfsync_clone_destroy(&pfs_if->sc_if);
1773ed1f0be2SJan Lentfer 		}
17742a7a2b1cSJan Lentfer 		break;
17752a7a2b1cSJan Lentfer 
17762a7a2b1cSJan Lentfer 	default:
17772a7a2b1cSJan Lentfer 		error = EINVAL;
17782a7a2b1cSJan Lentfer 		break;
17792a7a2b1cSJan Lentfer 	}
17802a7a2b1cSJan Lentfer 
17812a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
17822a7a2b1cSJan Lentfer 	return error;
17832a7a2b1cSJan Lentfer }
17842a7a2b1cSJan Lentfer 
17852a7a2b1cSJan Lentfer static moduledata_t pfsync_mod = {
17862a7a2b1cSJan Lentfer 	"pfsync",
17872a7a2b1cSJan Lentfer 	pfsync_modevent,
17882a7a2b1cSJan Lentfer 	0
17892a7a2b1cSJan Lentfer };
17902a7a2b1cSJan Lentfer 
1791ed1f0be2SJan Lentfer #define PFSYNC_MODVER 44
17922a7a2b1cSJan Lentfer 
17932a7a2b1cSJan Lentfer DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
17942a7a2b1cSJan Lentfer MODULE_VERSION(pfsync, PFSYNC_MODVER);
1795c8f430baSAaron LI MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER);
17962a7a2b1cSJan Lentfer 
1797ef15d469SSepherosa Ziehau static void
pfsync_in_addmulti_dispatch(netmsg_t nmsg)1798ef15d469SSepherosa Ziehau pfsync_in_addmulti_dispatch(netmsg_t nmsg)
1799ef15d469SSepherosa Ziehau {
1800ef15d469SSepherosa Ziehau 	struct lwkt_msg *lmsg = &nmsg->lmsg;
1801ef15d469SSepherosa Ziehau 	struct ifnet *ifp = lmsg->u.ms_resultp;
1802ef15d469SSepherosa Ziehau 	struct in_addr addr;
180302742ec6SJoerg Sonnenberger 
1804ef15d469SSepherosa Ziehau 	addr.s_addr = INADDR_PFSYNC_GROUP;
1805ef15d469SSepherosa Ziehau 	lmsg->u.ms_resultp = in_addmulti(&addr, ifp);
180602742ec6SJoerg Sonnenberger 
1807ef15d469SSepherosa Ziehau 	lwkt_replymsg(lmsg, 0);
1808ef15d469SSepherosa Ziehau }
1809ef15d469SSepherosa Ziehau 
1810ef15d469SSepherosa Ziehau static struct in_multi *
pfsync_in_addmulti(struct ifnet * ifp)1811ef15d469SSepherosa Ziehau pfsync_in_addmulti(struct ifnet *ifp)
1812ef15d469SSepherosa Ziehau {
1813ef15d469SSepherosa Ziehau 	struct netmsg_base nmsg;
1814ef15d469SSepherosa Ziehau 	struct lwkt_msg *lmsg = &nmsg.lmsg;
1815ef15d469SSepherosa Ziehau 
1816ef15d469SSepherosa Ziehau 	netmsg_init(&nmsg, NULL, &curthread->td_msgport, 0,
1817ef15d469SSepherosa Ziehau 	    pfsync_in_addmulti_dispatch);
1818ef15d469SSepherosa Ziehau 	lmsg->u.ms_resultp = ifp;
1819ef15d469SSepherosa Ziehau 
1820ef15d469SSepherosa Ziehau 	lwkt_domsg(netisr_cpuport(0), lmsg, 0);
1821ef15d469SSepherosa Ziehau 	return lmsg->u.ms_resultp;
1822ef15d469SSepherosa Ziehau }
1823ef15d469SSepherosa Ziehau 
1824ef15d469SSepherosa Ziehau static void
pfsync_in_delmulti_dispatch(netmsg_t nmsg)1825ef15d469SSepherosa Ziehau pfsync_in_delmulti_dispatch(netmsg_t nmsg)
1826ef15d469SSepherosa Ziehau {
1827ef15d469SSepherosa Ziehau 	struct lwkt_msg *lmsg = &nmsg->lmsg;
1828ef15d469SSepherosa Ziehau 
1829ef15d469SSepherosa Ziehau 	in_delmulti(lmsg->u.ms_resultp);
1830ef15d469SSepherosa Ziehau 	lwkt_replymsg(lmsg, 0);
1831ef15d469SSepherosa Ziehau }
1832ef15d469SSepherosa Ziehau 
1833ef15d469SSepherosa Ziehau static void
pfsync_in_delmulti(struct in_multi * inm)1834ef15d469SSepherosa Ziehau pfsync_in_delmulti(struct in_multi *inm)
1835ef15d469SSepherosa Ziehau {
1836ef15d469SSepherosa Ziehau 	struct netmsg_base nmsg;
1837ef15d469SSepherosa Ziehau 	struct lwkt_msg *lmsg = &nmsg.lmsg;
1838ef15d469SSepherosa Ziehau 
1839ef15d469SSepherosa Ziehau 	netmsg_init(&nmsg, NULL, &curthread->td_msgport, 0,
1840ef15d469SSepherosa Ziehau 	    pfsync_in_delmulti_dispatch);
1841ef15d469SSepherosa Ziehau 	lmsg->u.ms_resultp = inm;
1842ef15d469SSepherosa Ziehau 
1843ef15d469SSepherosa Ziehau 	lwkt_domsg(netisr_cpuport(0), lmsg, 0);
1844ef15d469SSepherosa Ziehau }
1845