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