if_pfsync.c revision 228814
1/*	$OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $	*/
2
3/*
4 * Copyright (c) 2002 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright (c) 2009 David Gwynne <dlg@openbsd.org>
31 *
32 * Permission to use, copy, modify, and distribute this software for any
33 * purpose with or without fee is hereby granted, provided that the above
34 * copyright notice and this permission notice appear in all copies.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
37 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
38 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
39 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
41 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
42 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 */
44
45/*
46 * Revisions picked from OpenBSD after revision 1.110 import:
47 * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates
48 */
49
50#ifdef __FreeBSD__
51#include "opt_inet.h"
52#include "opt_inet6.h"
53#include "opt_pf.h"
54
55#include <sys/cdefs.h>
56__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 228814 2011-12-22 18:56:27Z glebius $");
57
58#define	NBPFILTER	1
59
60#ifdef DEV_PFSYNC
61#define	NPFSYNC		DEV_PFSYNC
62#else
63#define	NPFSYNC		0
64#endif
65#endif /* __FreeBSD__ */
66
67#include <sys/param.h>
68#include <sys/kernel.h>
69#ifdef __FreeBSD__
70#include <sys/bus.h>
71#include <sys/interrupt.h>
72#include <sys/priv.h>
73#endif
74#include <sys/proc.h>
75#include <sys/systm.h>
76#include <sys/time.h>
77#include <sys/mbuf.h>
78#include <sys/socket.h>
79#ifdef __FreeBSD__
80#include <sys/endian.h>
81#include <sys/malloc.h>
82#include <sys/module.h>
83#include <sys/sockio.h>
84#include <sys/taskqueue.h>
85#include <sys/lock.h>
86#include <sys/mutex.h>
87#else
88#include <sys/ioctl.h>
89#include <sys/timeout.h>
90#endif
91#include <sys/sysctl.h>
92#ifndef __FreeBSD__
93#include <sys/pool.h>
94#endif
95
96#include <net/if.h>
97#ifdef __FreeBSD__
98#include <net/if_clone.h>
99#endif
100#include <net/if_types.h>
101#include <net/route.h>
102#include <net/bpf.h>
103#include <net/netisr.h>
104#ifdef __FreeBSD__
105#include <net/vnet.h>
106#endif
107
108#include <netinet/in.h>
109#include <netinet/if_ether.h>
110#include <netinet/tcp.h>
111#include <netinet/tcp_seq.h>
112
113#ifdef	INET
114#include <netinet/in_systm.h>
115#include <netinet/in_var.h>
116#include <netinet/ip.h>
117#include <netinet/ip_var.h>
118#endif
119
120#ifdef INET6
121#include <netinet6/nd6.h>
122#endif /* INET6 */
123
124#ifdef __FreeBSD__
125#include <netinet/ip_carp.h>
126#else
127#include "carp.h"
128#if NCARP > 0
129#include <netinet/ip_carp.h>
130#endif
131#endif
132
133#include <net/pfvar.h>
134#include <net/if_pfsync.h>
135
136#ifndef __FreeBSD__
137#include "bpfilter.h"
138#include "pfsync.h"
139#endif
140
141#define PFSYNC_MINPKT ( \
142	sizeof(struct ip) + \
143	sizeof(struct pfsync_header) + \
144	sizeof(struct pfsync_subheader) + \
145	sizeof(struct pfsync_eof))
146
147struct pfsync_pkt {
148	struct ip *ip;
149	struct in_addr src;
150	u_int8_t flags;
151};
152
153int	pfsync_input_hmac(struct mbuf *, int);
154
155int	pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *,
156	    struct pfsync_state_peer *);
157
158int	pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int);
159int	pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int);
160int	pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int);
161int	pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int);
162int	pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int);
163int	pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int);
164int	pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int);
165int	pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int);
166int	pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int);
167int	pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int);
168int	pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int);
169
170int	pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int);
171
172int	(*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = {
173	pfsync_in_clr,			/* PFSYNC_ACT_CLR */
174	pfsync_in_ins,			/* PFSYNC_ACT_INS */
175	pfsync_in_iack,			/* PFSYNC_ACT_INS_ACK */
176	pfsync_in_upd,			/* PFSYNC_ACT_UPD */
177	pfsync_in_upd_c,		/* PFSYNC_ACT_UPD_C */
178	pfsync_in_ureq,			/* PFSYNC_ACT_UPD_REQ */
179	pfsync_in_del,			/* PFSYNC_ACT_DEL */
180	pfsync_in_del_c,		/* PFSYNC_ACT_DEL_C */
181	pfsync_in_error,		/* PFSYNC_ACT_INS_F */
182	pfsync_in_error,		/* PFSYNC_ACT_DEL_F */
183	pfsync_in_bus,			/* PFSYNC_ACT_BUS */
184	pfsync_in_tdb,			/* PFSYNC_ACT_TDB */
185	pfsync_in_eof			/* PFSYNC_ACT_EOF */
186};
187
188struct pfsync_q {
189	int		(*write)(struct pf_state *, struct mbuf *, int);
190	size_t		len;
191	u_int8_t	action;
192};
193
194/* we have one of these for every PFSYNC_S_ */
195int	pfsync_out_state(struct pf_state *, struct mbuf *, int);
196int	pfsync_out_iack(struct pf_state *, struct mbuf *, int);
197int	pfsync_out_upd_c(struct pf_state *, struct mbuf *, int);
198int	pfsync_out_del(struct pf_state *, struct mbuf *, int);
199
200struct pfsync_q pfsync_qs[] = {
201	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_INS },
202	{ pfsync_out_iack,  sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
203	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_UPD },
204	{ pfsync_out_upd_c, sizeof(struct pfsync_upd_c),   PFSYNC_ACT_UPD_C },
205	{ pfsync_out_del,   sizeof(struct pfsync_del_c),   PFSYNC_ACT_DEL_C }
206};
207
208void	pfsync_q_ins(struct pf_state *, int);
209void	pfsync_q_del(struct pf_state *);
210
211struct pfsync_upd_req_item {
212	TAILQ_ENTRY(pfsync_upd_req_item)	ur_entry;
213	struct pfsync_upd_req			ur_msg;
214};
215TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item);
216
217struct pfsync_deferral {
218	TAILQ_ENTRY(pfsync_deferral)		 pd_entry;
219	struct pf_state				*pd_st;
220	struct mbuf				*pd_m;
221#ifdef __FreeBSD__
222	struct callout				 pd_tmo;
223#else
224	struct timeout				 pd_tmo;
225#endif
226};
227TAILQ_HEAD(pfsync_deferrals, pfsync_deferral);
228
229#define PFSYNC_PLSIZE	MAX(sizeof(struct pfsync_upd_req_item), \
230			    sizeof(struct pfsync_deferral))
231
232#ifdef notyet
233int	pfsync_out_tdb(struct tdb *, struct mbuf *, int);
234#endif
235
236struct pfsync_softc {
237#ifdef __FreeBSD__
238	struct ifnet		*sc_ifp;
239#else
240	struct ifnet		 sc_if;
241#endif
242	struct ifnet		*sc_sync_if;
243
244#ifdef __FreeBSD__
245	uma_zone_t		 sc_pool;
246#else
247	struct pool		 sc_pool;
248#endif
249
250	struct ip_moptions	 sc_imo;
251
252	struct in_addr		 sc_sync_peer;
253	u_int8_t		 sc_maxupdates;
254#ifdef __FreeBSD__
255	int			 pfsync_sync_ok;
256#endif
257
258	struct ip		 sc_template;
259
260	struct pf_state_queue	 sc_qs[PFSYNC_S_COUNT];
261	size_t			 sc_len;
262
263	struct pfsync_upd_reqs	 sc_upd_req_list;
264
265	struct pfsync_deferrals	 sc_deferrals;
266	u_int			 sc_deferred;
267
268	void			*sc_plus;
269	size_t			 sc_pluslen;
270
271	u_int32_t		 sc_ureq_sent;
272	int			 sc_bulk_tries;
273#ifdef __FreeBSD__
274	struct callout		 sc_bulkfail_tmo;
275#else
276	struct timeout		 sc_bulkfail_tmo;
277#endif
278
279	u_int32_t		 sc_ureq_received;
280	struct pf_state		*sc_bulk_next;
281	struct pf_state		*sc_bulk_last;
282#ifdef __FreeBSD__
283	struct callout		 sc_bulk_tmo;
284#else
285	struct timeout		 sc_bulk_tmo;
286#endif
287
288	TAILQ_HEAD(, tdb)	 sc_tdb_q;
289
290#ifdef __FreeBSD__
291	struct callout		 sc_tmo;
292#else
293	struct timeout		 sc_tmo;
294#endif
295#ifdef __FreeBSD__
296	eventhandler_tag	 sc_detachtag;
297#endif
298
299};
300
301#ifdef __FreeBSD__
302static VNET_DEFINE(struct pfsync_softc	*, pfsyncif) = NULL;
303#define	V_pfsyncif		VNET(pfsyncif)
304
305static VNET_DEFINE(struct pfsyncstats, pfsyncstats);
306#define	V_pfsyncstats		VNET(pfsyncstats)
307static VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW;
308#define	V_pfsync_carp_adj	VNET(pfsync_carp_adj)
309
310SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC");
311SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW,
312    &VNET_NAME(pfsyncstats), pfsyncstats,
313    "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
314SYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW,
315    &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment");
316#else
317struct pfsync_softc	*pfsyncif = NULL;
318struct pfsyncstats	 pfsyncstats;
319#define	V_pfsyncstats	 pfsyncstats
320#endif
321
322#ifdef __FreeBSD__
323static void	pfsyncintr(void *);
324struct pfsync_swi {
325	void *	pfsync_swi_cookie;
326};
327static struct pfsync_swi	 pfsync_swi;
328#define	schednetisr(p)	swi_sched(pfsync_swi.pfsync_swi_cookie, 0)
329#define	NETISR_PFSYNC
330#endif
331
332void	pfsyncattach(int);
333#ifdef __FreeBSD__
334int	pfsync_clone_create(struct if_clone *, int, caddr_t);
335void	pfsync_clone_destroy(struct ifnet *);
336#else
337int	pfsync_clone_create(struct if_clone *, int);
338int	pfsync_clone_destroy(struct ifnet *);
339#endif
340int	pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
341	    struct pf_state_peer *);
342void	pfsync_update_net_tdb(struct pfsync_tdb *);
343int	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
344#ifdef __FreeBSD__
345	    struct route *);
346#else
347	    struct rtentry *);
348#endif
349int	pfsyncioctl(struct ifnet *, u_long, caddr_t);
350void	pfsyncstart(struct ifnet *);
351
352struct mbuf *pfsync_if_dequeue(struct ifnet *);
353struct mbuf *pfsync_get_mbuf(struct pfsync_softc *);
354
355void	pfsync_deferred(struct pf_state *, int);
356void	pfsync_undefer(struct pfsync_deferral *, int);
357void	pfsync_defer_tmo(void *);
358
359void	pfsync_request_update(u_int32_t, u_int64_t);
360void	pfsync_update_state_req(struct pf_state *);
361
362void	pfsync_drop(struct pfsync_softc *);
363void	pfsync_sendout(void);
364void	pfsync_send_plus(void *, size_t);
365int	pfsync_tdb_sendout(struct pfsync_softc *);
366int	pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
367void	pfsync_timeout(void *);
368void	pfsync_tdb_timeout(void *);
369void	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
370
371void	pfsync_bulk_start(void);
372void	pfsync_bulk_status(u_int8_t);
373void	pfsync_bulk_update(void *);
374void	pfsync_bulk_fail(void *);
375
376#ifdef __FreeBSD__
377void	pfsync_ifdetach(void *, struct ifnet *);
378
379/* XXX: ugly */
380#define	betoh64		(unsigned long long)be64toh
381#define	timeout_del	callout_stop
382#endif
383
384#define PFSYNC_MAX_BULKTRIES	12
385#ifndef __FreeBSD__
386int	pfsync_sync_ok;
387#endif
388
389#ifdef __FreeBSD__
390IFC_SIMPLE_DECLARE(pfsync, 1);
391#else
392struct if_clone	pfsync_cloner =
393    IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
394#endif
395
396void
397pfsyncattach(int npfsync)
398{
399	if_clone_attach(&pfsync_cloner);
400}
401int
402#ifdef __FreeBSD__
403pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param)
404#else
405pfsync_clone_create(struct if_clone *ifc, int unit)
406#endif
407{
408	struct pfsync_softc *sc;
409	struct ifnet *ifp;
410	int q;
411
412	if (unit != 0)
413		return (EINVAL);
414
415#ifndef __FreeBSD__
416	pfsync_sync_ok = 1;
417#endif
418
419	sc = malloc(sizeof(struct pfsync_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
420	if (sc == NULL)
421		return (ENOMEM);
422
423	for (q = 0; q < PFSYNC_S_COUNT; q++)
424		TAILQ_INIT(&sc->sc_qs[q]);
425
426#ifdef __FreeBSD__
427	sc->pfsync_sync_ok = 1;
428	sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE,
429			NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
430	if (sc->sc_pool == NULL) {
431		free(sc, M_DEVBUF);
432		return (ENOMEM);
433	}
434#else
435	pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL);
436#endif
437	TAILQ_INIT(&sc->sc_upd_req_list);
438	TAILQ_INIT(&sc->sc_deferrals);
439	sc->sc_deferred = 0;
440
441	TAILQ_INIT(&sc->sc_tdb_q);
442
443	sc->sc_len = PFSYNC_MINPKT;
444	sc->sc_maxupdates = 128;
445
446#ifdef __FreeBSD__
447	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
448	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF,
449	    M_NOWAIT | M_ZERO);
450	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
451	sc->sc_imo.imo_multicast_vif = -1;
452#else
453	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
454	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
455	    M_WAITOK | M_ZERO);
456	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
457#endif
458
459#ifdef __FreeBSD__
460	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
461	if (ifp == NULL) {
462		free(sc->sc_imo.imo_membership, M_DEVBUF);
463		uma_zdestroy(sc->sc_pool);
464		free(sc, M_DEVBUF);
465		return (ENOSPC);
466	}
467	if_initname(ifp, ifc->ifc_name, unit);
468
469	sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
470#ifdef __FreeBSD__
471	    pfsync_ifdetach, V_pfsyncif, EVENTHANDLER_PRI_ANY);
472#else
473	    pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY);
474#endif
475	if (sc->sc_detachtag == NULL) {
476		if_free(ifp);
477		free(sc->sc_imo.imo_membership, M_DEVBUF);
478		uma_zdestroy(sc->sc_pool);
479		free(sc, M_DEVBUF);
480		return (ENOSPC);
481	}
482#else
483	ifp = &sc->sc_if;
484	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
485#endif
486	ifp->if_softc = sc;
487	ifp->if_ioctl = pfsyncioctl;
488	ifp->if_output = pfsyncoutput;
489	ifp->if_start = pfsyncstart;
490	ifp->if_type = IFT_PFSYNC;
491	ifp->if_snd.ifq_maxlen = ifqmaxlen;
492	ifp->if_hdrlen = sizeof(struct pfsync_header);
493	ifp->if_mtu = 1500; /* XXX */
494#ifdef __FreeBSD__
495	callout_init(&sc->sc_tmo, CALLOUT_MPSAFE);
496	callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0);
497	callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE);
498#else
499	ifp->if_hardmtu = MCLBYTES; /* XXX */
500	timeout_set(&sc->sc_tmo, pfsync_timeout, sc);
501	timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc);
502	timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc);
503#endif
504
505	if_attach(ifp);
506#ifndef __FreeBSD__
507	if_alloc_sadl(ifp);
508
509#if NCARP > 0
510	if_addgroup(ifp, "carp");
511#endif
512#endif
513
514#if NBPFILTER > 0
515#ifdef __FreeBSD__
516	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
517#else
518	bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
519#endif
520#endif
521
522#ifdef __FreeBSD__
523	V_pfsyncif = sc;
524#else
525	pfsyncif = sc;
526#endif
527
528	return (0);
529}
530
531#ifdef __FreeBSD__
532void
533#else
534int
535#endif
536pfsync_clone_destroy(struct ifnet *ifp)
537{
538	struct pfsync_softc *sc = ifp->if_softc;
539
540#ifdef __FreeBSD__
541	EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
542	PF_LOCK();
543#endif
544	timeout_del(&sc->sc_bulkfail_tmo);
545	timeout_del(&sc->sc_bulk_tmo);
546	timeout_del(&sc->sc_tmo);
547#ifdef __FreeBSD__
548	PF_UNLOCK();
549	if (!sc->pfsync_sync_ok && carp_demote_adj_p)
550		(*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy");
551#else
552#if NCARP > 0
553	if (!pfsync_sync_ok)
554		carp_group_demote_adj(&sc->sc_if, -1);
555#endif
556#endif
557#if NBPFILTER > 0
558	bpfdetach(ifp);
559#endif
560	if_detach(ifp);
561
562	pfsync_drop(sc);
563
564	while (sc->sc_deferred > 0)
565		pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
566
567#ifdef __FreeBSD__
568	UMA_DESTROY(sc->sc_pool);
569#else
570	pool_destroy(&sc->sc_pool);
571#endif
572#ifdef __FreeBSD__
573	if_free(ifp);
574	free(sc->sc_imo.imo_membership, M_DEVBUF);
575#else
576	free(sc->sc_imo.imo_membership, M_IPMOPTS);
577#endif
578	free(sc, M_DEVBUF);
579
580#ifdef __FreeBSD__
581	V_pfsyncif = NULL;
582#else
583	pfsyncif = NULL;
584#endif
585
586#ifndef __FreeBSD__
587	return (0);
588#endif
589}
590
591struct mbuf *
592pfsync_if_dequeue(struct ifnet *ifp)
593{
594	struct mbuf *m;
595#ifndef __FreeBSD__
596	int s;
597#endif
598
599#ifdef __FreeBSD__
600	IF_LOCK(&ifp->if_snd);
601	_IF_DROP(&ifp->if_snd);
602	_IF_DEQUEUE(&ifp->if_snd, m);
603	IF_UNLOCK(&ifp->if_snd);
604#else
605	s = splnet();
606	IF_DEQUEUE(&ifp->if_snd, m);
607	splx(s);
608#endif
609
610	return (m);
611}
612
613/*
614 * Start output on the pfsync interface.
615 */
616void
617pfsyncstart(struct ifnet *ifp)
618{
619	struct mbuf *m;
620
621	while ((m = pfsync_if_dequeue(ifp)) != NULL) {
622#ifndef __FreeBSD__
623		IF_DROP(&ifp->if_snd);
624#endif
625		m_freem(m);
626	}
627}
628
629int
630pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
631    struct pf_state_peer *d)
632{
633	if (s->scrub.scrub_flag && d->scrub == NULL) {
634#ifdef __FreeBSD__
635		d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
636#else
637		d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
638#endif
639		if (d->scrub == NULL)
640			return (ENOMEM);
641	}
642
643	return (0);
644}
645
646#ifndef __FreeBSD__
647void
648pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
649{
650	bzero(sp, sizeof(struct pfsync_state));
651
652	/* copy from state key */
653	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
654	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
655	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
656	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
657	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
658	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
659	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
660	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
661	sp->proto = st->key[PF_SK_WIRE]->proto;
662	sp->af = st->key[PF_SK_WIRE]->af;
663
664	/* copy from state */
665	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
666	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
667	sp->creation = htonl(time_second - st->creation);
668	sp->expire = pf_state_expires(st);
669	if (sp->expire <= time_second)
670		sp->expire = htonl(0);
671	else
672		sp->expire = htonl(sp->expire - time_second);
673
674	sp->direction = st->direction;
675	sp->log = st->log;
676	sp->timeout = st->timeout;
677	sp->state_flags = st->state_flags;
678	if (st->src_node)
679		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
680	if (st->nat_src_node)
681		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
682
683	bcopy(&st->id, &sp->id, sizeof(sp->id));
684	sp->creatorid = st->creatorid;
685	pf_state_peer_hton(&st->src, &sp->src);
686	pf_state_peer_hton(&st->dst, &sp->dst);
687
688	if (st->rule.ptr == NULL)
689		sp->rule = htonl(-1);
690	else
691		sp->rule = htonl(st->rule.ptr->nr);
692	if (st->anchor.ptr == NULL)
693		sp->anchor = htonl(-1);
694	else
695		sp->anchor = htonl(st->anchor.ptr->nr);
696	if (st->nat_rule.ptr == NULL)
697		sp->nat_rule = htonl(-1);
698	else
699		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
700
701	pf_state_counter_hton(st->packets[0], sp->packets[0]);
702	pf_state_counter_hton(st->packets[1], sp->packets[1]);
703	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
704	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
705
706}
707#endif
708
709int
710pfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
711{
712	struct pf_state	*st = NULL;
713	struct pf_state_key *skw = NULL, *sks = NULL;
714	struct pf_rule *r = NULL;
715	struct pfi_kif	*kif;
716	int pool_flags;
717	int error;
718
719	PF_LOCK_ASSERT();
720
721#ifdef __FreeBSD__
722	if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) {
723#else
724	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
725#endif
726		printf("pfsync_state_import: invalid creator id:"
727		    " %08x\n", ntohl(sp->creatorid));
728		return (EINVAL);
729	}
730
731	if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
732#ifdef __FreeBSD__
733		if (V_pf_status.debug >= PF_DEBUG_MISC)
734#else
735		if (pf_status.debug >= PF_DEBUG_MISC)
736#endif
737			printf("pfsync_state_import: "
738			    "unknown interface: %s\n", sp->ifname);
739		if (flags & PFSYNC_SI_IOCTL)
740			return (EINVAL);
741		return (0);	/* skip this state */
742	}
743
744	/*
745	 * If the ruleset checksums match or the state is coming from the ioctl,
746	 * it's safe to associate the state with the rule of that number.
747	 */
748	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
749	    (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
750	    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
751		r = pf_main_ruleset.rules[
752		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
753	else
754#ifdef __FreeBSD__
755		r = &V_pf_default_rule;
756#else
757		r = &pf_default_rule;
758#endif
759
760	if ((r->max_states && r->states_cur >= r->max_states))
761		goto cleanup;
762
763#ifdef __FreeBSD__
764	if (flags & PFSYNC_SI_IOCTL)
765		pool_flags = PR_WAITOK | PR_ZERO;
766	else
767		pool_flags = PR_NOWAIT | PR_ZERO;
768
769	if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL)
770		goto cleanup;
771#else
772	if (flags & PFSYNC_SI_IOCTL)
773		pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO;
774	else
775		pool_flags = PR_LIMITFAIL | PR_ZERO;
776
777	if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL)
778		goto cleanup;
779#endif
780
781	if ((skw = pf_alloc_state_key(pool_flags)) == NULL)
782		goto cleanup;
783
784	if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0],
785	    &sp->key[PF_SK_STACK].addr[0], sp->af) ||
786	    PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1],
787	    &sp->key[PF_SK_STACK].addr[1], sp->af) ||
788	    sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] ||
789	    sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) {
790		if ((sks = pf_alloc_state_key(pool_flags)) == NULL)
791			goto cleanup;
792	} else
793		sks = skw;
794
795	/* allocate memory for scrub info */
796	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
797	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
798		goto cleanup;
799
800	/* copy to state key(s) */
801	skw->addr[0] = sp->key[PF_SK_WIRE].addr[0];
802	skw->addr[1] = sp->key[PF_SK_WIRE].addr[1];
803	skw->port[0] = sp->key[PF_SK_WIRE].port[0];
804	skw->port[1] = sp->key[PF_SK_WIRE].port[1];
805	skw->proto = sp->proto;
806	skw->af = sp->af;
807	if (sks != skw) {
808		sks->addr[0] = sp->key[PF_SK_STACK].addr[0];
809		sks->addr[1] = sp->key[PF_SK_STACK].addr[1];
810		sks->port[0] = sp->key[PF_SK_STACK].port[0];
811		sks->port[1] = sp->key[PF_SK_STACK].port[1];
812		sks->proto = sp->proto;
813		sks->af = sp->af;
814	}
815
816	/* copy to state */
817	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
818	st->creation = time_second - ntohl(sp->creation);
819	st->expire = time_second;
820	if (sp->expire) {
821		/* XXX No adaptive scaling. */
822		st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire);
823	}
824
825	st->expire = ntohl(sp->expire) + time_second;
826	st->direction = sp->direction;
827	st->log = sp->log;
828	st->timeout = sp->timeout;
829	st->state_flags = sp->state_flags;
830
831	bcopy(sp->id, &st->id, sizeof(st->id));
832	st->creatorid = sp->creatorid;
833	pf_state_peer_ntoh(&sp->src, &st->src);
834	pf_state_peer_ntoh(&sp->dst, &st->dst);
835
836	st->rule.ptr = r;
837	st->nat_rule.ptr = NULL;
838	st->anchor.ptr = NULL;
839	st->rt_kif = NULL;
840
841	st->pfsync_time = time_second;
842	st->sync_state = PFSYNC_S_NONE;
843
844	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
845	r->states_cur++;
846	r->states_tot++;
847
848	if (!ISSET(flags, PFSYNC_SI_IOCTL))
849		SET(st->state_flags, PFSTATE_NOSYNC);
850
851	if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
852		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
853		r->states_cur--;
854		goto cleanup_state;
855	}
856
857	if (!ISSET(flags, PFSYNC_SI_IOCTL)) {
858		CLR(st->state_flags, PFSTATE_NOSYNC);
859		if (ISSET(st->state_flags, PFSTATE_ACK)) {
860			pfsync_q_ins(st, PFSYNC_S_IACK);
861#ifdef __FreeBSD__
862			pfsync_sendout();
863#else
864			schednetisr(NETISR_PFSYNC);
865#endif
866		}
867	}
868	CLR(st->state_flags, PFSTATE_ACK);
869
870	return (0);
871
872cleanup:
873	error = ENOMEM;
874	if (skw == sks)
875		sks = NULL;
876#ifdef __FreeBSD__
877	if (skw != NULL)
878		pool_put(&V_pf_state_key_pl, skw);
879	if (sks != NULL)
880		pool_put(&V_pf_state_key_pl, sks);
881#else
882	if (skw != NULL)
883		pool_put(&pf_state_key_pl, skw);
884	if (sks != NULL)
885		pool_put(&pf_state_key_pl, sks);
886#endif
887
888cleanup_state:	/* pf_state_insert frees the state keys */
889	if (st) {
890#ifdef __FreeBSD__
891		if (st->dst.scrub)
892			pool_put(&V_pf_state_scrub_pl, st->dst.scrub);
893		if (st->src.scrub)
894			pool_put(&V_pf_state_scrub_pl, st->src.scrub);
895		pool_put(&V_pf_state_pl, st);
896#else
897		if (st->dst.scrub)
898			pool_put(&pf_state_scrub_pl, st->dst.scrub);
899		if (st->src.scrub)
900			pool_put(&pf_state_scrub_pl, st->src.scrub);
901		pool_put(&pf_state_pl, st);
902#endif
903	}
904	return (error);
905}
906
907void
908#ifdef __FreeBSD__
909pfsync_input(struct mbuf *m, __unused int off)
910#else
911pfsync_input(struct mbuf *m, ...)
912#endif
913{
914#ifdef __FreeBSD__
915	struct pfsync_softc *sc = V_pfsyncif;
916#else
917	struct pfsync_softc *sc = pfsyncif;
918#endif
919	struct pfsync_pkt pkt;
920	struct ip *ip = mtod(m, struct ip *);
921	struct pfsync_header *ph;
922	struct pfsync_subheader subh;
923
924	int offset;
925	int rv;
926
927	V_pfsyncstats.pfsyncs_ipackets++;
928
929	/* verify that we have a sync interface configured */
930#ifdef __FreeBSD__
931	if (!sc || !sc->sc_sync_if || !V_pf_status.running)
932#else
933	if (!sc || !sc->sc_sync_if || !pf_status.running)
934#endif
935		goto done;
936
937	/* verify that the packet came in on the right interface */
938	if (sc->sc_sync_if != m->m_pkthdr.rcvif) {
939		V_pfsyncstats.pfsyncs_badif++;
940		goto done;
941	}
942
943#ifdef __FreeBSD__
944	sc->sc_ifp->if_ipackets++;
945	sc->sc_ifp->if_ibytes += m->m_pkthdr.len;
946#else
947	sc->sc_if.if_ipackets++;
948	sc->sc_if.if_ibytes += m->m_pkthdr.len;
949#endif
950	/* verify that the IP TTL is 255. */
951	if (ip->ip_ttl != PFSYNC_DFLTTL) {
952		V_pfsyncstats.pfsyncs_badttl++;
953		goto done;
954	}
955
956	offset = ip->ip_hl << 2;
957	if (m->m_pkthdr.len < offset + sizeof(*ph)) {
958		V_pfsyncstats.pfsyncs_hdrops++;
959		goto done;
960	}
961
962	if (offset + sizeof(*ph) > m->m_len) {
963		if (m_pullup(m, offset + sizeof(*ph)) == NULL) {
964			V_pfsyncstats.pfsyncs_hdrops++;
965			return;
966		}
967		ip = mtod(m, struct ip *);
968	}
969	ph = (struct pfsync_header *)((char *)ip + offset);
970
971	/* verify the version */
972	if (ph->version != PFSYNC_VERSION) {
973		V_pfsyncstats.pfsyncs_badver++;
974		goto done;
975	}
976
977#if 0
978	if (pfsync_input_hmac(m, offset) != 0) {
979		/* XXX stats */
980		goto done;
981	}
982#endif
983
984	/* Cheaper to grab this now than having to mess with mbufs later */
985	pkt.ip = ip;
986	pkt.src = ip->ip_src;
987	pkt.flags = 0;
988
989#ifdef __FreeBSD__
990	if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
991#else
992	if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
993#endif
994		pkt.flags |= PFSYNC_SI_CKSUM;
995
996	offset += sizeof(*ph);
997	for (;;) {
998		m_copydata(m, offset, sizeof(subh), (caddr_t)&subh);
999		offset += sizeof(subh);
1000
1001		if (subh.action >= PFSYNC_ACT_MAX) {
1002			V_pfsyncstats.pfsyncs_badact++;
1003			goto done;
1004		}
1005
1006		rv = (*pfsync_acts[subh.action])(&pkt, m, offset,
1007		    ntohs(subh.count));
1008		if (rv == -1)
1009			return;
1010
1011		offset += rv;
1012	}
1013
1014done:
1015	m_freem(m);
1016}
1017
1018int
1019pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1020{
1021	struct pfsync_clr *clr;
1022	struct mbuf *mp;
1023	int len = sizeof(*clr) * count;
1024	int i, offp;
1025
1026	struct pf_state *st, *nexts;
1027	struct pf_state_key *sk, *nextsk;
1028	struct pf_state_item *si;
1029	u_int32_t creatorid;
1030	int s;
1031
1032	mp = m_pulldown(m, offset, len, &offp);
1033	if (mp == NULL) {
1034		V_pfsyncstats.pfsyncs_badlen++;
1035		return (-1);
1036	}
1037	clr = (struct pfsync_clr *)(mp->m_data + offp);
1038
1039	s = splsoftnet();
1040#ifdef __FreeBSD__
1041	PF_LOCK();
1042#endif
1043	for (i = 0; i < count; i++) {
1044		creatorid = clr[i].creatorid;
1045
1046		if (clr[i].ifname[0] == '\0') {
1047#ifdef __FreeBSD__
1048			for (st = RB_MIN(pf_state_tree_id, &V_tree_id);
1049			    st; st = nexts) {
1050				nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st);
1051#else
1052			for (st = RB_MIN(pf_state_tree_id, &tree_id);
1053			    st; st = nexts) {
1054				nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
1055#endif
1056				if (st->creatorid == creatorid) {
1057					SET(st->state_flags, PFSTATE_NOSYNC);
1058					pf_unlink_state(st);
1059				}
1060			}
1061		} else {
1062			if (pfi_kif_get(clr[i].ifname) == NULL)
1063				continue;
1064
1065			/* XXX correct? */
1066#ifdef __FreeBSD__
1067			for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl);
1068#else
1069			for (sk = RB_MIN(pf_state_tree, &pf_statetbl);
1070#endif
1071			    sk; sk = nextsk) {
1072				nextsk = RB_NEXT(pf_state_tree,
1073#ifdef __FreeBSD__
1074				    &V_pf_statetbl, sk);
1075#else
1076				    &pf_statetbl, sk);
1077#endif
1078				TAILQ_FOREACH(si, &sk->states, entry) {
1079					if (si->s->creatorid == creatorid) {
1080						SET(si->s->state_flags,
1081						    PFSTATE_NOSYNC);
1082						pf_unlink_state(si->s);
1083					}
1084				}
1085			}
1086		}
1087	}
1088#ifdef __FreeBSD__
1089	PF_UNLOCK();
1090#endif
1091	splx(s);
1092
1093	return (len);
1094}
1095
1096int
1097pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1098{
1099	struct mbuf *mp;
1100	struct pfsync_state *sa, *sp;
1101	int len = sizeof(*sp) * count;
1102	int i, offp;
1103
1104	int s;
1105
1106	mp = m_pulldown(m, offset, len, &offp);
1107	if (mp == NULL) {
1108		V_pfsyncstats.pfsyncs_badlen++;
1109		return (-1);
1110	}
1111	sa = (struct pfsync_state *)(mp->m_data + offp);
1112
1113	s = splsoftnet();
1114#ifdef __FreeBSD__
1115	PF_LOCK();
1116#endif
1117	for (i = 0; i < count; i++) {
1118		sp = &sa[i];
1119
1120		/* check for invalid values */
1121		if (sp->timeout >= PFTM_MAX ||
1122		    sp->src.state > PF_TCPS_PROXY_DST ||
1123		    sp->dst.state > PF_TCPS_PROXY_DST ||
1124		    sp->direction > PF_OUT ||
1125		    (sp->af != AF_INET && sp->af != AF_INET6)) {
1126#ifdef __FreeBSD__
1127			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1128#else
1129			if (pf_status.debug >= PF_DEBUG_MISC) {
1130#endif
1131				printf("pfsync_input: PFSYNC5_ACT_INS: "
1132				    "invalid value\n");
1133			}
1134			V_pfsyncstats.pfsyncs_badval++;
1135			continue;
1136		}
1137
1138		if (pfsync_state_import(sp, pkt->flags) == ENOMEM) {
1139			/* drop out, but process the rest of the actions */
1140			break;
1141		}
1142	}
1143#ifdef __FreeBSD__
1144	PF_UNLOCK();
1145#endif
1146	splx(s);
1147
1148	return (len);
1149}
1150
1151int
1152pfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1153{
1154	struct pfsync_ins_ack *ia, *iaa;
1155	struct pf_state_cmp id_key;
1156	struct pf_state *st;
1157
1158	struct mbuf *mp;
1159	int len = count * sizeof(*ia);
1160	int offp, i;
1161	int s;
1162
1163	mp = m_pulldown(m, offset, len, &offp);
1164	if (mp == NULL) {
1165		V_pfsyncstats.pfsyncs_badlen++;
1166		return (-1);
1167	}
1168	iaa = (struct pfsync_ins_ack *)(mp->m_data + offp);
1169
1170	s = splsoftnet();
1171#ifdef __FreeBSD__
1172	PF_LOCK();
1173#endif
1174	for (i = 0; i < count; i++) {
1175		ia = &iaa[i];
1176
1177		bcopy(&ia->id, &id_key.id, sizeof(id_key.id));
1178		id_key.creatorid = ia->creatorid;
1179
1180		st = pf_find_state_byid(&id_key);
1181		if (st == NULL)
1182			continue;
1183
1184		if (ISSET(st->state_flags, PFSTATE_ACK))
1185			pfsync_deferred(st, 0);
1186	}
1187#ifdef __FreeBSD__
1188	PF_UNLOCK();
1189#endif
1190	splx(s);
1191	/*
1192	 * XXX this is not yet implemented, but we know the size of the
1193	 * message so we can skip it.
1194	 */
1195
1196	return (count * sizeof(struct pfsync_ins_ack));
1197}
1198
1199int
1200pfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src,
1201    struct pfsync_state_peer *dst)
1202{
1203	int sfail = 0;
1204
1205	/*
1206	 * The state should never go backwards except
1207	 * for syn-proxy states.  Neither should the
1208	 * sequence window slide backwards.
1209	 */
1210	if (st->src.state > src->state &&
1211	    (st->src.state < PF_TCPS_PROXY_SRC ||
1212	    src->state >= PF_TCPS_PROXY_SRC))
1213		sfail = 1;
1214	else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))
1215		sfail = 3;
1216	else if (st->dst.state > dst->state) {
1217		/* There might still be useful
1218		 * information about the src state here,
1219		 * so import that part of the update,
1220		 * then "fail" so we send the updated
1221		 * state back to the peer who is missing
1222		 * our what we know. */
1223		pf_state_peer_ntoh(src, &st->src);
1224		/* XXX do anything with timeouts? */
1225		sfail = 7;
1226	} else if (st->dst.state >= TCPS_SYN_SENT &&
1227	    SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))
1228		sfail = 4;
1229
1230	return (sfail);
1231}
1232
1233int
1234pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1235{
1236	struct pfsync_state *sa, *sp;
1237	struct pf_state_cmp id_key;
1238	struct pf_state_key *sk;
1239	struct pf_state *st;
1240	int sfail;
1241
1242	struct mbuf *mp;
1243	int len = count * sizeof(*sp);
1244	int offp, i;
1245	int s;
1246
1247	mp = m_pulldown(m, offset, len, &offp);
1248	if (mp == NULL) {
1249		V_pfsyncstats.pfsyncs_badlen++;
1250		return (-1);
1251	}
1252	sa = (struct pfsync_state *)(mp->m_data + offp);
1253
1254	s = splsoftnet();
1255#ifdef __FreeBSD__
1256	PF_LOCK();
1257#endif
1258	for (i = 0; i < count; i++) {
1259		sp = &sa[i];
1260
1261		/* check for invalid values */
1262		if (sp->timeout >= PFTM_MAX ||
1263		    sp->src.state > PF_TCPS_PROXY_DST ||
1264		    sp->dst.state > PF_TCPS_PROXY_DST) {
1265#ifdef __FreeBSD__
1266			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1267#else
1268			if (pf_status.debug >= PF_DEBUG_MISC) {
1269#endif
1270				printf("pfsync_input: PFSYNC_ACT_UPD: "
1271				    "invalid value\n");
1272			}
1273			V_pfsyncstats.pfsyncs_badval++;
1274			continue;
1275		}
1276
1277		bcopy(sp->id, &id_key.id, sizeof(id_key.id));
1278		id_key.creatorid = sp->creatorid;
1279
1280		st = pf_find_state_byid(&id_key);
1281		if (st == NULL) {
1282			/* insert the update */
1283			if (pfsync_state_import(sp, 0))
1284				V_pfsyncstats.pfsyncs_badstate++;
1285			continue;
1286		}
1287
1288		if (ISSET(st->state_flags, PFSTATE_ACK))
1289			pfsync_deferred(st, 1);
1290
1291		sk = st->key[PF_SK_WIRE];	/* XXX right one? */
1292		sfail = 0;
1293		if (sk->proto == IPPROTO_TCP)
1294			sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst);
1295		else {
1296			/*
1297			 * Non-TCP protocol state machine always go
1298			 * forwards
1299			 */
1300			if (st->src.state > sp->src.state)
1301				sfail = 5;
1302			else if (st->dst.state > sp->dst.state)
1303				sfail = 6;
1304		}
1305
1306		if (sfail) {
1307#ifdef __FreeBSD__
1308			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1309#else
1310			if (pf_status.debug >= PF_DEBUG_MISC) {
1311#endif
1312				printf("pfsync: %s stale update (%d)"
1313				    " id: %016llx creatorid: %08x\n",
1314				    (sfail < 7 ?  "ignoring" : "partial"),
1315				    sfail, betoh64(st->id),
1316				    ntohl(st->creatorid));
1317			}
1318			V_pfsyncstats.pfsyncs_stale++;
1319
1320			pfsync_update_state(st);
1321#ifdef __FreeBSD__
1322			pfsync_sendout();
1323#else
1324			schednetisr(NETISR_PFSYNC);
1325#endif
1326			continue;
1327		}
1328		pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
1329		pf_state_peer_ntoh(&sp->src, &st->src);
1330		pf_state_peer_ntoh(&sp->dst, &st->dst);
1331		st->expire = ntohl(sp->expire) + time_second;
1332		st->timeout = sp->timeout;
1333		st->pfsync_time = time_second;
1334	}
1335#ifdef __FreeBSD__
1336	PF_UNLOCK();
1337#endif
1338	splx(s);
1339
1340	return (len);
1341}
1342
1343int
1344pfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1345{
1346	struct pfsync_upd_c *ua, *up;
1347	struct pf_state_key *sk;
1348	struct pf_state_cmp id_key;
1349	struct pf_state *st;
1350
1351	int len = count * sizeof(*up);
1352	int sfail;
1353
1354	struct mbuf *mp;
1355	int offp, i;
1356	int s;
1357
1358	mp = m_pulldown(m, offset, len, &offp);
1359	if (mp == NULL) {
1360		V_pfsyncstats.pfsyncs_badlen++;
1361		return (-1);
1362	}
1363	ua = (struct pfsync_upd_c *)(mp->m_data + offp);
1364
1365	s = splsoftnet();
1366#ifdef __FreeBSD__
1367	PF_LOCK();
1368#endif
1369	for (i = 0; i < count; i++) {
1370		up = &ua[i];
1371
1372		/* check for invalid values */
1373		if (up->timeout >= PFTM_MAX ||
1374		    up->src.state > PF_TCPS_PROXY_DST ||
1375		    up->dst.state > PF_TCPS_PROXY_DST) {
1376#ifdef __FreeBSD__
1377			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1378#else
1379			if (pf_status.debug >= PF_DEBUG_MISC) {
1380#endif
1381				printf("pfsync_input: "
1382				    "PFSYNC_ACT_UPD_C: "
1383				    "invalid value\n");
1384			}
1385			V_pfsyncstats.pfsyncs_badval++;
1386			continue;
1387		}
1388
1389		bcopy(&up->id, &id_key.id, sizeof(id_key.id));
1390		id_key.creatorid = up->creatorid;
1391
1392		st = pf_find_state_byid(&id_key);
1393		if (st == NULL) {
1394			/* We don't have this state. Ask for it. */
1395			pfsync_request_update(id_key.creatorid, id_key.id);
1396			continue;
1397		}
1398
1399		if (ISSET(st->state_flags, PFSTATE_ACK))
1400			pfsync_deferred(st, 1);
1401
1402		sk = st->key[PF_SK_WIRE]; /* XXX right one? */
1403		sfail = 0;
1404		if (sk->proto == IPPROTO_TCP)
1405			sfail = pfsync_upd_tcp(st, &up->src, &up->dst);
1406		else {
1407			/*
1408			 * Non-TCP protocol state machine always go forwards
1409			 */
1410			if (st->src.state > up->src.state)
1411				sfail = 5;
1412			else if (st->dst.state > up->dst.state)
1413				sfail = 6;
1414		}
1415
1416		if (sfail) {
1417#ifdef __FreeBSD__
1418			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1419#else
1420			if (pf_status.debug >= PF_DEBUG_MISC) {
1421#endif
1422				printf("pfsync: ignoring stale update "
1423				    "(%d) id: %016llx "
1424				    "creatorid: %08x\n", sfail,
1425				    betoh64(st->id),
1426				    ntohl(st->creatorid));
1427			}
1428			V_pfsyncstats.pfsyncs_stale++;
1429
1430			pfsync_update_state(st);
1431#ifdef __FreeBSD__
1432			pfsync_sendout();
1433#else
1434			schednetisr(NETISR_PFSYNC);
1435#endif
1436			continue;
1437		}
1438		pfsync_alloc_scrub_memory(&up->dst, &st->dst);
1439		pf_state_peer_ntoh(&up->src, &st->src);
1440		pf_state_peer_ntoh(&up->dst, &st->dst);
1441		st->expire = ntohl(up->expire) + time_second;
1442		st->timeout = up->timeout;
1443		st->pfsync_time = time_second;
1444	}
1445#ifdef __FreeBSD__
1446	PF_UNLOCK();
1447#endif
1448	splx(s);
1449
1450	return (len);
1451}
1452
1453int
1454pfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1455{
1456	struct pfsync_upd_req *ur, *ura;
1457	struct mbuf *mp;
1458	int len = count * sizeof(*ur);
1459	int i, offp;
1460
1461	struct pf_state_cmp id_key;
1462	struct pf_state *st;
1463
1464	mp = m_pulldown(m, offset, len, &offp);
1465	if (mp == NULL) {
1466		V_pfsyncstats.pfsyncs_badlen++;
1467		return (-1);
1468	}
1469	ura = (struct pfsync_upd_req *)(mp->m_data + offp);
1470
1471	for (i = 0; i < count; i++) {
1472		ur = &ura[i];
1473
1474		bcopy(&ur->id, &id_key.id, sizeof(id_key.id));
1475		id_key.creatorid = ur->creatorid;
1476
1477		if (id_key.id == 0 && id_key.creatorid == 0)
1478			pfsync_bulk_start();
1479		else {
1480			st = pf_find_state_byid(&id_key);
1481			if (st == NULL) {
1482				V_pfsyncstats.pfsyncs_badstate++;
1483				continue;
1484			}
1485			if (ISSET(st->state_flags, PFSTATE_NOSYNC))
1486				continue;
1487
1488			PF_LOCK();
1489			pfsync_update_state_req(st);
1490			PF_UNLOCK();
1491		}
1492	}
1493
1494	return (len);
1495}
1496
1497int
1498pfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1499{
1500	struct mbuf *mp;
1501	struct pfsync_state *sa, *sp;
1502	struct pf_state_cmp id_key;
1503	struct pf_state *st;
1504	int len = count * sizeof(*sp);
1505	int offp, i;
1506	int s;
1507
1508	mp = m_pulldown(m, offset, len, &offp);
1509	if (mp == NULL) {
1510		V_pfsyncstats.pfsyncs_badlen++;
1511		return (-1);
1512	}
1513	sa = (struct pfsync_state *)(mp->m_data + offp);
1514
1515	s = splsoftnet();
1516#ifdef __FreeBSD__
1517	PF_LOCK();
1518#endif
1519	for (i = 0; i < count; i++) {
1520		sp = &sa[i];
1521
1522		bcopy(sp->id, &id_key.id, sizeof(id_key.id));
1523		id_key.creatorid = sp->creatorid;
1524
1525		st = pf_find_state_byid(&id_key);
1526		if (st == NULL) {
1527			V_pfsyncstats.pfsyncs_badstate++;
1528			continue;
1529		}
1530		SET(st->state_flags, PFSTATE_NOSYNC);
1531		pf_unlink_state(st);
1532	}
1533#ifdef __FreeBSD__
1534	PF_UNLOCK();
1535#endif
1536	splx(s);
1537
1538	return (len);
1539}
1540
1541int
1542pfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1543{
1544	struct mbuf *mp;
1545	struct pfsync_del_c *sa, *sp;
1546	struct pf_state_cmp id_key;
1547	struct pf_state *st;
1548	int len = count * sizeof(*sp);
1549	int offp, i;
1550	int s;
1551
1552	mp = m_pulldown(m, offset, len, &offp);
1553	if (mp == NULL) {
1554		V_pfsyncstats.pfsyncs_badlen++;
1555		return (-1);
1556	}
1557	sa = (struct pfsync_del_c *)(mp->m_data + offp);
1558
1559	s = splsoftnet();
1560#ifdef __FreeBSD__
1561	PF_LOCK();
1562#endif
1563	for (i = 0; i < count; i++) {
1564		sp = &sa[i];
1565
1566		bcopy(&sp->id, &id_key.id, sizeof(id_key.id));
1567		id_key.creatorid = sp->creatorid;
1568
1569		st = pf_find_state_byid(&id_key);
1570		if (st == NULL) {
1571			V_pfsyncstats.pfsyncs_badstate++;
1572			continue;
1573		}
1574
1575		SET(st->state_flags, PFSTATE_NOSYNC);
1576		pf_unlink_state(st);
1577	}
1578#ifdef __FreeBSD__
1579	PF_UNLOCK();
1580#endif
1581	splx(s);
1582
1583	return (len);
1584}
1585
1586int
1587pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1588{
1589#ifdef __FreeBSD__
1590	struct pfsync_softc *sc = V_pfsyncif;
1591#else
1592	struct pfsync_softc *sc = pfsyncif;
1593#endif
1594	struct pfsync_bus *bus;
1595	struct mbuf *mp;
1596	int len = count * sizeof(*bus);
1597	int offp;
1598
1599	/* If we're not waiting for a bulk update, who cares. */
1600	if (sc->sc_ureq_sent == 0)
1601		return (len);
1602
1603	mp = m_pulldown(m, offset, len, &offp);
1604	if (mp == NULL) {
1605		V_pfsyncstats.pfsyncs_badlen++;
1606		return (-1);
1607	}
1608	bus = (struct pfsync_bus *)(mp->m_data + offp);
1609
1610	switch (bus->status) {
1611	case PFSYNC_BUS_START:
1612#ifdef __FreeBSD__
1613		callout_reset(&sc->sc_bulkfail_tmo, 4 * hz +
1614		    pf_pool_limits[PF_LIMIT_STATES].limit /
1615		    ((sc->sc_sync_if->if_mtu - PFSYNC_MINPKT) /
1616		    sizeof(struct pfsync_state)),
1617		    pfsync_bulk_fail, V_pfsyncif);
1618#else
1619		timeout_add(&sc->sc_bulkfail_tmo, 4 * hz +
1620		    pf_pool_limits[PF_LIMIT_STATES].limit /
1621		    ((sc->sc_if.if_mtu - PFSYNC_MINPKT) /
1622		    sizeof(struct pfsync_state)));
1623#endif
1624#ifdef __FreeBSD__
1625		if (V_pf_status.debug >= PF_DEBUG_MISC)
1626#else
1627		if (pf_status.debug >= PF_DEBUG_MISC)
1628#endif
1629			printf("pfsync: received bulk update start\n");
1630		break;
1631
1632	case PFSYNC_BUS_END:
1633		if (time_uptime - ntohl(bus->endtime) >=
1634		    sc->sc_ureq_sent) {
1635			/* that's it, we're happy */
1636			sc->sc_ureq_sent = 0;
1637			sc->sc_bulk_tries = 0;
1638			timeout_del(&sc->sc_bulkfail_tmo);
1639#ifdef __FreeBSD__
1640			if (!sc->pfsync_sync_ok && carp_demote_adj_p)
1641				(*carp_demote_adj_p)(-V_pfsync_carp_adj,
1642				    "pfsync bulk done");
1643			sc->pfsync_sync_ok = 1;
1644#else
1645#if NCARP > 0
1646			if (!pfsync_sync_ok)
1647				carp_group_demote_adj(&sc->sc_if, -1);
1648#endif
1649			pfsync_sync_ok = 1;
1650#endif
1651#ifdef __FreeBSD__
1652			if (V_pf_status.debug >= PF_DEBUG_MISC)
1653#else
1654			if (pf_status.debug >= PF_DEBUG_MISC)
1655#endif
1656				printf("pfsync: received valid "
1657				    "bulk update end\n");
1658		} else {
1659#ifdef __FreeBSD__
1660			if (V_pf_status.debug >= PF_DEBUG_MISC)
1661#else
1662			if (pf_status.debug >= PF_DEBUG_MISC)
1663#endif
1664				printf("pfsync: received invalid "
1665				    "bulk update end: bad timestamp\n");
1666		}
1667		break;
1668	}
1669
1670	return (len);
1671}
1672
1673int
1674pfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1675{
1676	int len = count * sizeof(struct pfsync_tdb);
1677
1678#if defined(IPSEC)
1679	struct pfsync_tdb *tp;
1680	struct mbuf *mp;
1681	int offp;
1682	int i;
1683	int s;
1684
1685	mp = m_pulldown(m, offset, len, &offp);
1686	if (mp == NULL) {
1687		V_pfsyncstats.pfsyncs_badlen++;
1688		return (-1);
1689	}
1690	tp = (struct pfsync_tdb *)(mp->m_data + offp);
1691
1692	s = splsoftnet();
1693#ifdef __FreeBSD__
1694	PF_LOCK();
1695#endif
1696	for (i = 0; i < count; i++)
1697		pfsync_update_net_tdb(&tp[i]);
1698#ifdef __FreeBSD__
1699	PF_UNLOCK();
1700#endif
1701	splx(s);
1702#endif
1703
1704	return (len);
1705}
1706
1707#if defined(IPSEC)
1708/* Update an in-kernel tdb. Silently fail if no tdb is found. */
1709void
1710pfsync_update_net_tdb(struct pfsync_tdb *pt)
1711{
1712	struct tdb		*tdb;
1713	int			 s;
1714
1715	/* check for invalid values */
1716	if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
1717	    (pt->dst.sa.sa_family != AF_INET &&
1718	     pt->dst.sa.sa_family != AF_INET6))
1719		goto bad;
1720
1721	s = spltdb();
1722	tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
1723	if (tdb) {
1724		pt->rpl = ntohl(pt->rpl);
1725		pt->cur_bytes = betoh64(pt->cur_bytes);
1726
1727		/* Neither replay nor byte counter should ever decrease. */
1728		if (pt->rpl < tdb->tdb_rpl ||
1729		    pt->cur_bytes < tdb->tdb_cur_bytes) {
1730			splx(s);
1731			goto bad;
1732		}
1733
1734		tdb->tdb_rpl = pt->rpl;
1735		tdb->tdb_cur_bytes = pt->cur_bytes;
1736	}
1737	splx(s);
1738	return;
1739
1740bad:
1741#ifdef __FreeBSD__
1742	if (V_pf_status.debug >= PF_DEBUG_MISC)
1743#else
1744	if (pf_status.debug >= PF_DEBUG_MISC)
1745#endif
1746		printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
1747		    "invalid value\n");
1748	V_pfsyncstats.pfsyncs_badstate++;
1749	return;
1750}
1751#endif
1752
1753
1754int
1755pfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1756{
1757	/* check if we are at the right place in the packet */
1758	if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof))
1759		V_pfsyncstats.pfsyncs_badact++;
1760
1761	/* we're done. free and let the caller return */
1762	m_freem(m);
1763	return (-1);
1764}
1765
1766int
1767pfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1768{
1769	V_pfsyncstats.pfsyncs_badact++;
1770
1771	m_freem(m);
1772	return (-1);
1773}
1774
1775int
1776pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1777#ifdef __FreeBSD__
1778	struct route *rt)
1779#else
1780	struct rtentry *rt)
1781#endif
1782{
1783	m_freem(m);
1784	return (0);
1785}
1786
1787/* ARGSUSED */
1788int
1789pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1790{
1791#ifndef __FreeBSD__
1792	struct proc *p = curproc;
1793#endif
1794	struct pfsync_softc *sc = ifp->if_softc;
1795	struct ifreq *ifr = (struct ifreq *)data;
1796	struct ip_moptions *imo = &sc->sc_imo;
1797	struct pfsyncreq pfsyncr;
1798	struct ifnet    *sifp;
1799	struct ip *ip;
1800	int s, error;
1801
1802	switch (cmd) {
1803#if 0
1804	case SIOCSIFADDR:
1805	case SIOCAIFADDR:
1806	case SIOCSIFDSTADDR:
1807#endif
1808	case SIOCSIFFLAGS:
1809#ifdef __FreeBSD__
1810		if (ifp->if_flags & IFF_UP)
1811			ifp->if_drv_flags |= IFF_DRV_RUNNING;
1812		else
1813			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1814#else
1815		if (ifp->if_flags & IFF_UP)
1816			ifp->if_flags |= IFF_RUNNING;
1817		else
1818			ifp->if_flags &= ~IFF_RUNNING;
1819#endif
1820		break;
1821	case SIOCSIFMTU:
1822		if (ifr->ifr_mtu <= PFSYNC_MINPKT)
1823			return (EINVAL);
1824		if (ifr->ifr_mtu > MCLBYTES) /* XXX could be bigger */
1825			ifr->ifr_mtu = MCLBYTES;
1826		if (ifr->ifr_mtu < ifp->if_mtu) {
1827			s = splnet();
1828#ifdef __FreeBSD__
1829			PF_LOCK();
1830#endif
1831			pfsync_sendout();
1832#ifdef __FreeBSD__
1833			PF_UNLOCK();
1834#endif
1835			splx(s);
1836		}
1837		ifp->if_mtu = ifr->ifr_mtu;
1838		break;
1839	case SIOCGETPFSYNC:
1840		bzero(&pfsyncr, sizeof(pfsyncr));
1841		if (sc->sc_sync_if) {
1842			strlcpy(pfsyncr.pfsyncr_syncdev,
1843			    sc->sc_sync_if->if_xname, IFNAMSIZ);
1844		}
1845		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1846		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1847		return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)));
1848
1849	case SIOCSETPFSYNC:
1850#ifdef __FreeBSD__
1851		if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
1852#else
1853		if ((error = suser(p, p->p_acflag)) != 0)
1854#endif
1855			return (error);
1856		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1857			return (error);
1858
1859#ifdef __FreeBSD__
1860		PF_LOCK();
1861#endif
1862		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1863#ifdef __FreeBSD__
1864			sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
1865#else
1866			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1867#endif
1868		else
1869			sc->sc_sync_peer.s_addr =
1870			    pfsyncr.pfsyncr_syncpeer.s_addr;
1871
1872		if (pfsyncr.pfsyncr_maxupdates > 255)
1873#ifdef __FreeBSD__
1874		{
1875			PF_UNLOCK();
1876#endif
1877			return (EINVAL);
1878#ifdef __FreeBSD__
1879		}
1880#endif
1881		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1882
1883		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1884			sc->sc_sync_if = NULL;
1885#ifdef __FreeBSD__
1886			PF_UNLOCK();
1887#endif
1888			if (imo->imo_num_memberships > 0) {
1889				in_delmulti(imo->imo_membership[
1890				    --imo->imo_num_memberships]);
1891				imo->imo_multicast_ifp = NULL;
1892			}
1893			break;
1894		}
1895
1896#ifdef __FreeBSD__
1897		PF_UNLOCK();
1898#endif
1899		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
1900			return (EINVAL);
1901
1902#ifdef __FreeBSD__
1903		PF_LOCK();
1904#endif
1905		s = splnet();
1906#ifdef __FreeBSD__
1907		if (sifp->if_mtu < sc->sc_ifp->if_mtu ||
1908#else
1909		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1910#endif
1911		    (sc->sc_sync_if != NULL &&
1912		    sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
1913		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1914			pfsync_sendout();
1915		sc->sc_sync_if = sifp;
1916
1917		if (imo->imo_num_memberships > 0) {
1918#ifdef __FreeBSD__
1919			PF_UNLOCK();
1920#endif
1921			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1922#ifdef __FreeBSD__
1923			PF_LOCK();
1924#endif
1925			imo->imo_multicast_ifp = NULL;
1926		}
1927
1928		if (sc->sc_sync_if &&
1929#ifdef __FreeBSD__
1930		    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1931#else
1932		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1933#endif
1934			struct in_addr addr;
1935
1936			if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) {
1937				sc->sc_sync_if = NULL;
1938#ifdef __FreeBSD__
1939				PF_UNLOCK();
1940#endif
1941				splx(s);
1942				return (EADDRNOTAVAIL);
1943			}
1944
1945#ifdef __FreeBSD__
1946			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1947#else
1948			addr.s_addr = INADDR_PFSYNC_GROUP;
1949#endif
1950
1951#ifdef __FreeBSD__
1952			PF_UNLOCK();
1953#endif
1954			if ((imo->imo_membership[0] =
1955			    in_addmulti(&addr, sc->sc_sync_if)) == NULL) {
1956				sc->sc_sync_if = NULL;
1957				splx(s);
1958				return (ENOBUFS);
1959			}
1960#ifdef __FreeBSD__
1961			PF_LOCK();
1962#endif
1963			imo->imo_num_memberships++;
1964			imo->imo_multicast_ifp = sc->sc_sync_if;
1965			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1966			imo->imo_multicast_loop = 0;
1967		}
1968
1969		ip = &sc->sc_template;
1970		bzero(ip, sizeof(*ip));
1971		ip->ip_v = IPVERSION;
1972		ip->ip_hl = sizeof(sc->sc_template) >> 2;
1973		ip->ip_tos = IPTOS_LOWDELAY;
1974		/* len and id are set later */
1975#ifdef __FreeBSD__
1976		ip->ip_off = IP_DF;
1977#else
1978		ip->ip_off = htons(IP_DF);
1979#endif
1980		ip->ip_ttl = PFSYNC_DFLTTL;
1981		ip->ip_p = IPPROTO_PFSYNC;
1982		ip->ip_src.s_addr = INADDR_ANY;
1983		ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
1984
1985		if (sc->sc_sync_if) {
1986			/* Request a full state table update. */
1987			sc->sc_ureq_sent = time_uptime;
1988#ifdef __FreeBSD__
1989			if (sc->pfsync_sync_ok && carp_demote_adj_p)
1990				(*carp_demote_adj_p)(V_pfsync_carp_adj,
1991				    "pfsync bulk start");
1992			sc->pfsync_sync_ok = 0;
1993#else
1994#if NCARP > 0
1995			if (pfsync_sync_ok)
1996				carp_group_demote_adj(&sc->sc_if, 1);
1997#endif
1998			pfsync_sync_ok = 0;
1999#endif
2000#ifdef __FreeBSD__
2001			if (V_pf_status.debug >= PF_DEBUG_MISC)
2002#else
2003			if (pf_status.debug >= PF_DEBUG_MISC)
2004#endif
2005				printf("pfsync: requesting bulk update\n");
2006#ifdef __FreeBSD__
2007			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
2008			    pfsync_bulk_fail, V_pfsyncif);
2009#else
2010			timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
2011#endif
2012			pfsync_request_update(0, 0);
2013		}
2014#ifdef __FreeBSD__
2015		PF_UNLOCK();
2016#endif
2017		splx(s);
2018
2019		break;
2020
2021	default:
2022		return (ENOTTY);
2023	}
2024
2025	return (0);
2026}
2027
2028int
2029pfsync_out_state(struct pf_state *st, struct mbuf *m, int offset)
2030{
2031	struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset);
2032
2033	pfsync_state_export(sp, st);
2034
2035	return (sizeof(*sp));
2036}
2037
2038int
2039pfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset)
2040{
2041	struct pfsync_ins_ack *iack =
2042	    (struct pfsync_ins_ack *)(m->m_data + offset);
2043
2044	iack->id = st->id;
2045	iack->creatorid = st->creatorid;
2046
2047	return (sizeof(*iack));
2048}
2049
2050int
2051pfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset)
2052{
2053	struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset);
2054
2055	up->id = st->id;
2056	pf_state_peer_hton(&st->src, &up->src);
2057	pf_state_peer_hton(&st->dst, &up->dst);
2058	up->creatorid = st->creatorid;
2059
2060	up->expire = pf_state_expires(st);
2061	if (up->expire <= time_second)
2062		up->expire = htonl(0);
2063	else
2064		up->expire = htonl(up->expire - time_second);
2065	up->timeout = st->timeout;
2066
2067	bzero(up->_pad, sizeof(up->_pad)); /* XXX */
2068
2069	return (sizeof(*up));
2070}
2071
2072int
2073pfsync_out_del(struct pf_state *st, struct mbuf *m, int offset)
2074{
2075	struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset);
2076
2077	dp->id = st->id;
2078	dp->creatorid = st->creatorid;
2079
2080	SET(st->state_flags, PFSTATE_NOSYNC);
2081
2082	return (sizeof(*dp));
2083}
2084
2085void
2086pfsync_drop(struct pfsync_softc *sc)
2087{
2088	struct pf_state *st;
2089	struct pfsync_upd_req_item *ur;
2090#ifdef notyet
2091	struct tdb *t;
2092#endif
2093	int q;
2094
2095	for (q = 0; q < PFSYNC_S_COUNT; q++) {
2096		if (TAILQ_EMPTY(&sc->sc_qs[q]))
2097			continue;
2098
2099		TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
2100#ifdef PFSYNC_DEBUG
2101#ifdef __FreeBSD__
2102			KASSERT(st->sync_state == q,
2103				("%s: st->sync_state == q",
2104					__FUNCTION__));
2105#else
2106			KASSERT(st->sync_state == q);
2107#endif
2108#endif
2109			st->sync_state = PFSYNC_S_NONE;
2110		}
2111		TAILQ_INIT(&sc->sc_qs[q]);
2112	}
2113
2114	while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
2115		TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
2116		pool_put(&sc->sc_pool, ur);
2117	}
2118
2119	sc->sc_plus = NULL;
2120
2121#ifdef notyet
2122	if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
2123		TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry)
2124			CLR(t->tdb_flags, TDBF_PFSYNC);
2125
2126		TAILQ_INIT(&sc->sc_tdb_q);
2127	}
2128#endif
2129
2130	sc->sc_len = PFSYNC_MINPKT;
2131}
2132
2133void
2134pfsync_sendout(void)
2135{
2136#ifdef __FreeBSD__
2137	struct pfsync_softc *sc = V_pfsyncif;
2138#else
2139	struct pfsync_softc *sc = pfsyncif;
2140#endif
2141#if NBPFILTER > 0
2142#ifdef __FreeBSD__
2143	struct ifnet *ifp = sc->sc_ifp;
2144#else
2145	struct ifnet *ifp = &sc->sc_if;
2146#endif
2147#endif
2148	struct mbuf *m;
2149	struct ip *ip;
2150	struct pfsync_header *ph;
2151	struct pfsync_subheader *subh;
2152	struct pf_state *st;
2153	struct pfsync_upd_req_item *ur;
2154#ifdef notyet
2155	struct tdb *t;
2156#endif
2157#ifdef __FreeBSD__
2158	size_t pktlen;
2159	int dummy_error;
2160#endif
2161	int offset;
2162	int q, count = 0;
2163
2164#ifdef __FreeBSD__
2165	PF_LOCK_ASSERT();
2166#else
2167	splassert(IPL_NET);
2168#endif
2169
2170	if (sc == NULL || sc->sc_len == PFSYNC_MINPKT)
2171		return;
2172
2173#if NBPFILTER > 0
2174	if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) {
2175#else
2176	if (sc->sc_sync_if == NULL) {
2177#endif
2178		pfsync_drop(sc);
2179		return;
2180	}
2181
2182	MGETHDR(m, M_DONTWAIT, MT_DATA);
2183	if (m == NULL) {
2184#ifdef __FreeBSD__
2185		sc->sc_ifp->if_oerrors++;
2186#else
2187		sc->sc_if.if_oerrors++;
2188#endif
2189		V_pfsyncstats.pfsyncs_onomem++;
2190		pfsync_drop(sc);
2191		return;
2192	}
2193
2194#ifdef __FreeBSD__
2195	pktlen = max_linkhdr + sc->sc_len;
2196	if (pktlen > MHLEN) {
2197		/* Find the right pool to allocate from. */
2198		/* XXX: This is ugly. */
2199		m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE :
2200			pktlen <= MCLBYTES ? MCLBYTES :
2201#if MJUMPAGESIZE != MCLBYTES
2202			pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE :
2203#endif
2204			pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES);
2205#else
2206	if (max_linkhdr + sc->sc_len > MHLEN) {
2207		MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len);
2208#endif
2209		if (!ISSET(m->m_flags, M_EXT)) {
2210			m_free(m);
2211#ifdef __FreeBSD__
2212			sc->sc_ifp->if_oerrors++;
2213#else
2214			sc->sc_if.if_oerrors++;
2215#endif
2216			V_pfsyncstats.pfsyncs_onomem++;
2217			pfsync_drop(sc);
2218			return;
2219		}
2220	}
2221	m->m_data += max_linkhdr;
2222	m->m_len = m->m_pkthdr.len = sc->sc_len;
2223
2224	/* build the ip header */
2225	ip = (struct ip *)m->m_data;
2226	bcopy(&sc->sc_template, ip, sizeof(*ip));
2227	offset = sizeof(*ip);
2228
2229#ifdef __FreeBSD__
2230	ip->ip_len = m->m_pkthdr.len;
2231#else
2232	ip->ip_len = htons(m->m_pkthdr.len);
2233#endif
2234	ip->ip_id = htons(ip_randomid());
2235
2236	/* build the pfsync header */
2237	ph = (struct pfsync_header *)(m->m_data + offset);
2238	bzero(ph, sizeof(*ph));
2239	offset += sizeof(*ph);
2240
2241	ph->version = PFSYNC_VERSION;
2242	ph->len = htons(sc->sc_len - sizeof(*ip));
2243#ifdef __FreeBSD__
2244	bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
2245#else
2246	bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
2247#endif
2248
2249	/* walk the queues */
2250	for (q = 0; q < PFSYNC_S_COUNT; q++) {
2251		if (TAILQ_EMPTY(&sc->sc_qs[q]))
2252			continue;
2253
2254		subh = (struct pfsync_subheader *)(m->m_data + offset);
2255		offset += sizeof(*subh);
2256
2257		count = 0;
2258		TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
2259#ifdef PFSYNC_DEBUG
2260#ifdef __FreeBSD__
2261			KASSERT(st->sync_state == q,
2262				("%s: st->sync_state == q",
2263					__FUNCTION__));
2264#else
2265			KASSERT(st->sync_state == q);
2266#endif
2267#endif
2268
2269			offset += pfsync_qs[q].write(st, m, offset);
2270			st->sync_state = PFSYNC_S_NONE;
2271			count++;
2272		}
2273		TAILQ_INIT(&sc->sc_qs[q]);
2274
2275		bzero(subh, sizeof(*subh));
2276		subh->action = pfsync_qs[q].action;
2277		subh->count = htons(count);
2278	}
2279
2280	if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) {
2281		subh = (struct pfsync_subheader *)(m->m_data + offset);
2282		offset += sizeof(*subh);
2283
2284		count = 0;
2285		while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
2286			TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
2287
2288			bcopy(&ur->ur_msg, m->m_data + offset,
2289			    sizeof(ur->ur_msg));
2290			offset += sizeof(ur->ur_msg);
2291
2292			pool_put(&sc->sc_pool, ur);
2293
2294			count++;
2295		}
2296
2297		bzero(subh, sizeof(*subh));
2298		subh->action = PFSYNC_ACT_UPD_REQ;
2299		subh->count = htons(count);
2300	}
2301
2302	/* has someone built a custom region for us to add? */
2303	if (sc->sc_plus != NULL) {
2304		bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen);
2305		offset += sc->sc_pluslen;
2306
2307		sc->sc_plus = NULL;
2308	}
2309
2310#ifdef notyet
2311	if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
2312		subh = (struct pfsync_subheader *)(m->m_data + offset);
2313		offset += sizeof(*subh);
2314
2315		count = 0;
2316		TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) {
2317			offset += pfsync_out_tdb(t, m, offset);
2318			CLR(t->tdb_flags, TDBF_PFSYNC);
2319
2320			count++;
2321		}
2322		TAILQ_INIT(&sc->sc_tdb_q);
2323
2324		bzero(subh, sizeof(*subh));
2325		subh->action = PFSYNC_ACT_TDB;
2326		subh->count = htons(count);
2327	}
2328#endif
2329
2330	subh = (struct pfsync_subheader *)(m->m_data + offset);
2331	offset += sizeof(*subh);
2332
2333	bzero(subh, sizeof(*subh));
2334	subh->action = PFSYNC_ACT_EOF;
2335	subh->count = htons(1);
2336
2337	/* XXX write checksum in EOF here */
2338
2339	/* we're done, let's put it on the wire */
2340#if NBPFILTER > 0
2341	if (ifp->if_bpf) {
2342		m->m_data += sizeof(*ip);
2343		m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip);
2344#ifdef __FreeBSD__
2345		BPF_MTAP(ifp, m);
2346#else
2347		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
2348#endif
2349		m->m_data -= sizeof(*ip);
2350		m->m_len = m->m_pkthdr.len = sc->sc_len;
2351	}
2352
2353	if (sc->sc_sync_if == NULL) {
2354		sc->sc_len = PFSYNC_MINPKT;
2355		m_freem(m);
2356		return;
2357	}
2358#endif
2359
2360#ifdef __FreeBSD__
2361	sc->sc_ifp->if_opackets++;
2362	sc->sc_ifp->if_obytes += m->m_pkthdr.len;
2363	sc->sc_len = PFSYNC_MINPKT;
2364
2365	IFQ_ENQUEUE(&sc->sc_ifp->if_snd, m, dummy_error);
2366	schednetisr(NETISR_PFSYNC);
2367#else
2368	sc->sc_if.if_opackets++;
2369	sc->sc_if.if_obytes += m->m_pkthdr.len;
2370
2371	if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0)
2372		pfsyncstats.pfsyncs_opackets++;
2373	else
2374		pfsyncstats.pfsyncs_oerrors++;
2375
2376	/* start again */
2377	sc->sc_len = PFSYNC_MINPKT;
2378#endif
2379}
2380
2381void
2382pfsync_insert_state(struct pf_state *st)
2383{
2384#ifdef __FreeBSD__
2385	struct pfsync_softc *sc = V_pfsyncif;
2386#else
2387	struct pfsync_softc *sc = pfsyncif;
2388#endif
2389
2390#ifdef __FreeBSD__
2391	PF_LOCK_ASSERT();
2392#else
2393	splassert(IPL_SOFTNET);
2394#endif
2395
2396	if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) ||
2397	    st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) {
2398		SET(st->state_flags, PFSTATE_NOSYNC);
2399		return;
2400	}
2401
2402	if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC))
2403		return;
2404
2405#ifdef PFSYNC_DEBUG
2406#ifdef __FreeBSD__
2407	KASSERT(st->sync_state == PFSYNC_S_NONE,
2408		("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
2409#else
2410	KASSERT(st->sync_state == PFSYNC_S_NONE);
2411#endif
2412#endif
2413
2414	if (sc->sc_len == PFSYNC_MINPKT)
2415#ifdef __FreeBSD__
2416		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2417		    V_pfsyncif);
2418#else
2419		timeout_add_sec(&sc->sc_tmo, 1);
2420#endif
2421
2422	pfsync_q_ins(st, PFSYNC_S_INS);
2423
2424	if (ISSET(st->state_flags, PFSTATE_ACK))
2425#ifdef __FreeBSD__
2426		pfsync_sendout();
2427#else
2428		schednetisr(NETISR_PFSYNC);
2429#endif
2430	else
2431		st->sync_updates = 0;
2432}
2433
2434int defer = 10;
2435
2436int
2437pfsync_defer(struct pf_state *st, struct mbuf *m)
2438{
2439#ifdef __FreeBSD__
2440	struct pfsync_softc *sc = V_pfsyncif;
2441#else
2442	struct pfsync_softc *sc = pfsyncif;
2443#endif
2444	struct pfsync_deferral *pd;
2445
2446#ifdef __FreeBSD__
2447	PF_LOCK_ASSERT();
2448#else
2449	splassert(IPL_SOFTNET);
2450#endif
2451
2452	if (sc->sc_deferred >= 128)
2453		pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
2454
2455	pd = pool_get(&sc->sc_pool, M_NOWAIT);
2456	if (pd == NULL)
2457		return (0);
2458	sc->sc_deferred++;
2459
2460#ifdef __FreeBSD__
2461	m->m_flags |= M_SKIP_FIREWALL;
2462#else
2463	m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
2464#endif
2465	SET(st->state_flags, PFSTATE_ACK);
2466
2467	pd->pd_st = st;
2468	pd->pd_m = m;
2469
2470	TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry);
2471#ifdef __FreeBSD__
2472	callout_init(&pd->pd_tmo, CALLOUT_MPSAFE);
2473	callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo,
2474		pd);
2475#else
2476	timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd);
2477	timeout_add(&pd->pd_tmo, defer);
2478#endif
2479
2480	return (1);
2481}
2482
2483void
2484pfsync_undefer(struct pfsync_deferral *pd, int drop)
2485{
2486#ifdef __FreeBSD__
2487	struct pfsync_softc *sc = V_pfsyncif;
2488#else
2489	struct pfsync_softc *sc = pfsyncif;
2490#endif
2491	int s;
2492
2493#ifdef __FreeBSD__
2494	PF_LOCK_ASSERT();
2495#else
2496	splassert(IPL_SOFTNET);
2497#endif
2498
2499	TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry);
2500	sc->sc_deferred--;
2501
2502	CLR(pd->pd_st->state_flags, PFSTATE_ACK);
2503	timeout_del(&pd->pd_tmo); /* bah */
2504	if (drop)
2505		m_freem(pd->pd_m);
2506	else {
2507		s = splnet();
2508#ifdef __FreeBSD__
2509		/* XXX: use pf_defered?! */
2510		PF_UNLOCK();
2511#endif
2512		ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0,
2513		    (void *)NULL, (void *)NULL);
2514#ifdef __FreeBSD__
2515		PF_LOCK();
2516#endif
2517		splx(s);
2518	}
2519
2520	pool_put(&sc->sc_pool, pd);
2521}
2522
2523void
2524pfsync_defer_tmo(void *arg)
2525{
2526#if defined(__FreeBSD__) && defined(VIMAGE)
2527	struct pfsync_deferral *pd = arg;
2528#endif
2529	int s;
2530
2531	s = splsoftnet();
2532#ifdef __FreeBSD__
2533	CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */
2534	PF_LOCK();
2535#endif
2536	pfsync_undefer(arg, 0);
2537#ifdef __FreeBSD__
2538	PF_UNLOCK();
2539	CURVNET_RESTORE();
2540#endif
2541	splx(s);
2542}
2543
2544void
2545pfsync_deferred(struct pf_state *st, int drop)
2546{
2547#ifdef __FreeBSD__
2548	struct pfsync_softc *sc = V_pfsyncif;
2549#else
2550	struct pfsync_softc *sc = pfsyncif;
2551#endif
2552	struct pfsync_deferral *pd;
2553
2554	TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) {
2555		 if (pd->pd_st == st) {
2556			pfsync_undefer(pd, drop);
2557			return;
2558		}
2559	}
2560
2561	panic("pfsync_send_deferred: unable to find deferred state");
2562}
2563
2564u_int pfsync_upds = 0;
2565
2566void
2567pfsync_update_state(struct pf_state *st)
2568{
2569#ifdef __FreeBSD__
2570	struct pfsync_softc *sc = V_pfsyncif;
2571#else
2572	struct pfsync_softc *sc = pfsyncif;
2573#endif
2574	int sync = 0;
2575
2576#ifdef __FreeBSD__
2577	PF_LOCK_ASSERT();
2578#else
2579	splassert(IPL_SOFTNET);
2580#endif
2581
2582	if (sc == NULL)
2583		return;
2584
2585	if (ISSET(st->state_flags, PFSTATE_ACK))
2586		pfsync_deferred(st, 0);
2587	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2588		if (st->sync_state != PFSYNC_S_NONE)
2589			pfsync_q_del(st);
2590		return;
2591	}
2592
2593	if (sc->sc_len == PFSYNC_MINPKT)
2594#ifdef __FreeBSD__
2595		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2596		    V_pfsyncif);
2597#else
2598		timeout_add_sec(&sc->sc_tmo, 1);
2599#endif
2600
2601	switch (st->sync_state) {
2602	case PFSYNC_S_UPD_C:
2603	case PFSYNC_S_UPD:
2604	case PFSYNC_S_INS:
2605		/* we're already handling it */
2606
2607		st->sync_updates++;
2608		if (st->sync_updates >= sc->sc_maxupdates)
2609			sync = 1;
2610		break;
2611
2612	case PFSYNC_S_IACK:
2613		pfsync_q_del(st);
2614	case PFSYNC_S_NONE:
2615		pfsync_q_ins(st, PFSYNC_S_UPD_C);
2616		st->sync_updates = 0;
2617		break;
2618
2619	default:
2620		panic("pfsync_update_state: unexpected sync state %d",
2621		    st->sync_state);
2622	}
2623
2624	if (sync || (time_second - st->pfsync_time) < 2) {
2625		pfsync_upds++;
2626#ifdef __FreeBSD__
2627		pfsync_sendout();
2628#else
2629		schednetisr(NETISR_PFSYNC);
2630#endif
2631	}
2632}
2633
2634void
2635pfsync_request_update(u_int32_t creatorid, u_int64_t id)
2636{
2637#ifdef __FreeBSD__
2638	struct pfsync_softc *sc = V_pfsyncif;
2639#else
2640	struct pfsync_softc *sc = pfsyncif;
2641#endif
2642	struct pfsync_upd_req_item *item;
2643	size_t nlen = sizeof(struct pfsync_upd_req);
2644	int s;
2645
2646	PF_LOCK_ASSERT();
2647
2648	/*
2649	 * this code does nothing to prevent multiple update requests for the
2650	 * same state being generated.
2651	 */
2652
2653	item = pool_get(&sc->sc_pool, PR_NOWAIT);
2654	if (item == NULL) {
2655		/* XXX stats */
2656		return;
2657	}
2658
2659	item->ur_msg.id = id;
2660	item->ur_msg.creatorid = creatorid;
2661
2662	if (TAILQ_EMPTY(&sc->sc_upd_req_list))
2663		nlen += sizeof(struct pfsync_subheader);
2664
2665#ifdef __FreeBSD__
2666	if (sc->sc_len + nlen > sc->sc_sync_if->if_mtu) {
2667#else
2668	if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2669#endif
2670		s = splnet();
2671		pfsync_sendout();
2672		splx(s);
2673
2674		nlen = sizeof(struct pfsync_subheader) +
2675		    sizeof(struct pfsync_upd_req);
2676	}
2677
2678	TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry);
2679	sc->sc_len += nlen;
2680
2681#ifdef __FreeBSD__
2682	pfsync_sendout();
2683#else
2684	schednetisr(NETISR_PFSYNC);
2685#endif
2686}
2687
2688void
2689pfsync_update_state_req(struct pf_state *st)
2690{
2691#ifdef __FreeBSD__
2692	struct pfsync_softc *sc = V_pfsyncif;
2693#else
2694	struct pfsync_softc *sc = pfsyncif;
2695#endif
2696
2697	PF_LOCK_ASSERT();
2698
2699	if (sc == NULL)
2700		panic("pfsync_update_state_req: nonexistant instance");
2701
2702	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2703		if (st->sync_state != PFSYNC_S_NONE)
2704			pfsync_q_del(st);
2705		return;
2706	}
2707
2708	switch (st->sync_state) {
2709	case PFSYNC_S_UPD_C:
2710	case PFSYNC_S_IACK:
2711		pfsync_q_del(st);
2712	case PFSYNC_S_NONE:
2713		pfsync_q_ins(st, PFSYNC_S_UPD);
2714#ifdef __FreeBSD__
2715		pfsync_sendout();
2716#else
2717		schednetisr(NETISR_PFSYNC);
2718#endif
2719		return;
2720
2721	case PFSYNC_S_INS:
2722	case PFSYNC_S_UPD:
2723	case PFSYNC_S_DEL:
2724		/* we're already handling it */
2725		return;
2726
2727	default:
2728		panic("pfsync_update_state_req: unexpected sync state %d",
2729		    st->sync_state);
2730	}
2731}
2732
2733void
2734pfsync_delete_state(struct pf_state *st)
2735{
2736#ifdef __FreeBSD__
2737	struct pfsync_softc *sc = V_pfsyncif;
2738#else
2739	struct pfsync_softc *sc = pfsyncif;
2740#endif
2741
2742#ifdef __FreeBSD__
2743	PF_LOCK_ASSERT();
2744#else
2745	splassert(IPL_SOFTNET);
2746#endif
2747
2748	if (sc == NULL)
2749		return;
2750
2751	if (ISSET(st->state_flags, PFSTATE_ACK))
2752		pfsync_deferred(st, 1);
2753	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2754		if (st->sync_state != PFSYNC_S_NONE)
2755			pfsync_q_del(st);
2756		return;
2757	}
2758
2759	if (sc->sc_len == PFSYNC_MINPKT)
2760#ifdef __FreeBSD__
2761		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2762		    V_pfsyncif);
2763#else
2764		timeout_add_sec(&sc->sc_tmo, 1);
2765#endif
2766
2767	switch (st->sync_state) {
2768	case PFSYNC_S_INS:
2769		/* we never got to tell the world so just forget about it */
2770		pfsync_q_del(st);
2771		return;
2772
2773	case PFSYNC_S_UPD_C:
2774	case PFSYNC_S_UPD:
2775	case PFSYNC_S_IACK:
2776		pfsync_q_del(st);
2777		/* FALLTHROUGH to putting it on the del list */
2778
2779	case PFSYNC_S_NONE:
2780		pfsync_q_ins(st, PFSYNC_S_DEL);
2781		return;
2782
2783	default:
2784		panic("pfsync_delete_state: unexpected sync state %d",
2785		    st->sync_state);
2786	}
2787}
2788
2789void
2790pfsync_clear_states(u_int32_t creatorid, const char *ifname)
2791{
2792	struct {
2793		struct pfsync_subheader subh;
2794		struct pfsync_clr clr;
2795	} __packed r;
2796
2797#ifdef __FreeBSD__
2798	struct pfsync_softc *sc = V_pfsyncif;
2799#else
2800	struct pfsync_softc *sc = pfsyncif;
2801#endif
2802
2803#ifdef __FreeBSD__
2804	PF_LOCK_ASSERT();
2805#else
2806	splassert(IPL_SOFTNET);
2807#endif
2808
2809	if (sc == NULL)
2810		return;
2811
2812	bzero(&r, sizeof(r));
2813
2814	r.subh.action = PFSYNC_ACT_CLR;
2815	r.subh.count = htons(1);
2816
2817	strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname));
2818	r.clr.creatorid = creatorid;
2819
2820	pfsync_send_plus(&r, sizeof(r));
2821}
2822
2823void
2824pfsync_q_ins(struct pf_state *st, int q)
2825{
2826#ifdef __FreeBSD__
2827	struct pfsync_softc *sc = V_pfsyncif;
2828#else
2829	struct pfsync_softc *sc = pfsyncif;
2830#endif
2831	size_t nlen = pfsync_qs[q].len;
2832	int s;
2833
2834	PF_LOCK_ASSERT();
2835
2836#ifdef __FreeBSD__
2837	KASSERT(st->sync_state == PFSYNC_S_NONE,
2838		("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
2839#else
2840	KASSERT(st->sync_state == PFSYNC_S_NONE);
2841#endif
2842
2843#if 1 || defined(PFSYNC_DEBUG)
2844	if (sc->sc_len < PFSYNC_MINPKT)
2845#ifdef __FreeBSD__
2846		panic("pfsync pkt len is too low %zu", sc->sc_len);
2847#else
2848		panic("pfsync pkt len is too low %d", sc->sc_len);
2849#endif
2850#endif
2851	if (TAILQ_EMPTY(&sc->sc_qs[q]))
2852		nlen += sizeof(struct pfsync_subheader);
2853
2854#ifdef __FreeBSD__
2855	if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) {
2856#else
2857	if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2858#endif
2859		s = splnet();
2860		pfsync_sendout();
2861		splx(s);
2862
2863		nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len;
2864	}
2865
2866	sc->sc_len += nlen;
2867	TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
2868	st->sync_state = q;
2869}
2870
2871void
2872pfsync_q_del(struct pf_state *st)
2873{
2874#ifdef __FreeBSD__
2875	struct pfsync_softc *sc = V_pfsyncif;
2876#else
2877	struct pfsync_softc *sc = pfsyncif;
2878#endif
2879	int q = st->sync_state;
2880
2881#ifdef __FreeBSD__
2882	KASSERT(st->sync_state != PFSYNC_S_NONE,
2883		("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__));
2884#else
2885	KASSERT(st->sync_state != PFSYNC_S_NONE);
2886#endif
2887
2888	sc->sc_len -= pfsync_qs[q].len;
2889	TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
2890	st->sync_state = PFSYNC_S_NONE;
2891
2892	if (TAILQ_EMPTY(&sc->sc_qs[q]))
2893		sc->sc_len -= sizeof(struct pfsync_subheader);
2894}
2895
2896#ifdef notyet
2897void
2898pfsync_update_tdb(struct tdb *t, int output)
2899{
2900#ifdef __FreeBSD__
2901	struct pfsync_softc *sc = V_pfsyncif;
2902#else
2903	struct pfsync_softc *sc = pfsyncif;
2904#endif
2905	size_t nlen = sizeof(struct pfsync_tdb);
2906	int s;
2907
2908	if (sc == NULL)
2909		return;
2910
2911	if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) {
2912		if (TAILQ_EMPTY(&sc->sc_tdb_q))
2913			nlen += sizeof(struct pfsync_subheader);
2914
2915		if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2916			s = splnet();
2917			PF_LOCK();
2918			pfsync_sendout();
2919			PF_UNLOCK();
2920			splx(s);
2921
2922			nlen = sizeof(struct pfsync_subheader) +
2923			    sizeof(struct pfsync_tdb);
2924		}
2925
2926		sc->sc_len += nlen;
2927		TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry);
2928		SET(t->tdb_flags, TDBF_PFSYNC);
2929		t->tdb_updates = 0;
2930	} else {
2931		if (++t->tdb_updates >= sc->sc_maxupdates)
2932			schednetisr(NETISR_PFSYNC);
2933	}
2934
2935	if (output)
2936		SET(t->tdb_flags, TDBF_PFSYNC_RPL);
2937	else
2938		CLR(t->tdb_flags, TDBF_PFSYNC_RPL);
2939}
2940
2941void
2942pfsync_delete_tdb(struct tdb *t)
2943{
2944#ifdef __FreeBSD__
2945	struct pfsync_softc *sc = V_pfsyncif;
2946#else
2947	struct pfsync_softc *sc = pfsyncif;
2948#endif
2949
2950	if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC))
2951		return;
2952
2953	sc->sc_len -= sizeof(struct pfsync_tdb);
2954	TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry);
2955	CLR(t->tdb_flags, TDBF_PFSYNC);
2956
2957	if (TAILQ_EMPTY(&sc->sc_tdb_q))
2958		sc->sc_len -= sizeof(struct pfsync_subheader);
2959}
2960
2961int
2962pfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset)
2963{
2964	struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset);
2965
2966	bzero(ut, sizeof(*ut));
2967	ut->spi = t->tdb_spi;
2968	bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst));
2969	/*
2970	 * When a failover happens, the master's rpl is probably above
2971	 * what we see here (we may be up to a second late), so
2972	 * increase it a bit for outbound tdbs to manage most such
2973	 * situations.
2974	 *
2975	 * For now, just add an offset that is likely to be larger
2976	 * than the number of packets we can see in one second. The RFC
2977	 * just says the next packet must have a higher seq value.
2978	 *
2979	 * XXX What is a good algorithm for this? We could use
2980	 * a rate-determined increase, but to know it, we would have
2981	 * to extend struct tdb.
2982	 * XXX pt->rpl can wrap over MAXINT, but if so the real tdb
2983	 * will soon be replaced anyway. For now, just don't handle
2984	 * this edge case.
2985	 */
2986#define RPL_INCR 16384
2987	ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ?
2988	    RPL_INCR : 0));
2989	ut->cur_bytes = htobe64(t->tdb_cur_bytes);
2990	ut->sproto = t->tdb_sproto;
2991
2992	return (sizeof(*ut));
2993}
2994#endif
2995
2996void
2997pfsync_bulk_start(void)
2998{
2999#ifdef __FreeBSD__
3000	struct pfsync_softc *sc = V_pfsyncif;
3001#else
3002	struct pfsync_softc *sc = pfsyncif;
3003#endif
3004
3005#ifdef __FreeBSD__
3006	if (V_pf_status.debug >= PF_DEBUG_MISC)
3007#else
3008	if (pf_status.debug >= PF_DEBUG_MISC)
3009#endif
3010		printf("pfsync: received bulk update request\n");
3011
3012#ifdef __FreeBSD__
3013	PF_LOCK();
3014	if (TAILQ_EMPTY(&V_state_list))
3015#else
3016	if (TAILQ_EMPTY(&state_list))
3017#endif
3018		pfsync_bulk_status(PFSYNC_BUS_END);
3019	else {
3020		sc->sc_ureq_received = time_uptime;
3021		if (sc->sc_bulk_next == NULL)
3022#ifdef __FreeBSD__
3023			sc->sc_bulk_next = TAILQ_FIRST(&V_state_list);
3024#else
3025			sc->sc_bulk_next = TAILQ_FIRST(&state_list);
3026#endif
3027			sc->sc_bulk_last = sc->sc_bulk_next;
3028
3029			pfsync_bulk_status(PFSYNC_BUS_START);
3030			callout_reset(&sc->sc_bulk_tmo, 1,
3031			    pfsync_bulk_update, sc);
3032	}
3033#ifdef __FreeBSD__
3034	PF_UNLOCK();
3035#endif
3036}
3037
3038void
3039pfsync_bulk_update(void *arg)
3040{
3041	struct pfsync_softc *sc = arg;
3042	struct pf_state *st = sc->sc_bulk_next;
3043	int i = 0;
3044	int s;
3045
3046	PF_LOCK_ASSERT();
3047
3048	s = splsoftnet();
3049#ifdef __FreeBSD__
3050	CURVNET_SET(sc->sc_ifp->if_vnet);
3051#endif
3052	for (;;) {
3053		if (st->sync_state == PFSYNC_S_NONE &&
3054		    st->timeout < PFTM_MAX &&
3055		    st->pfsync_time <= sc->sc_ureq_received) {
3056			pfsync_update_state_req(st);
3057			i++;
3058		}
3059
3060		st = TAILQ_NEXT(st, entry_list);
3061		if (st == NULL)
3062#ifdef __FreeBSD__
3063			st = TAILQ_FIRST(&V_state_list);
3064#else
3065			st = TAILQ_FIRST(&state_list);
3066#endif
3067
3068		if (st == sc->sc_bulk_last) {
3069			/* we're done */
3070			sc->sc_bulk_next = NULL;
3071			sc->sc_bulk_last = NULL;
3072			pfsync_bulk_status(PFSYNC_BUS_END);
3073			break;
3074		}
3075
3076#ifdef __FreeBSD__
3077		if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) <
3078#else
3079		if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) <
3080#endif
3081		    sizeof(struct pfsync_state)) {
3082			/* we've filled a packet */
3083			sc->sc_bulk_next = st;
3084#ifdef __FreeBSD__
3085			callout_reset(&sc->sc_bulk_tmo, 1,
3086			    pfsync_bulk_update, sc);
3087#else
3088			timeout_add(&sc->sc_bulk_tmo, 1);
3089#endif
3090			break;
3091		}
3092	}
3093
3094#ifdef __FreeBSD__
3095	CURVNET_RESTORE();
3096#endif
3097	splx(s);
3098}
3099
3100void
3101pfsync_bulk_status(u_int8_t status)
3102{
3103	struct {
3104		struct pfsync_subheader subh;
3105		struct pfsync_bus bus;
3106	} __packed r;
3107
3108#ifdef __FreeBSD__
3109	struct pfsync_softc *sc = V_pfsyncif;
3110#else
3111	struct pfsync_softc *sc = pfsyncif;
3112#endif
3113
3114	PF_LOCK_ASSERT();
3115
3116	bzero(&r, sizeof(r));
3117
3118	r.subh.action = PFSYNC_ACT_BUS;
3119	r.subh.count = htons(1);
3120
3121#ifdef __FreeBSD__
3122	r.bus.creatorid = V_pf_status.hostid;
3123#else
3124	r.bus.creatorid = pf_status.hostid;
3125#endif
3126	r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received);
3127	r.bus.status = status;
3128
3129	pfsync_send_plus(&r, sizeof(r));
3130}
3131
3132void
3133pfsync_bulk_fail(void *arg)
3134{
3135	struct pfsync_softc *sc = arg;
3136
3137#ifdef __FreeBSD__
3138	CURVNET_SET(sc->sc_ifp->if_vnet);
3139#endif
3140
3141	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
3142		/* Try again */
3143#ifdef __FreeBSD__
3144		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
3145		    pfsync_bulk_fail, V_pfsyncif);
3146#else
3147		timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
3148#endif
3149		PF_LOCK();
3150		pfsync_request_update(0, 0);
3151		PF_UNLOCK();
3152	} else {
3153		/* Pretend like the transfer was ok */
3154		sc->sc_ureq_sent = 0;
3155		sc->sc_bulk_tries = 0;
3156#ifdef __FreeBSD__
3157		if (!sc->pfsync_sync_ok && carp_demote_adj_p)
3158			(*carp_demote_adj_p)(-V_pfsync_carp_adj,
3159			    "pfsync bulk fail");
3160		sc->pfsync_sync_ok = 1;
3161#else
3162#if NCARP > 0
3163		if (!pfsync_sync_ok)
3164			carp_group_demote_adj(&sc->sc_if, -1);
3165#endif
3166		pfsync_sync_ok = 1;
3167#endif
3168#ifdef __FreeBSD__
3169		if (V_pf_status.debug >= PF_DEBUG_MISC)
3170#else
3171		if (pf_status.debug >= PF_DEBUG_MISC)
3172#endif
3173			printf("pfsync: failed to receive bulk update\n");
3174	}
3175
3176#ifdef __FreeBSD__
3177	CURVNET_RESTORE();
3178#endif
3179}
3180
3181void
3182pfsync_send_plus(void *plus, size_t pluslen)
3183{
3184#ifdef __FreeBSD__
3185	struct pfsync_softc *sc = V_pfsyncif;
3186#else
3187	struct pfsync_softc *sc = pfsyncif;
3188#endif
3189	int s;
3190
3191	PF_LOCK_ASSERT();
3192
3193#ifdef __FreeBSD__
3194	if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) {
3195#else
3196	if (sc->sc_len + pluslen > sc->sc_if.if_mtu) {
3197#endif
3198		s = splnet();
3199		pfsync_sendout();
3200		splx(s);
3201	}
3202
3203	sc->sc_plus = plus;
3204	sc->sc_len += (sc->sc_pluslen = pluslen);
3205
3206	s = splnet();
3207	pfsync_sendout();
3208	splx(s);
3209}
3210
3211int
3212pfsync_up(void)
3213{
3214#ifdef __FreeBSD__
3215	struct pfsync_softc *sc = V_pfsyncif;
3216#else
3217	struct pfsync_softc *sc = pfsyncif;
3218#endif
3219
3220#ifdef __FreeBSD__
3221	if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING))
3222#else
3223	if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING))
3224#endif
3225		return (0);
3226
3227	return (1);
3228}
3229
3230int
3231pfsync_state_in_use(struct pf_state *st)
3232{
3233#ifdef __FreeBSD__
3234	struct pfsync_softc *sc = V_pfsyncif;
3235#else
3236	struct pfsync_softc *sc = pfsyncif;
3237#endif
3238
3239	if (sc == NULL)
3240		return (0);
3241
3242	if (st->sync_state != PFSYNC_S_NONE ||
3243	    st == sc->sc_bulk_next ||
3244	    st == sc->sc_bulk_last)
3245		return (1);
3246
3247	return (0);
3248}
3249
3250u_int pfsync_ints;
3251u_int pfsync_tmos;
3252
3253void
3254pfsync_timeout(void *arg)
3255{
3256#if defined(__FreeBSD__) && defined(VIMAGE)
3257	struct pfsync_softc *sc = arg;
3258#endif
3259	int s;
3260
3261#ifdef __FreeBSD__
3262	CURVNET_SET(sc->sc_ifp->if_vnet);
3263#endif
3264
3265	pfsync_tmos++;
3266
3267	s = splnet();
3268#ifdef __FreeBSD__
3269	PF_LOCK();
3270#endif
3271	pfsync_sendout();
3272#ifdef __FreeBSD__
3273	PF_UNLOCK();
3274#endif
3275	splx(s);
3276
3277#ifdef __FreeBSD__
3278	CURVNET_RESTORE();
3279#endif
3280}
3281
3282/* this is a softnet/netisr handler */
3283void
3284#ifdef __FreeBSD__
3285pfsyncintr(void *arg)
3286{
3287	struct pfsync_softc *sc = arg;
3288	struct mbuf *m, *n;
3289
3290	CURVNET_SET(sc->sc_ifp->if_vnet);
3291	pfsync_ints++;
3292
3293	IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m);
3294
3295	for (; m != NULL; m = n) {
3296
3297		n = m->m_nextpkt;
3298		m->m_nextpkt = NULL;
3299		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)
3300		    == 0)
3301			V_pfsyncstats.pfsyncs_opackets++;
3302		else
3303			V_pfsyncstats.pfsyncs_oerrors++;
3304	}
3305	CURVNET_RESTORE();
3306}
3307#else
3308pfsyncintr(void)
3309{
3310	int s;
3311
3312	pfsync_ints++;
3313
3314	s = splnet();
3315	pfsync_sendout();
3316	splx(s);
3317}
3318#endif
3319
3320int
3321pfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
3322    size_t newlen)
3323{
3324
3325#ifdef notyet
3326	/* All sysctl names at this level are terminal. */
3327	if (namelen != 1)
3328		return (ENOTDIR);
3329
3330	switch (name[0]) {
3331	case PFSYNCCTL_STATS:
3332		if (newp != NULL)
3333			return (EPERM);
3334		return (sysctl_struct(oldp, oldlenp, newp, newlen,
3335		    &V_pfsyncstats, sizeof(V_pfsyncstats)));
3336	}
3337#endif
3338	return (ENOPROTOOPT);
3339}
3340
3341#ifdef __FreeBSD__
3342void
3343pfsync_ifdetach(void *arg, struct ifnet *ifp)
3344{
3345	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
3346	struct ip_moptions *imo;
3347
3348	if (sc == NULL || sc->sc_sync_if != ifp)
3349		return;         /* not for us; unlocked read */
3350
3351	CURVNET_SET(sc->sc_ifp->if_vnet);
3352
3353	PF_LOCK();
3354
3355	/* Deal with a member interface going away from under us. */
3356	sc->sc_sync_if = NULL;
3357	imo = &sc->sc_imo;
3358	if (imo->imo_num_memberships > 0) {
3359		KASSERT(imo->imo_num_memberships == 1,
3360		    ("%s: imo_num_memberships != 1", __func__));
3361		/*
3362		 * Our event handler is always called after protocol
3363		 * domains have been detached from the underlying ifnet.
3364		 * Do not call in_delmulti(); we held a single reference
3365		 * which the protocol domain has purged in in_purgemaddrs().
3366		 */
3367		PF_UNLOCK();
3368		imo->imo_membership[--imo->imo_num_memberships] = NULL;
3369		PF_LOCK();
3370		imo->imo_multicast_ifp = NULL;
3371	}
3372
3373	PF_UNLOCK();
3374
3375	CURVNET_RESTORE();
3376}
3377
3378static int
3379vnet_pfsync_init(const void *unused)
3380{
3381	int error = 0;
3382
3383	pfsyncattach(0);
3384
3385	error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif,
3386		SWI_NET, INTR_MPSAFE, &pfsync_swi.pfsync_swi_cookie);
3387	if (error)
3388		panic("%s: swi_add %d", __func__, error);
3389
3390	PF_LOCK();
3391	pfsync_state_import_ptr = pfsync_state_import;
3392	pfsync_up_ptr = pfsync_up;
3393	pfsync_insert_state_ptr = pfsync_insert_state;
3394	pfsync_update_state_ptr = pfsync_update_state;
3395	pfsync_delete_state_ptr = pfsync_delete_state;
3396	pfsync_clear_states_ptr = pfsync_clear_states;
3397	pfsync_state_in_use_ptr = pfsync_state_in_use;
3398	pfsync_defer_ptr = pfsync_defer;
3399	PF_UNLOCK();
3400
3401	return (0);
3402}
3403
3404static int
3405vnet_pfsync_uninit(const void *unused)
3406{
3407
3408	swi_remove(pfsync_swi.pfsync_swi_cookie);
3409
3410	PF_LOCK();
3411	pfsync_state_import_ptr = NULL;
3412	pfsync_up_ptr = NULL;
3413	pfsync_insert_state_ptr = NULL;
3414	pfsync_update_state_ptr = NULL;
3415	pfsync_delete_state_ptr = NULL;
3416	pfsync_clear_states_ptr = NULL;
3417	pfsync_state_in_use_ptr = NULL;
3418	pfsync_defer_ptr = NULL;
3419	PF_UNLOCK();
3420
3421	if_clone_detach(&pfsync_cloner);
3422
3423	return (0);
3424}
3425
3426/* Define startup order. */
3427#define	PFSYNC_SYSINIT_ORDER	SI_SUB_PROTO_IF
3428#define	PFSYNC_MODEVENT_ORDER	(SI_ORDER_FIRST) /* On boot slot in here. */
3429#define	PFSYNC_VNET_ORDER	(PFSYNC_MODEVENT_ORDER + 2) /* Later still. */
3430
3431/*
3432 * Starting up.
3433 * VNET_SYSINIT is called for each existing vnet and each new vnet.
3434 */
3435VNET_SYSINIT(vnet_pfsync_init, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER,
3436    vnet_pfsync_init, NULL);
3437
3438/*
3439 * Closing up shop. These are done in REVERSE ORDER,
3440 * Not called on reboot.
3441 * VNET_SYSUNINIT is called for each exiting vnet as it exits.
3442 */
3443VNET_SYSUNINIT(vnet_pfsync_uninit, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER,
3444    vnet_pfsync_uninit, NULL);
3445static int
3446pfsync_modevent(module_t mod, int type, void *data)
3447{
3448	int error = 0;
3449
3450	switch (type) {
3451	case MOD_LOAD:
3452#ifndef __FreeBSD__
3453		pfsyncattach(0);
3454#endif
3455		break;
3456	case MOD_UNLOAD:
3457#ifndef __FreeBSD__
3458		if_clone_detach(&pfsync_cloner);
3459#endif
3460		break;
3461	default:
3462		error = EINVAL;
3463		break;
3464	}
3465
3466	return error;
3467}
3468
3469static moduledata_t pfsync_mod = {
3470	"pfsync",
3471	pfsync_modevent,
3472	0
3473};
3474
3475#define PFSYNC_MODVER 1
3476
3477DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
3478MODULE_VERSION(pfsync, PFSYNC_MODVER);
3479MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER);
3480#endif /* __FreeBSD__ */
3481