if_pfsync.c revision 223637
1223637Sbz/*	$OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $	*/
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2002 Michael Shalayeff
5126258Smlaier * All rights reserved.
6126258Smlaier *
7126258Smlaier * Redistribution and use in source and binary forms, with or without
8126258Smlaier * modification, are permitted provided that the following conditions
9126258Smlaier * are met:
10126258Smlaier * 1. Redistributions of source code must retain the above copyright
11126258Smlaier *    notice, this list of conditions and the following disclaimer.
12126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright
13126258Smlaier *    notice, this list of conditions and the following disclaimer in the
14126258Smlaier *    documentation and/or other materials provided with the distribution.
15126258Smlaier *
16126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE.
27126258Smlaier */
28126258Smlaier
29223637Sbz/*
30223637Sbz * Copyright (c) 2009 David Gwynne <dlg@openbsd.org>
31223637Sbz *
32223637Sbz * Permission to use, copy, modify, and distribute this software for any
33223637Sbz * purpose with or without fee is hereby granted, provided that the above
34223637Sbz * copyright notice and this permission notice appear in all copies.
35223637Sbz *
36223637Sbz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
37223637Sbz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
38223637Sbz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
39223637Sbz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40223637Sbz * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
41223637Sbz * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
42223637Sbz * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43223637Sbz */
44223637Sbz
45127145Smlaier#ifdef __FreeBSD__
46126261Smlaier#include "opt_inet.h"
47126261Smlaier#include "opt_inet6.h"
48126261Smlaier#include "opt_bpf.h"
49126261Smlaier#include "opt_pf.h"
50153110Sru
51171168Smlaier#include <sys/cdefs.h>
52171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 223637 2011-06-28 11:57:25Z bz $");
53171168Smlaier
54153110Sru#ifdef DEV_BPF
55127145Smlaier#define	NBPFILTER	DEV_BPF
56153110Sru#else
57153110Sru#define	NBPFILTER	0
58153110Sru#endif
59153110Sru
60153110Sru#ifdef DEV_PFSYNC
61127145Smlaier#define	NPFSYNC		DEV_PFSYNC
62153110Sru#else
63153110Sru#define	NPFSYNC		0
64126261Smlaier#endif
65126258Smlaier
66171168Smlaier#ifdef DEV_CARP
67171168Smlaier#define	NCARP		DEV_CARP
68171168Smlaier#else
69171168Smlaier#define	NCARP		0
70153110Sru#endif
71171168Smlaier#endif /* __FreeBSD__ */
72153110Sru
73126258Smlaier#include <sys/param.h>
74223637Sbz#include <sys/kernel.h>
75164033Srwatson#ifdef __FreeBSD__
76223637Sbz#include <sys/bus.h>
77223637Sbz#include <sys/interrupt.h>
78164033Srwatson#include <sys/priv.h>
79164033Srwatson#endif
80130613Smlaier#include <sys/proc.h>
81126258Smlaier#include <sys/systm.h>
82126258Smlaier#include <sys/time.h>
83126258Smlaier#include <sys/mbuf.h>
84126258Smlaier#include <sys/socket.h>
85127145Smlaier#ifdef __FreeBSD__
86145836Smlaier#include <sys/endian.h>
87126261Smlaier#include <sys/malloc.h>
88129907Smlaier#include <sys/module.h>
89126261Smlaier#include <sys/sockio.h>
90171168Smlaier#include <sys/taskqueue.h>
91130613Smlaier#include <sys/lock.h>
92130613Smlaier#include <sys/mutex.h>
93126261Smlaier#else
94126258Smlaier#include <sys/ioctl.h>
95126258Smlaier#include <sys/timeout.h>
96126261Smlaier#endif
97223637Sbz#include <sys/sysctl.h>
98223637Sbz#ifndef __FreeBSD__
99223637Sbz#include <sys/pool.h>
100223637Sbz#endif
101126258Smlaier
102126258Smlaier#include <net/if.h>
103171168Smlaier#ifdef __FreeBSD__
104130933Sbrooks#include <net/if_clone.h>
105130933Sbrooks#endif
106126258Smlaier#include <net/if_types.h>
107126258Smlaier#include <net/route.h>
108126258Smlaier#include <net/bpf.h>
109223637Sbz#include <net/netisr.h>
110223637Sbz#ifdef __FreeBSD__
111223637Sbz#include <net/vnet.h>
112223637Sbz#endif
113223637Sbz
114171168Smlaier#include <netinet/in.h>
115171168Smlaier#include <netinet/if_ether.h>
116145836Smlaier#include <netinet/tcp.h>
117145836Smlaier#include <netinet/tcp_seq.h>
118126258Smlaier
119126258Smlaier#ifdef	INET
120130613Smlaier#include <netinet/in_systm.h>
121126258Smlaier#include <netinet/in_var.h>
122130613Smlaier#include <netinet/ip.h>
123130613Smlaier#include <netinet/ip_var.h>
124126258Smlaier#endif
125126258Smlaier
126126258Smlaier#ifdef INET6
127126258Smlaier#include <netinet6/nd6.h>
128126258Smlaier#endif /* INET6 */
129126258Smlaier
130171168Smlaier#ifndef __FreeBSD__
131145836Smlaier#include "carp.h"
132145836Smlaier#endif
133145836Smlaier#if NCARP > 0
134171168Smlaier#include <netinet/ip_carp.h>
135145836Smlaier#endif
136145836Smlaier
137126258Smlaier#include <net/pfvar.h>
138126258Smlaier#include <net/if_pfsync.h>
139126258Smlaier
140171168Smlaier#ifndef __FreeBSD__
141171168Smlaier#include "bpfilter.h"
142171168Smlaier#include "pfsync.h"
143126261Smlaier#endif
144126261Smlaier
145223637Sbz#define PFSYNC_MINPKT ( \
146223637Sbz	sizeof(struct ip) + \
147223637Sbz	sizeof(struct pfsync_header) + \
148223637Sbz	sizeof(struct pfsync_subheader) + \
149223637Sbz	sizeof(struct pfsync_eof))
150126258Smlaier
151223637Sbzstruct pfsync_pkt {
152223637Sbz	struct ip *ip;
153223637Sbz	struct in_addr src;
154223637Sbz	u_int8_t flags;
155223637Sbz};
156223637Sbz
157223637Sbzint	pfsync_input_hmac(struct mbuf *, int);
158223637Sbz
159223637Sbzint	pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *,
160223637Sbz	    struct pfsync_state_peer *);
161223637Sbz
162223637Sbzint	pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int);
163223637Sbzint	pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int);
164223637Sbzint	pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int);
165223637Sbzint	pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int);
166223637Sbzint	pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int);
167223637Sbzint	pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int);
168223637Sbzint	pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int);
169223637Sbzint	pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int);
170223637Sbzint	pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int);
171223637Sbzint	pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int);
172223637Sbzint	pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int);
173223637Sbz
174223637Sbzint	pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int);
175223637Sbz
176223637Sbzint	(*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = {
177223637Sbz	pfsync_in_clr,			/* PFSYNC_ACT_CLR */
178223637Sbz	pfsync_in_ins,			/* PFSYNC_ACT_INS */
179223637Sbz	pfsync_in_iack,			/* PFSYNC_ACT_INS_ACK */
180223637Sbz	pfsync_in_upd,			/* PFSYNC_ACT_UPD */
181223637Sbz	pfsync_in_upd_c,		/* PFSYNC_ACT_UPD_C */
182223637Sbz	pfsync_in_ureq,			/* PFSYNC_ACT_UPD_REQ */
183223637Sbz	pfsync_in_del,			/* PFSYNC_ACT_DEL */
184223637Sbz	pfsync_in_del_c,		/* PFSYNC_ACT_DEL_C */
185223637Sbz	pfsync_in_error,		/* PFSYNC_ACT_INS_F */
186223637Sbz	pfsync_in_error,		/* PFSYNC_ACT_DEL_F */
187223637Sbz	pfsync_in_bus,			/* PFSYNC_ACT_BUS */
188223637Sbz	pfsync_in_tdb,			/* PFSYNC_ACT_TDB */
189223637Sbz	pfsync_in_eof			/* PFSYNC_ACT_EOF */
190223637Sbz};
191223637Sbz
192223637Sbzstruct pfsync_q {
193223637Sbz	int		(*write)(struct pf_state *, struct mbuf *, int);
194223637Sbz	size_t		len;
195223637Sbz	u_int8_t	action;
196223637Sbz};
197223637Sbz
198223637Sbz/* we have one of these for every PFSYNC_S_ */
199223637Sbzint	pfsync_out_state(struct pf_state *, struct mbuf *, int);
200223637Sbzint	pfsync_out_iack(struct pf_state *, struct mbuf *, int);
201223637Sbzint	pfsync_out_upd_c(struct pf_state *, struct mbuf *, int);
202223637Sbzint	pfsync_out_del(struct pf_state *, struct mbuf *, int);
203223637Sbz
204223637Sbzstruct pfsync_q pfsync_qs[] = {
205223637Sbz	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_INS },
206223637Sbz	{ pfsync_out_iack,  sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
207223637Sbz	{ pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_UPD },
208223637Sbz	{ pfsync_out_upd_c, sizeof(struct pfsync_upd_c),   PFSYNC_ACT_UPD_C },
209223637Sbz	{ pfsync_out_del,   sizeof(struct pfsync_del_c),   PFSYNC_ACT_DEL_C }
210223637Sbz};
211223637Sbz
212223637Sbzvoid	pfsync_q_ins(struct pf_state *, int);
213223637Sbzvoid	pfsync_q_del(struct pf_state *);
214223637Sbz
215223637Sbzstruct pfsync_upd_req_item {
216223637Sbz	TAILQ_ENTRY(pfsync_upd_req_item)	ur_entry;
217223637Sbz	struct pfsync_upd_req			ur_msg;
218223637Sbz};
219223637SbzTAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item);
220223637Sbz
221223637Sbzstruct pfsync_deferral {
222223637Sbz	TAILQ_ENTRY(pfsync_deferral)		 pd_entry;
223223637Sbz	struct pf_state				*pd_st;
224223637Sbz	struct mbuf				*pd_m;
225223637Sbz#ifdef __FreeBSD__
226223637Sbz	struct callout				 pd_tmo;
227126258Smlaier#else
228223637Sbz	struct timeout				 pd_tmo;
229126258Smlaier#endif
230223637Sbz};
231223637SbzTAILQ_HEAD(pfsync_deferrals, pfsync_deferral);
232126258Smlaier
233223637Sbz#define PFSYNC_PLSIZE	MAX(sizeof(struct pfsync_upd_req_item), \
234223637Sbz			    sizeof(struct pfsync_deferral))
235223637Sbz
236223637Sbz#ifdef notyet
237223637Sbzint	pfsync_out_tdb(struct tdb *, struct mbuf *, int);
238223637Sbz#endif
239223637Sbz
240223637Sbzstruct pfsync_softc {
241223637Sbz#ifdef __FreeBSD__
242223637Sbz	struct ifnet		*sc_ifp;
243223637Sbz#else
244223637Sbz	struct ifnet		 sc_if;
245223637Sbz#endif
246223637Sbz	struct ifnet		*sc_sync_if;
247223637Sbz
248223637Sbz#ifdef __FreeBSD__
249223637Sbz	uma_zone_t		 sc_pool;
250223637Sbz#else
251223637Sbz	struct pool		 sc_pool;
252223637Sbz#endif
253223637Sbz
254223637Sbz	struct ip_moptions	 sc_imo;
255223637Sbz
256223637Sbz	struct in_addr		 sc_sync_peer;
257223637Sbz	u_int8_t		 sc_maxupdates;
258223637Sbz#ifdef __FreeBSD__
259223637Sbz	int			 pfsync_sync_ok;
260223637Sbz#endif
261223637Sbz
262223637Sbz	struct ip		 sc_template;
263223637Sbz
264223637Sbz	struct pf_state_queue	 sc_qs[PFSYNC_S_COUNT];
265223637Sbz	size_t			 sc_len;
266223637Sbz
267223637Sbz	struct pfsync_upd_reqs	 sc_upd_req_list;
268223637Sbz
269223637Sbz	struct pfsync_deferrals	 sc_deferrals;
270223637Sbz	u_int			 sc_deferred;
271223637Sbz
272223637Sbz	void			*sc_plus;
273223637Sbz	size_t			 sc_pluslen;
274223637Sbz
275223637Sbz	u_int32_t		 sc_ureq_sent;
276223637Sbz	int			 sc_bulk_tries;
277223637Sbz#ifdef __FreeBSD__
278223637Sbz	struct callout		 sc_bulkfail_tmo;
279223637Sbz#else
280223637Sbz	struct timeout		 sc_bulkfail_tmo;
281223637Sbz#endif
282223637Sbz
283223637Sbz	u_int32_t		 sc_ureq_received;
284223637Sbz	struct pf_state		*sc_bulk_next;
285223637Sbz	struct pf_state		*sc_bulk_last;
286223637Sbz#ifdef __FreeBSD__
287223637Sbz	struct callout		 sc_bulk_tmo;
288223637Sbz#else
289223637Sbz	struct timeout		 sc_bulk_tmo;
290223637Sbz#endif
291223637Sbz
292223637Sbz	TAILQ_HEAD(, tdb)	 sc_tdb_q;
293223637Sbz
294223637Sbz#ifdef __FreeBSD__
295223637Sbz	struct callout		 sc_tmo;
296223637Sbz#else
297223637Sbz	struct timeout		 sc_tmo;
298223637Sbz#endif
299223637Sbz#ifdef __FreeBSD__
300223637Sbz	eventhandler_tag	 sc_detachtag;
301223637Sbz#endif
302223637Sbz
303223637Sbz};
304223637Sbz
305223637Sbz#ifdef __FreeBSD__
306223637Sbzstatic VNET_DEFINE(struct pfsync_softc	*, pfsyncif) = NULL;
307223637Sbz#define	V_pfsyncif		VNET(pfsyncif)
308223637Sbz
309223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats);
310223637Sbz#define	V_pfsyncstats		VNET(pfsyncstats)
311223637Sbz
312223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC");
313223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW,
314223637Sbz    &VNET_NAME(pfsyncstats), pfsyncstats,
315223637Sbz    "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
316223637Sbz#else
317171168Smlaierstruct pfsync_softc	*pfsyncif = NULL;
318171168Smlaierstruct pfsyncstats	 pfsyncstats;
319223637Sbz#define	V_pfsyncstats	 pfsyncstats
320223637Sbz#endif
321223637Sbz
322127145Smlaier#ifdef __FreeBSD__
323223637Sbzstatic void	pfsyncintr(void *);
324223637Sbzstruct pfsync_swi {
325223637Sbz	void *	pfsync_swi_cookie;
326223637Sbz};
327223637Sbzstatic struct pfsync_swi	 pfsync_swi;
328223637Sbz#define	schednetisr(p)	swi_sched(pfsync_swi.pfsync_swi_cookie, 0)
329223637Sbz#define	NETISR_PFSYNC
330171168Smlaier#endif
331130613Smlaier
332171168Smlaiervoid	pfsyncattach(int);
333171168Smlaier#ifdef __FreeBSD__
334171168Smlaierint	pfsync_clone_create(struct if_clone *, int, caddr_t);
335171168Smlaiervoid	pfsync_clone_destroy(struct ifnet *);
336126261Smlaier#else
337171168Smlaierint	pfsync_clone_create(struct if_clone *, int);
338171168Smlaierint	pfsync_clone_destroy(struct ifnet *);
339126261Smlaier#endif
340171168Smlaierint	pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
341171168Smlaier	    struct pf_state_peer *);
342171168Smlaiervoid	pfsync_update_net_tdb(struct pfsync_tdb *);
343126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
344223637Sbz#ifdef __FreeBSD__
345191148Skmacy	    struct route *);
346223637Sbz#else
347223637Sbz	    struct rtentry *);
348223637Sbz#endif
349126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
350126258Smlaiervoid	pfsyncstart(struct ifnet *);
351126258Smlaier
352223637Sbzstruct mbuf *pfsync_if_dequeue(struct ifnet *);
353223637Sbzstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *);
354223637Sbz
355223637Sbzvoid	pfsync_deferred(struct pf_state *, int);
356223637Sbzvoid	pfsync_undefer(struct pfsync_deferral *, int);
357223637Sbzvoid	pfsync_defer_tmo(void *);
358223637Sbz
359223637Sbzvoid	pfsync_request_update(u_int32_t, u_int64_t);
360223637Sbzvoid	pfsync_update_state_req(struct pf_state *);
361223637Sbz
362223637Sbzvoid	pfsync_drop(struct pfsync_softc *);
363223637Sbzvoid	pfsync_sendout(void);
364223637Sbzvoid	pfsync_send_plus(void *, size_t);
365171168Smlaierint	pfsync_tdb_sendout(struct pfsync_softc *);
366171168Smlaierint	pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
367130613Smlaiervoid	pfsync_timeout(void *);
368171168Smlaiervoid	pfsync_tdb_timeout(void *);
369130613Smlaiervoid	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
370223637Sbz
371223637Sbzvoid	pfsync_bulk_start(void);
372223637Sbzvoid	pfsync_bulk_status(u_int8_t);
373130613Smlaiervoid	pfsync_bulk_update(void *);
374223637Sbzvoid	pfsync_bulk_fail(void *);
375171168Smlaier
376167710Sbms#ifdef __FreeBSD__
377171168Smlaiervoid	pfsync_ifdetach(void *, struct ifnet *);
378171168Smlaier
379171168Smlaier/* XXX: ugly */
380171168Smlaier#define	betoh64		(unsigned long long)be64toh
381171168Smlaier#define	timeout_del	callout_stop
382167710Sbms#endif
383126258Smlaier
384223637Sbz#define PFSYNC_MAX_BULKTRIES	12
385223637Sbz#ifndef __FreeBSD__
386145836Smlaierint	pfsync_sync_ok;
387126261Smlaier#endif
388126258Smlaier
389127145Smlaier#ifdef __FreeBSD__
390130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1);
391171168Smlaier#else
392171168Smlaierstruct if_clone	pfsync_cloner =
393171168Smlaier    IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
394171168Smlaier#endif
395126261Smlaier
396171168Smlaiervoid
397171168Smlaierpfsyncattach(int npfsync)
398126261Smlaier{
399171168Smlaier	if_clone_attach(&pfsync_cloner);
400126261Smlaier}
401171168Smlaierint
402160195Ssam#ifdef __FreeBSD__
403171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param)
404160195Ssam#else
405126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
406160195Ssam#endif
407126261Smlaier{
408223637Sbz	struct pfsync_softc *sc;
409130613Smlaier	struct ifnet *ifp;
410223637Sbz	int q;
411126261Smlaier
412171168Smlaier	if (unit != 0)
413171168Smlaier		return (EINVAL);
414171168Smlaier
415223637Sbz#ifndef __FreeBSD__
416171168Smlaier	pfsync_sync_ok = 1;
417223637Sbz#endif
418223637Sbz
419223637Sbz	sc = malloc(sizeof(struct pfsync_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
420223637Sbz	if (sc == NULL)
421171168Smlaier		return (ENOMEM);
422223637Sbz
423223637Sbz	for (q = 0; q < PFSYNC_S_COUNT; q++)
424223637Sbz		TAILQ_INIT(&sc->sc_qs[q]);
425223637Sbz
426171168Smlaier#ifdef __FreeBSD__
427223637Sbz	sc->pfsync_sync_ok = 1;
428223637Sbz	sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE,
429223637Sbz			NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
430223637Sbz	if (sc->sc_pool == NULL) {
431223637Sbz		free(sc, M_DEVBUF);
432223637Sbz		return (ENOMEM);
433171168Smlaier	}
434223637Sbz#else
435223637Sbz	pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL);
436223637Sbz#endif
437223637Sbz	TAILQ_INIT(&sc->sc_upd_req_list);
438223637Sbz	TAILQ_INIT(&sc->sc_deferrals);
439223637Sbz	sc->sc_deferred = 0;
440171168Smlaier
441223637Sbz	TAILQ_INIT(&sc->sc_tdb_q);
442223637Sbz
443223637Sbz	sc->sc_len = PFSYNC_MINPKT;
444223637Sbz	sc->sc_maxupdates = 128;
445223637Sbz
446223637Sbz#ifdef __FreeBSD__
447223637Sbz	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
448223637Sbz	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF,
449223637Sbz	    M_NOWAIT | M_ZERO);
450223637Sbz	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
451223637Sbz	sc->sc_imo.imo_multicast_vif = -1;
452223637Sbz#else
453223637Sbz	sc->sc_imo.imo_membership = (struct in_multi **)malloc(
454223637Sbz	    (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
455223637Sbz	    M_WAITOK | M_ZERO);
456223637Sbz	sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
457223637Sbz#endif
458223637Sbz
459223637Sbz#ifdef __FreeBSD__
460223637Sbz	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
461147256Sbrooks	if (ifp == NULL) {
462223637Sbz		free(sc->sc_imo.imo_membership, M_DEVBUF);
463223637Sbz		uma_zdestroy(sc->sc_pool);
464223637Sbz		free(sc, M_DEVBUF);
465147256Sbrooks		return (ENOSPC);
466147256Sbrooks	}
467171168Smlaier	if_initname(ifp, ifc->ifc_name, unit);
468126261Smlaier
469223637Sbz	sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
470223637Sbz#ifdef __FreeBSD__
471223637Sbz	    pfsync_ifdetach, V_pfsyncif, EVENTHANDLER_PRI_ANY);
472223637Sbz#else
473171168Smlaier	    pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY);
474223637Sbz#endif
475223637Sbz	if (sc->sc_detachtag == NULL) {
476167710Sbms		if_free(ifp);
477223637Sbz		free(sc->sc_imo.imo_membership, M_DEVBUF);
478223637Sbz		uma_zdestroy(sc->sc_pool);
479223637Sbz		free(sc, M_DEVBUF);
480167710Sbms		return (ENOSPC);
481167710Sbms	}
482171168Smlaier#else
483223637Sbz	ifp = &sc->sc_if;
484171168Smlaier	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
485171168Smlaier#endif
486223637Sbz	ifp->if_softc = sc;
487130613Smlaier	ifp->if_ioctl = pfsyncioctl;
488130613Smlaier	ifp->if_output = pfsyncoutput;
489130613Smlaier	ifp->if_start = pfsyncstart;
490171168Smlaier	ifp->if_type = IFT_PFSYNC;
491130613Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
492223637Sbz	ifp->if_hdrlen = sizeof(struct pfsync_header);
493223637Sbz	ifp->if_mtu = 1500; /* XXX */
494171168Smlaier#ifdef __FreeBSD__
495223637Sbz	callout_init(&sc->sc_tmo, CALLOUT_MPSAFE);
496223637Sbz	callout_init(&sc->sc_bulk_tmo, CALLOUT_MPSAFE);
497223637Sbz	callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE);
498171168Smlaier#else
499223637Sbz	ifp->if_hardmtu = MCLBYTES; /* XXX */
500223637Sbz	timeout_set(&sc->sc_tmo, pfsync_timeout, sc);
501223637Sbz	timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc);
502223637Sbz	timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc);
503171168Smlaier#endif
504223637Sbz
505141584Smlaier	if_attach(ifp);
506171168Smlaier#ifndef __FreeBSD__
507171168Smlaier	if_alloc_sadl(ifp);
508171168Smlaier#endif
509126261Smlaier
510171168Smlaier#if NCARP > 0
511171168Smlaier	if_addgroup(ifp, "carp");
512171168Smlaier#endif
513171168Smlaier
514126261Smlaier#if NBPFILTER > 0
515171168Smlaier#ifdef __FreeBSD__
516141584Smlaier	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
517171168Smlaier#else
518223637Sbz	bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
519126261Smlaier#endif
520171168Smlaier#endif
521126261Smlaier
522223637Sbz#ifdef __FreeBSD__
523223637Sbz	V_pfsyncif = sc;
524223637Sbz#else
525223637Sbz	pfsyncif = sc;
526223637Sbz#endif
527223637Sbz
528126261Smlaier	return (0);
529126261Smlaier}
530171168Smlaier
531171168Smlaier#ifdef __FreeBSD__
532126261Smlaiervoid
533171168Smlaier#else
534171168Smlaierint
535171168Smlaier#endif
536171168Smlaierpfsync_clone_destroy(struct ifnet *ifp)
537126258Smlaier{
538223637Sbz	struct pfsync_softc *sc = ifp->if_softc;
539223637Sbz
540171168Smlaier#ifdef __FreeBSD__
541223637Sbz	EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
542171168Smlaier#endif
543223637Sbz	timeout_del(&sc->sc_bulk_tmo);
544223637Sbz	timeout_del(&sc->sc_tmo);
545223637Sbz#if NCARP > 0
546223637Sbz#ifdef notyet
547223637Sbz#ifdef __FreeBSD__
548223637Sbz	if (!sc->pfsync_sync_ok)
549223637Sbz#else
550223637Sbz	if (!pfsync_sync_ok)
551171168Smlaier#endif
552223637Sbz		carp_group_demote_adj(&sc->sc_if, -1);
553223637Sbz#endif
554223637Sbz#endif
555126258Smlaier#if NBPFILTER > 0
556171168Smlaier	bpfdetach(ifp);
557126258Smlaier#endif
558171168Smlaier	if_detach(ifp);
559223637Sbz
560223637Sbz	pfsync_drop(sc);
561223637Sbz
562223637Sbz	while (sc->sc_deferred > 0)
563223637Sbz		pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
564223637Sbz
565171168Smlaier#ifdef __FreeBSD__
566223637Sbz	UMA_DESTROY(sc->sc_pool);
567223637Sbz#else
568223637Sbz	pool_destroy(&sc->sc_pool);
569223637Sbz#endif
570223637Sbz#ifdef __FreeBSD__
571171168Smlaier	if_free(ifp);
572223637Sbz	free(sc->sc_imo.imo_membership, M_DEVBUF);
573223637Sbz#else
574223637Sbz	free(sc->sc_imo.imo_membership, M_IPMOPTS);
575171168Smlaier#endif
576223637Sbz	free(sc, M_DEVBUF);
577223637Sbz
578223637Sbz#ifdef __FreeBSD__
579223637Sbz	V_pfsyncif = NULL;
580223637Sbz#else
581171168Smlaier	pfsyncif = NULL;
582223637Sbz#endif
583223637Sbz
584171168Smlaier#ifndef __FreeBSD__
585171168Smlaier	return (0);
586171168Smlaier#endif
587126258Smlaier}
588126258Smlaier
589223637Sbzstruct mbuf *
590223637Sbzpfsync_if_dequeue(struct ifnet *ifp)
591223637Sbz{
592223637Sbz	struct mbuf *m;
593223637Sbz#ifndef __FreeBSD__
594223637Sbz	int s;
595223637Sbz#endif
596223637Sbz
597223637Sbz#ifdef __FreeBSD__
598223637Sbz	IF_LOCK(&ifp->if_snd);
599223637Sbz	_IF_DROP(&ifp->if_snd);
600223637Sbz	_IF_DEQUEUE(&ifp->if_snd, m);
601223637Sbz	IF_UNLOCK(&ifp->if_snd);
602223637Sbz#else
603223637Sbz	s = splnet();
604223637Sbz	IF_DEQUEUE(&ifp->if_snd, m);
605223637Sbz	splx(s);
606223637Sbz#endif
607223637Sbz
608223637Sbz	return (m);
609223637Sbz}
610223637Sbz
611126258Smlaier/*
612126258Smlaier * Start output on the pfsync interface.
613126258Smlaier */
614126258Smlaiervoid
615126258Smlaierpfsyncstart(struct ifnet *ifp)
616126258Smlaier{
617126258Smlaier	struct mbuf *m;
618223637Sbz
619223637Sbz	while ((m = pfsync_if_dequeue(ifp)) != NULL) {
620171168Smlaier#ifndef __FreeBSD__
621126258Smlaier		IF_DROP(&ifp->if_snd);
622171168Smlaier#endif
623223637Sbz		m_freem(m);
624126258Smlaier	}
625126258Smlaier}
626126258Smlaier
627126258Smlaierint
628171168Smlaierpfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
629171168Smlaier    struct pf_state_peer *d)
630130613Smlaier{
631171168Smlaier	if (s->scrub.scrub_flag && d->scrub == NULL) {
632223637Sbz#ifdef __FreeBSD__
633223637Sbz		d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
634223637Sbz#else
635223637Sbz		d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO);
636223637Sbz#endif
637171168Smlaier		if (d->scrub == NULL)
638171168Smlaier			return (ENOMEM);
639171168Smlaier	}
640171168Smlaier
641171168Smlaier	return (0);
642171168Smlaier}
643171168Smlaier
644223637Sbz#ifndef __FreeBSD__
645223637Sbzvoid
646223637Sbzpfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
647223637Sbz{
648223637Sbz	bzero(sp, sizeof(struct pfsync_state));
649223637Sbz
650223637Sbz	/* copy from state key */
651223637Sbz	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
652223637Sbz	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
653223637Sbz	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
654223637Sbz	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
655223637Sbz	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
656223637Sbz	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
657223637Sbz	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
658223637Sbz	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
659223637Sbz	sp->proto = st->key[PF_SK_WIRE]->proto;
660223637Sbz	sp->af = st->key[PF_SK_WIRE]->af;
661223637Sbz
662223637Sbz	/* copy from state */
663223637Sbz	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
664223637Sbz	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
665223637Sbz	sp->creation = htonl(time_second - st->creation);
666223637Sbz	sp->expire = pf_state_expires(st);
667223637Sbz	if (sp->expire <= time_second)
668223637Sbz		sp->expire = htonl(0);
669223637Sbz	else
670223637Sbz		sp->expire = htonl(sp->expire - time_second);
671223637Sbz
672223637Sbz	sp->direction = st->direction;
673223637Sbz	sp->log = st->log;
674223637Sbz	sp->timeout = st->timeout;
675223637Sbz	sp->state_flags = st->state_flags;
676223637Sbz	if (st->src_node)
677223637Sbz		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
678223637Sbz	if (st->nat_src_node)
679223637Sbz		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
680223637Sbz
681223637Sbz	bcopy(&st->id, &sp->id, sizeof(sp->id));
682223637Sbz	sp->creatorid = st->creatorid;
683223637Sbz	pf_state_peer_hton(&st->src, &sp->src);
684223637Sbz	pf_state_peer_hton(&st->dst, &sp->dst);
685223637Sbz
686223637Sbz	if (st->rule.ptr == NULL)
687223637Sbz		sp->rule = htonl(-1);
688223637Sbz	else
689223637Sbz		sp->rule = htonl(st->rule.ptr->nr);
690223637Sbz	if (st->anchor.ptr == NULL)
691223637Sbz		sp->anchor = htonl(-1);
692223637Sbz	else
693223637Sbz		sp->anchor = htonl(st->anchor.ptr->nr);
694223637Sbz	if (st->nat_rule.ptr == NULL)
695223637Sbz		sp->nat_rule = htonl(-1);
696223637Sbz	else
697223637Sbz		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
698223637Sbz
699223637Sbz	pf_state_counter_hton(st->packets[0], sp->packets[0]);
700223637Sbz	pf_state_counter_hton(st->packets[1], sp->packets[1]);
701223637Sbz	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
702223637Sbz	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
703223637Sbz
704223637Sbz}
705223637Sbz#endif
706223637Sbz
707171168Smlaierint
708223637Sbzpfsync_state_import(struct pfsync_state *sp, u_int8_t flags)
709171168Smlaier{
710130613Smlaier	struct pf_state	*st = NULL;
711223637Sbz	struct pf_state_key *skw = NULL, *sks = NULL;
712130613Smlaier	struct pf_rule *r = NULL;
713130613Smlaier	struct pfi_kif	*kif;
714223637Sbz	int pool_flags;
715223637Sbz	int error;
716130613Smlaier
717223637Sbz#ifdef __FreeBSD__
718223637Sbz	if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) {
719223637Sbz#else
720130613Smlaier	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
721223637Sbz#endif
722223637Sbz		printf("pfsync_state_import: invalid creator id:"
723130613Smlaier		    " %08x\n", ntohl(sp->creatorid));
724130613Smlaier		return (EINVAL);
725130613Smlaier	}
726130613Smlaier
727223637Sbz	if ((kif = pfi_kif_get(sp->ifname)) == NULL) {
728223637Sbz#ifdef __FreeBSD__
729223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC)
730223637Sbz#else
731130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
732223637Sbz#endif
733223637Sbz			printf("pfsync_state_import: "
734130613Smlaier			    "unknown interface: %s\n", sp->ifname);
735223637Sbz		if (flags & PFSYNC_SI_IOCTL)
736223637Sbz			return (EINVAL);
737223637Sbz		return (0);	/* skip this state */
738130613Smlaier	}
739130613Smlaier
740130613Smlaier	/*
741223637Sbz	 * If the ruleset checksums match or the state is coming from the ioctl,
742223637Sbz	 * it's safe to associate the state with the rule of that number.
743130613Smlaier	 */
744223637Sbz	if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
745223637Sbz	    (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
746223637Sbz	    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
747171168Smlaier		r = pf_main_ruleset.rules[
748171168Smlaier		    PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
749171168Smlaier	else
750223637Sbz#ifdef __FreeBSD__
751223637Sbz		r = &V_pf_default_rule;
752223637Sbz#else
753171168Smlaier		r = &pf_default_rule;
754223637Sbz#endif
755130613Smlaier
756223637Sbz	if ((r->max_states && r->states_cur >= r->max_states))
757223637Sbz		goto cleanup;
758130613Smlaier
759223637Sbz#ifdef __FreeBSD__
760223637Sbz	if (flags & PFSYNC_SI_IOCTL)
761223637Sbz		pool_flags = PR_WAITOK | PR_ZERO;
762223637Sbz	else
763223637Sbz		pool_flags = PR_ZERO;
764171168Smlaier
765223637Sbz	if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL)
766223637Sbz		goto cleanup;
767223637Sbz#else
768223637Sbz	if (flags & PFSYNC_SI_IOCTL)
769223637Sbz		pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO;
770223637Sbz	else
771223637Sbz		pool_flags = PR_LIMITFAIL | PR_ZERO;
772130613Smlaier
773223637Sbz	if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL)
774223637Sbz		goto cleanup;
775223637Sbz#endif
776145836Smlaier
777223637Sbz	if ((skw = pf_alloc_state_key(pool_flags)) == NULL)
778223637Sbz		goto cleanup;
779130613Smlaier
780223637Sbz	if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0],
781223637Sbz	    &sp->key[PF_SK_STACK].addr[0], sp->af) ||
782223637Sbz	    PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1],
783223637Sbz	    &sp->key[PF_SK_STACK].addr[1], sp->af) ||
784223637Sbz	    sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] ||
785223637Sbz	    sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) {
786223637Sbz		if ((sks = pf_alloc_state_key(pool_flags)) == NULL)
787223637Sbz			goto cleanup;
788223637Sbz	} else
789223637Sbz		sks = skw;
790130613Smlaier
791223637Sbz	/* allocate memory for scrub info */
792223637Sbz	if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
793223637Sbz	    pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
794223637Sbz		goto cleanup;
795223637Sbz
796223637Sbz	/* copy to state key(s) */
797223637Sbz	skw->addr[0] = sp->key[PF_SK_WIRE].addr[0];
798223637Sbz	skw->addr[1] = sp->key[PF_SK_WIRE].addr[1];
799223637Sbz	skw->port[0] = sp->key[PF_SK_WIRE].port[0];
800223637Sbz	skw->port[1] = sp->key[PF_SK_WIRE].port[1];
801223637Sbz	skw->proto = sp->proto;
802223637Sbz	skw->af = sp->af;
803223637Sbz	if (sks != skw) {
804223637Sbz		sks->addr[0] = sp->key[PF_SK_STACK].addr[0];
805223637Sbz		sks->addr[1] = sp->key[PF_SK_STACK].addr[1];
806223637Sbz		sks->port[0] = sp->key[PF_SK_STACK].port[0];
807223637Sbz		sks->port[1] = sp->key[PF_SK_STACK].port[1];
808223637Sbz		sks->proto = sp->proto;
809223637Sbz		sks->af = sp->af;
810223637Sbz	}
811223637Sbz
812223637Sbz	/* copy to state */
813130613Smlaier	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
814145836Smlaier	st->creation = time_second - ntohl(sp->creation);
815223637Sbz	st->expire = time_second;
816223637Sbz	if (sp->expire) {
817223637Sbz		/* XXX No adaptive scaling. */
818223637Sbz		st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire);
819223637Sbz	}
820223637Sbz
821130613Smlaier	st->expire = ntohl(sp->expire) + time_second;
822130613Smlaier	st->direction = sp->direction;
823130613Smlaier	st->log = sp->log;
824130613Smlaier	st->timeout = sp->timeout;
825200930Sdelphij	st->state_flags = sp->state_flags;
826130613Smlaier
827130613Smlaier	bcopy(sp->id, &st->id, sizeof(st->id));
828130613Smlaier	st->creatorid = sp->creatorid;
829223637Sbz	pf_state_peer_ntoh(&sp->src, &st->src);
830223637Sbz	pf_state_peer_ntoh(&sp->dst, &st->dst);
831130613Smlaier
832223637Sbz	st->rule.ptr = r;
833223637Sbz	st->nat_rule.ptr = NULL;
834223637Sbz	st->anchor.ptr = NULL;
835223637Sbz	st->rt_kif = NULL;
836223637Sbz
837223637Sbz	st->pfsync_time = time_second;
838223637Sbz	st->sync_state = PFSYNC_S_NONE;
839223637Sbz
840223637Sbz	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
841223637Sbz	r->states_cur++;
842223637Sbz	r->states_tot++;
843223637Sbz
844223637Sbz	if (!ISSET(flags, PFSYNC_SI_IOCTL))
845223637Sbz		SET(st->state_flags, PFSTATE_NOSYNC);
846223637Sbz
847223637Sbz	if ((error = pf_state_insert(kif, skw, sks, st)) != 0) {
848145836Smlaier		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
849223637Sbz		r->states_cur--;
850223637Sbz		goto cleanup_state;
851223637Sbz	}
852223637Sbz
853223637Sbz	if (!ISSET(flags, PFSYNC_SI_IOCTL)) {
854223637Sbz		CLR(st->state_flags, PFSTATE_NOSYNC);
855223637Sbz		if (ISSET(st->state_flags, PFSTATE_ACK)) {
856223637Sbz			pfsync_q_ins(st, PFSYNC_S_IACK);
857223637Sbz			schednetisr(NETISR_PFSYNC);
858223637Sbz		}
859223637Sbz	}
860223637Sbz	CLR(st->state_flags, PFSTATE_ACK);
861223637Sbz
862223637Sbz	return (0);
863223637Sbz
864223637Sbzcleanup:
865223637Sbz	error = ENOMEM;
866223637Sbz	if (skw == sks)
867223637Sbz		sks = NULL;
868223637Sbz#ifdef __FreeBSD__
869223637Sbz	if (skw != NULL)
870223637Sbz		pool_put(&V_pf_state_key_pl, skw);
871223637Sbz	if (sks != NULL)
872223637Sbz		pool_put(&V_pf_state_key_pl, sks);
873223637Sbz#else
874223637Sbz	if (skw != NULL)
875223637Sbz		pool_put(&pf_state_key_pl, skw);
876223637Sbz	if (sks != NULL)
877223637Sbz		pool_put(&pf_state_key_pl, sks);
878223637Sbz#endif
879223637Sbz
880223637Sbzcleanup_state:	/* pf_state_insert frees the state keys */
881223637Sbz	if (st) {
882223637Sbz#ifdef __FreeBSD__
883171168Smlaier		if (st->dst.scrub)
884223637Sbz			pool_put(&V_pf_state_scrub_pl, st->dst.scrub);
885223637Sbz		if (st->src.scrub)
886223637Sbz			pool_put(&V_pf_state_scrub_pl, st->src.scrub);
887223637Sbz		pool_put(&V_pf_state_pl, st);
888223637Sbz#else
889223637Sbz		if (st->dst.scrub)
890171168Smlaier			pool_put(&pf_state_scrub_pl, st->dst.scrub);
891171168Smlaier		if (st->src.scrub)
892171168Smlaier			pool_put(&pf_state_scrub_pl, st->src.scrub);
893130613Smlaier		pool_put(&pf_state_pl, st);
894223637Sbz#endif
895130613Smlaier	}
896223637Sbz	return (error);
897130613Smlaier}
898130613Smlaier
899130613Smlaiervoid
900130613Smlaier#ifdef __FreeBSD__
901130613Smlaierpfsync_input(struct mbuf *m, __unused int off)
902130613Smlaier#else
903130613Smlaierpfsync_input(struct mbuf *m, ...)
904130613Smlaier#endif
905130613Smlaier{
906223637Sbz#ifdef __FreeBSD__
907223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
908223637Sbz#else
909223637Sbz	struct pfsync_softc *sc = pfsyncif;
910223637Sbz#endif
911223637Sbz	struct pfsync_pkt pkt;
912130613Smlaier	struct ip *ip = mtod(m, struct ip *);
913130613Smlaier	struct pfsync_header *ph;
914223637Sbz	struct pfsync_subheader subh;
915130613Smlaier
916223637Sbz	int offset;
917223637Sbz	int rv;
918130613Smlaier
919223637Sbz	V_pfsyncstats.pfsyncs_ipackets++;
920223637Sbz
921130613Smlaier	/* verify that we have a sync interface configured */
922223637Sbz#ifdef __FreeBSD__
923223637Sbz	if (!sc || !sc->sc_sync_if || !V_pf_status.running)
924223637Sbz#else
925223637Sbz	if (!sc || !sc->sc_sync_if || !pf_status.running)
926223637Sbz#endif
927130613Smlaier		goto done;
928130613Smlaier
929130613Smlaier	/* verify that the packet came in on the right interface */
930223637Sbz	if (sc->sc_sync_if != m->m_pkthdr.rcvif) {
931223637Sbz		V_pfsyncstats.pfsyncs_badif++;
932130613Smlaier		goto done;
933130613Smlaier	}
934130613Smlaier
935223637Sbz#ifdef __FreeBSD__
936223637Sbz	sc->sc_ifp->if_ipackets++;
937223637Sbz	sc->sc_ifp->if_ibytes += m->m_pkthdr.len;
938223637Sbz#else
939223637Sbz	sc->sc_if.if_ipackets++;
940223637Sbz	sc->sc_if.if_ibytes += m->m_pkthdr.len;
941223637Sbz#endif
942223637Sbz	/* verify that the IP TTL is 255. */
943130613Smlaier	if (ip->ip_ttl != PFSYNC_DFLTTL) {
944223637Sbz		V_pfsyncstats.pfsyncs_badttl++;
945130613Smlaier		goto done;
946130613Smlaier	}
947130613Smlaier
948223637Sbz	offset = ip->ip_hl << 2;
949223637Sbz	if (m->m_pkthdr.len < offset + sizeof(*ph)) {
950223637Sbz		V_pfsyncstats.pfsyncs_hdrops++;
951130613Smlaier		goto done;
952130613Smlaier	}
953130613Smlaier
954223637Sbz	if (offset + sizeof(*ph) > m->m_len) {
955223637Sbz		if (m_pullup(m, offset + sizeof(*ph)) == NULL) {
956223637Sbz			V_pfsyncstats.pfsyncs_hdrops++;
957223637Sbz			return;
958130613Smlaier		}
959130613Smlaier		ip = mtod(m, struct ip *);
960130613Smlaier	}
961223637Sbz	ph = (struct pfsync_header *)((char *)ip + offset);
962130613Smlaier
963130613Smlaier	/* verify the version */
964130613Smlaier	if (ph->version != PFSYNC_VERSION) {
965223637Sbz		V_pfsyncstats.pfsyncs_badver++;
966130613Smlaier		goto done;
967130613Smlaier	}
968130613Smlaier
969223637Sbz#if 0
970223637Sbz	if (pfsync_input_hmac(m, offset) != 0) {
971223637Sbz		/* XXX stats */
972130613Smlaier		goto done;
973130613Smlaier	}
974223637Sbz#endif
975130613Smlaier
976130613Smlaier	/* Cheaper to grab this now than having to mess with mbufs later */
977223637Sbz	pkt.ip = ip;
978223637Sbz	pkt.src = ip->ip_src;
979223637Sbz	pkt.flags = 0;
980130613Smlaier
981223637Sbz#ifdef __FreeBSD__
982223637Sbz	if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
983223637Sbz#else
984223637Sbz	if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
985223637Sbz#endif
986223637Sbz		pkt.flags |= PFSYNC_SI_CKSUM;
987171168Smlaier
988223637Sbz	offset += sizeof(*ph);
989223637Sbz	for (;;) {
990223637Sbz		m_copydata(m, offset, sizeof(subh), (caddr_t)&subh);
991223637Sbz		offset += sizeof(subh);
992223637Sbz
993223637Sbz		if (subh.action >= PFSYNC_ACT_MAX) {
994223637Sbz			V_pfsyncstats.pfsyncs_badact++;
995223637Sbz			goto done;
996130613Smlaier		}
997130613Smlaier
998223637Sbz		rv = (*pfsync_acts[subh.action])(&pkt, m, offset,
999223637Sbz		    ntohs(subh.count));
1000223637Sbz		if (rv == -1)
1001223637Sbz			return;
1002223637Sbz
1003223637Sbz		offset += rv;
1004223637Sbz	}
1005223637Sbz
1006223637Sbzdone:
1007223637Sbz	m_freem(m);
1008223637Sbz}
1009223637Sbz
1010223637Sbzint
1011223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1012223637Sbz{
1013223637Sbz	struct pfsync_clr *clr;
1014223637Sbz	struct mbuf *mp;
1015223637Sbz	int len = sizeof(*clr) * count;
1016223637Sbz	int i, offp;
1017223637Sbz
1018223637Sbz	struct pf_state *st, *nexts;
1019223637Sbz	struct pf_state_key *sk, *nextsk;
1020223637Sbz	struct pf_state_item *si;
1021223637Sbz	u_int32_t creatorid;
1022223637Sbz	int s;
1023223637Sbz
1024223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1025223637Sbz	if (mp == NULL) {
1026223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1027223637Sbz		return (-1);
1028223637Sbz	}
1029223637Sbz	clr = (struct pfsync_clr *)(mp->m_data + offp);
1030223637Sbz
1031223637Sbz	s = splsoftnet();
1032130613Smlaier#ifdef __FreeBSD__
1033223637Sbz	PF_LOCK();
1034130613Smlaier#endif
1035223637Sbz	for (i = 0; i < count; i++) {
1036223637Sbz		creatorid = clr[i].creatorid;
1037223637Sbz
1038223637Sbz		if (clr[i].ifname[0] == '\0') {
1039223637Sbz#ifdef __FreeBSD__
1040223637Sbz			for (st = RB_MIN(pf_state_tree_id, &V_tree_id);
1041223637Sbz			    st; st = nexts) {
1042223637Sbz				nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st);
1043223637Sbz#else
1044145836Smlaier			for (st = RB_MIN(pf_state_tree_id, &tree_id);
1045145836Smlaier			    st; st = nexts) {
1046171168Smlaier				nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
1047223637Sbz#endif
1048145836Smlaier				if (st->creatorid == creatorid) {
1049223637Sbz					SET(st->state_flags, PFSTATE_NOSYNC);
1050171168Smlaier					pf_unlink_state(st);
1051145836Smlaier				}
1052130613Smlaier			}
1053130613Smlaier		} else {
1054223637Sbz			if (pfi_kif_get(clr[i].ifname) == NULL)
1055223637Sbz				continue;
1056223637Sbz
1057223637Sbz			/* XXX correct? */
1058130613Smlaier#ifdef __FreeBSD__
1059223637Sbz			for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl);
1060223637Sbz#else
1061223637Sbz			for (sk = RB_MIN(pf_state_tree, &pf_statetbl);
1062130613Smlaier#endif
1063223637Sbz			    sk; sk = nextsk) {
1064223637Sbz				nextsk = RB_NEXT(pf_state_tree,
1065223637Sbz#ifdef __FreeBSD__
1066223637Sbz				    &V_pf_statetbl, sk);
1067223637Sbz#else
1068223637Sbz				    &pf_statetbl, sk);
1069223637Sbz#endif
1070223637Sbz				TAILQ_FOREACH(si, &sk->states, entry) {
1071223637Sbz					if (si->s->creatorid == creatorid) {
1072223637Sbz						SET(si->s->state_flags,
1073223637Sbz						    PFSTATE_NOSYNC);
1074223637Sbz						pf_unlink_state(si->s);
1075223637Sbz					}
1076145836Smlaier				}
1077130613Smlaier			}
1078130613Smlaier		}
1079223637Sbz	}
1080130613Smlaier#ifdef __FreeBSD__
1081223637Sbz	PF_UNLOCK();
1082130613Smlaier#endif
1083223637Sbz	splx(s);
1084130613Smlaier
1085223637Sbz	return (len);
1086223637Sbz}
1087223637Sbz
1088223637Sbzint
1089223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1090223637Sbz{
1091223637Sbz	struct mbuf *mp;
1092223637Sbz	struct pfsync_state *sa, *sp;
1093223637Sbz	int len = sizeof(*sp) * count;
1094223637Sbz	int i, offp;
1095223637Sbz
1096223637Sbz	int s;
1097223637Sbz
1098223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1099223637Sbz	if (mp == NULL) {
1100223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1101223637Sbz		return (-1);
1102130613Smlaier	}
1103223637Sbz	sa = (struct pfsync_state *)(mp->m_data + offp);
1104130613Smlaier
1105223637Sbz	s = splsoftnet();
1106130613Smlaier#ifdef __FreeBSD__
1107223637Sbz	PF_LOCK();
1108130613Smlaier#endif
1109223637Sbz	for (i = 0; i < count; i++) {
1110223637Sbz		sp = &sa[i];
1111130613Smlaier
1112223637Sbz		/* check for invalid values */
1113223637Sbz		if (sp->timeout >= PFTM_MAX ||
1114223637Sbz		    sp->src.state > PF_TCPS_PROXY_DST ||
1115223637Sbz		    sp->dst.state > PF_TCPS_PROXY_DST ||
1116223637Sbz		    sp->direction > PF_OUT ||
1117223637Sbz		    (sp->af != AF_INET && sp->af != AF_INET6)) {
1118130613Smlaier#ifdef __FreeBSD__
1119223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1120223637Sbz#else
1121223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
1122130613Smlaier#endif
1123223637Sbz				printf("pfsync_input: PFSYNC5_ACT_INS: "
1124223637Sbz				    "invalid value\n");
1125130613Smlaier			}
1126223637Sbz			V_pfsyncstats.pfsyncs_badval++;
1127223637Sbz			continue;
1128130613Smlaier		}
1129223637Sbz
1130223637Sbz		if (pfsync_state_import(sp, pkt->flags) == ENOMEM) {
1131223637Sbz			/* drop out, but process the rest of the actions */
1132223637Sbz			break;
1133223637Sbz		}
1134223637Sbz	}
1135130613Smlaier#ifdef __FreeBSD__
1136223637Sbz	PF_UNLOCK();
1137130613Smlaier#endif
1138223637Sbz	splx(s);
1139130613Smlaier
1140223637Sbz	return (len);
1141223637Sbz}
1142223637Sbz
1143223637Sbzint
1144223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1145223637Sbz{
1146223637Sbz	struct pfsync_ins_ack *ia, *iaa;
1147223637Sbz	struct pf_state_cmp id_key;
1148223637Sbz	struct pf_state *st;
1149223637Sbz
1150223637Sbz	struct mbuf *mp;
1151223637Sbz	int len = count * sizeof(*ia);
1152223637Sbz	int offp, i;
1153223637Sbz	int s;
1154223637Sbz
1155223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1156223637Sbz	if (mp == NULL) {
1157223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1158223637Sbz		return (-1);
1159223637Sbz	}
1160223637Sbz	iaa = (struct pfsync_ins_ack *)(mp->m_data + offp);
1161223637Sbz
1162223637Sbz	s = splsoftnet();
1163130613Smlaier#ifdef __FreeBSD__
1164223637Sbz	PF_LOCK();
1165130613Smlaier#endif
1166223637Sbz	for (i = 0; i < count; i++) {
1167223637Sbz		ia = &iaa[i];
1168145836Smlaier
1169223637Sbz		bcopy(&ia->id, &id_key.id, sizeof(id_key.id));
1170223637Sbz		id_key.creatorid = ia->creatorid;
1171130613Smlaier
1172223637Sbz		st = pf_find_state_byid(&id_key);
1173223637Sbz		if (st == NULL)
1174223637Sbz			continue;
1175130613Smlaier
1176223637Sbz		if (ISSET(st->state_flags, PFSTATE_ACK))
1177223637Sbz			pfsync_deferred(st, 0);
1178223637Sbz	}
1179130613Smlaier#ifdef __FreeBSD__
1180223637Sbz	PF_UNLOCK();
1181130613Smlaier#endif
1182223637Sbz	splx(s);
1183130613Smlaier	/*
1184223637Sbz	 * XXX this is not yet implemented, but we know the size of the
1185223637Sbz	 * message so we can skip it.
1186130613Smlaier	 */
1187130613Smlaier
1188223637Sbz	return (count * sizeof(struct pfsync_ins_ack));
1189223637Sbz}
1190223637Sbz
1191223637Sbzint
1192223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src,
1193223637Sbz    struct pfsync_state_peer *dst)
1194223637Sbz{
1195223637Sbz	int sfail = 0;
1196223637Sbz
1197223637Sbz	/*
1198223637Sbz	 * The state should never go backwards except
1199223637Sbz	 * for syn-proxy states.  Neither should the
1200223637Sbz	 * sequence window slide backwards.
1201223637Sbz	 */
1202223637Sbz	if (st->src.state > src->state &&
1203223637Sbz	    (st->src.state < PF_TCPS_PROXY_SRC ||
1204223637Sbz	    src->state >= PF_TCPS_PROXY_SRC))
1205223637Sbz		sfail = 1;
1206223637Sbz	else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))
1207223637Sbz		sfail = 3;
1208223637Sbz	else if (st->dst.state > dst->state) {
1209223637Sbz		/* There might still be useful
1210223637Sbz		 * information about the src state here,
1211223637Sbz		 * so import that part of the update,
1212223637Sbz		 * then "fail" so we send the updated
1213223637Sbz		 * state back to the peer who is missing
1214223637Sbz		 * our what we know. */
1215223637Sbz		pf_state_peer_ntoh(src, &st->src);
1216223637Sbz		/* XXX do anything with timeouts? */
1217223637Sbz		sfail = 7;
1218223637Sbz	} else if (st->dst.state >= TCPS_SYN_SENT &&
1219223637Sbz	    SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))
1220223637Sbz		sfail = 4;
1221223637Sbz
1222223637Sbz	return (sfail);
1223223637Sbz}
1224223637Sbz
1225223637Sbzint
1226223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1227223637Sbz{
1228223637Sbz	struct pfsync_state *sa, *sp;
1229223637Sbz	struct pf_state_cmp id_key;
1230223637Sbz	struct pf_state_key *sk;
1231223637Sbz	struct pf_state *st;
1232223637Sbz	int sfail;
1233223637Sbz
1234223637Sbz	struct mbuf *mp;
1235223637Sbz	int len = count * sizeof(*sp);
1236223637Sbz	int offp, i;
1237223637Sbz	int s;
1238223637Sbz
1239223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1240223637Sbz	if (mp == NULL) {
1241223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1242223637Sbz		return (-1);
1243223637Sbz	}
1244223637Sbz	sa = (struct pfsync_state *)(mp->m_data + offp);
1245223637Sbz
1246223637Sbz	s = splsoftnet();
1247130613Smlaier#ifdef __FreeBSD__
1248223637Sbz	PF_LOCK();
1249130613Smlaier#endif
1250223637Sbz	for (i = 0; i < count; i++) {
1251223637Sbz		sp = &sa[i];
1252130613Smlaier
1253223637Sbz		/* check for invalid values */
1254223637Sbz		if (sp->timeout >= PFTM_MAX ||
1255223637Sbz		    sp->src.state > PF_TCPS_PROXY_DST ||
1256223637Sbz		    sp->dst.state > PF_TCPS_PROXY_DST) {
1257223637Sbz#ifdef __FreeBSD__
1258223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1259223637Sbz#else
1260223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
1261223637Sbz#endif
1262223637Sbz				printf("pfsync_input: PFSYNC_ACT_UPD: "
1263223637Sbz				    "invalid value\n");
1264130613Smlaier			}
1265223637Sbz			V_pfsyncstats.pfsyncs_badval++;
1266223637Sbz			continue;
1267130613Smlaier		}
1268223637Sbz
1269223637Sbz		bcopy(sp->id, &id_key.id, sizeof(id_key.id));
1270223637Sbz		id_key.creatorid = sp->creatorid;
1271223637Sbz
1272223637Sbz		st = pf_find_state_byid(&id_key);
1273223637Sbz		if (st == NULL) {
1274223637Sbz			/* insert the update */
1275223637Sbz			if (pfsync_state_import(sp, 0))
1276223637Sbz				V_pfsyncstats.pfsyncs_badstate++;
1277223637Sbz			continue;
1278223637Sbz		}
1279223637Sbz
1280223637Sbz		if (ISSET(st->state_flags, PFSTATE_ACK))
1281223637Sbz			pfsync_deferred(st, 1);
1282223637Sbz
1283223637Sbz		sk = st->key[PF_SK_WIRE];	/* XXX right one? */
1284223637Sbz		sfail = 0;
1285223637Sbz		if (sk->proto == IPPROTO_TCP)
1286223637Sbz			sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst);
1287223637Sbz		else {
1288223637Sbz			/*
1289223637Sbz			 * Non-TCP protocol state machine always go
1290223637Sbz			 * forwards
1291223637Sbz			 */
1292223637Sbz			if (st->src.state > sp->src.state)
1293223637Sbz				sfail = 5;
1294223637Sbz			else if (st->dst.state > sp->dst.state)
1295223637Sbz				sfail = 6;
1296223637Sbz		}
1297223637Sbz
1298223637Sbz		if (sfail) {
1299130613Smlaier#ifdef __FreeBSD__
1300223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1301223637Sbz#else
1302223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
1303130613Smlaier#endif
1304223637Sbz				printf("pfsync: %s stale update (%d)"
1305223637Sbz				    " id: %016llx creatorid: %08x\n",
1306223637Sbz				    (sfail < 7 ?  "ignoring" : "partial"),
1307223637Sbz				    sfail, betoh64(st->id),
1308223637Sbz				    ntohl(st->creatorid));
1309223637Sbz			}
1310223637Sbz			V_pfsyncstats.pfsyncs_stale++;
1311130613Smlaier
1312223637Sbz			pfsync_update_state(st);
1313223637Sbz			schednetisr(NETISR_PFSYNC);
1314223637Sbz			continue;
1315130613Smlaier		}
1316223637Sbz		pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
1317223637Sbz		pf_state_peer_ntoh(&sp->src, &st->src);
1318223637Sbz		pf_state_peer_ntoh(&sp->dst, &st->dst);
1319223637Sbz		st->expire = ntohl(sp->expire) + time_second;
1320223637Sbz		st->timeout = sp->timeout;
1321223637Sbz		st->pfsync_time = time_second;
1322223637Sbz	}
1323223637Sbz#ifdef __FreeBSD__
1324223637Sbz	PF_UNLOCK();
1325223637Sbz#endif
1326223637Sbz	splx(s);
1327130613Smlaier
1328223637Sbz	return (len);
1329223637Sbz}
1330223637Sbz
1331223637Sbzint
1332223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1333223637Sbz{
1334223637Sbz	struct pfsync_upd_c *ua, *up;
1335223637Sbz	struct pf_state_key *sk;
1336223637Sbz	struct pf_state_cmp id_key;
1337223637Sbz	struct pf_state *st;
1338223637Sbz
1339223637Sbz	int len = count * sizeof(*up);
1340223637Sbz	int sfail;
1341223637Sbz
1342223637Sbz	struct mbuf *mp;
1343223637Sbz	int offp, i;
1344223637Sbz	int s;
1345223637Sbz
1346223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1347223637Sbz	if (mp == NULL) {
1348223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1349223637Sbz		return (-1);
1350223637Sbz	}
1351223637Sbz	ua = (struct pfsync_upd_c *)(mp->m_data + offp);
1352223637Sbz
1353223637Sbz	s = splsoftnet();
1354130613Smlaier#ifdef __FreeBSD__
1355223637Sbz	PF_LOCK();
1356130613Smlaier#endif
1357223637Sbz	for (i = 0; i < count; i++) {
1358223637Sbz		up = &ua[i];
1359223637Sbz
1360223637Sbz		/* check for invalid values */
1361223637Sbz		if (up->timeout >= PFTM_MAX ||
1362223637Sbz		    up->src.state > PF_TCPS_PROXY_DST ||
1363223637Sbz		    up->dst.state > PF_TCPS_PROXY_DST) {
1364223637Sbz#ifdef __FreeBSD__
1365223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1366223637Sbz#else
1367223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
1368223637Sbz#endif
1369223637Sbz				printf("pfsync_input: "
1370223637Sbz				    "PFSYNC_ACT_UPD_C: "
1371223637Sbz				    "invalid value\n");
1372130613Smlaier			}
1373223637Sbz			V_pfsyncstats.pfsyncs_badval++;
1374223637Sbz			continue;
1375223637Sbz		}
1376130613Smlaier
1377223637Sbz		bcopy(&up->id, &id_key.id, sizeof(id_key.id));
1378223637Sbz		id_key.creatorid = up->creatorid;
1379130613Smlaier
1380223637Sbz		st = pf_find_state_byid(&id_key);
1381223637Sbz		if (st == NULL) {
1382223637Sbz			/* We don't have this state. Ask for it. */
1383223637Sbz			pfsync_request_update(id_key.creatorid, id_key.id);
1384223637Sbz			continue;
1385223637Sbz		}
1386223637Sbz
1387223637Sbz		if (ISSET(st->state_flags, PFSTATE_ACK))
1388223637Sbz			pfsync_deferred(st, 1);
1389223637Sbz
1390223637Sbz		sk = st->key[PF_SK_WIRE]; /* XXX right one? */
1391223637Sbz		sfail = 0;
1392223637Sbz		if (sk->proto == IPPROTO_TCP)
1393223637Sbz			sfail = pfsync_upd_tcp(st, &up->src, &up->dst);
1394223637Sbz		else {
1395223637Sbz			/*
1396223637Sbz			 * Non-TCP protocol state machine always go forwards
1397223637Sbz			 */
1398223637Sbz			if (st->src.state > up->src.state)
1399223637Sbz				sfail = 5;
1400223637Sbz			else if (st->dst.state > up->dst.state)
1401223637Sbz				sfail = 6;
1402223637Sbz		}
1403223637Sbz
1404223637Sbz		if (sfail) {
1405171168Smlaier#ifdef __FreeBSD__
1406223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
1407223637Sbz#else
1408223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
1409171168Smlaier#endif
1410223637Sbz				printf("pfsync: ignoring stale update "
1411223637Sbz				    "(%d) id: %016llx "
1412223637Sbz				    "creatorid: %08x\n", sfail,
1413223637Sbz				    betoh64(st->id),
1414223637Sbz				    ntohl(st->creatorid));
1415130613Smlaier			}
1416223637Sbz			V_pfsyncstats.pfsyncs_stale++;
1417145836Smlaier
1418223637Sbz			pfsync_update_state(st);
1419223637Sbz			schednetisr(NETISR_PFSYNC);
1420223637Sbz			continue;
1421130613Smlaier		}
1422223637Sbz		pfsync_alloc_scrub_memory(&up->dst, &st->dst);
1423223637Sbz		pf_state_peer_ntoh(&up->src, &st->src);
1424223637Sbz		pf_state_peer_ntoh(&up->dst, &st->dst);
1425223637Sbz		st->expire = ntohl(up->expire) + time_second;
1426223637Sbz		st->timeout = up->timeout;
1427223637Sbz		st->pfsync_time = time_second;
1428223637Sbz	}
1429130613Smlaier#ifdef __FreeBSD__
1430223637Sbz	PF_UNLOCK();
1431130613Smlaier#endif
1432223637Sbz	splx(s);
1433223637Sbz
1434223637Sbz	return (len);
1435223637Sbz}
1436223637Sbz
1437223637Sbzint
1438223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1439223637Sbz{
1440223637Sbz	struct pfsync_upd_req *ur, *ura;
1441223637Sbz	struct mbuf *mp;
1442223637Sbz	int len = count * sizeof(*ur);
1443223637Sbz	int i, offp;
1444223637Sbz
1445223637Sbz	struct pf_state_cmp id_key;
1446223637Sbz	struct pf_state *st;
1447223637Sbz
1448223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1449223637Sbz	if (mp == NULL) {
1450223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1451223637Sbz		return (-1);
1452130613Smlaier	}
1453223637Sbz	ura = (struct pfsync_upd_req *)(mp->m_data + offp);
1454130613Smlaier
1455223637Sbz	for (i = 0; i < count; i++) {
1456223637Sbz		ur = &ura[i];
1457130613Smlaier
1458223637Sbz		bcopy(&ur->id, &id_key.id, sizeof(id_key.id));
1459223637Sbz		id_key.creatorid = ur->creatorid;
1460223637Sbz
1461223637Sbz		if (id_key.id == 0 && id_key.creatorid == 0)
1462223637Sbz			pfsync_bulk_start();
1463223637Sbz		else {
1464223637Sbz			st = pf_find_state_byid(&id_key);
1465130613Smlaier			if (st == NULL) {
1466223637Sbz				V_pfsyncstats.pfsyncs_badstate++;
1467130613Smlaier				continue;
1468130613Smlaier			}
1469223637Sbz			if (ISSET(st->state_flags, PFSTATE_NOSYNC))
1470223637Sbz				continue;
1471223637Sbz
1472223637Sbz			pfsync_update_state_req(st);
1473130613Smlaier		}
1474223637Sbz	}
1475223637Sbz
1476223637Sbz	return (len);
1477223637Sbz}
1478223637Sbz
1479223637Sbzint
1480223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1481223637Sbz{
1482223637Sbz	struct mbuf *mp;
1483223637Sbz	struct pfsync_state *sa, *sp;
1484223637Sbz	struct pf_state_cmp id_key;
1485223637Sbz	struct pf_state *st;
1486223637Sbz	int len = count * sizeof(*sp);
1487223637Sbz	int offp, i;
1488223637Sbz	int s;
1489223637Sbz
1490223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1491223637Sbz	if (mp == NULL) {
1492223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1493223637Sbz		return (-1);
1494223637Sbz	}
1495223637Sbz	sa = (struct pfsync_state *)(mp->m_data + offp);
1496223637Sbz
1497223637Sbz	s = splsoftnet();
1498130613Smlaier#ifdef __FreeBSD__
1499223637Sbz	PF_LOCK();
1500130613Smlaier#endif
1501223637Sbz	for (i = 0; i < count; i++) {
1502223637Sbz		sp = &sa[i];
1503223637Sbz
1504223637Sbz		bcopy(sp->id, &id_key.id, sizeof(id_key.id));
1505223637Sbz		id_key.creatorid = sp->creatorid;
1506223637Sbz
1507223637Sbz		st = pf_find_state_byid(&id_key);
1508223637Sbz		if (st == NULL) {
1509223637Sbz			V_pfsyncstats.pfsyncs_badstate++;
1510223637Sbz			continue;
1511130613Smlaier		}
1512223637Sbz		SET(st->state_flags, PFSTATE_NOSYNC);
1513223637Sbz		pf_unlink_state(st);
1514223637Sbz	}
1515223637Sbz#ifdef __FreeBSD__
1516223637Sbz	PF_UNLOCK();
1517223637Sbz#endif
1518223637Sbz	splx(s);
1519130613Smlaier
1520223637Sbz	return (len);
1521223637Sbz}
1522223637Sbz
1523223637Sbzint
1524223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1525223637Sbz{
1526223637Sbz	struct mbuf *mp;
1527223637Sbz	struct pfsync_del_c *sa, *sp;
1528223637Sbz	struct pf_state_cmp id_key;
1529223637Sbz	struct pf_state *st;
1530223637Sbz	int len = count * sizeof(*sp);
1531223637Sbz	int offp, i;
1532223637Sbz	int s;
1533223637Sbz
1534223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1535223637Sbz	if (mp == NULL) {
1536223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1537223637Sbz		return (-1);
1538223637Sbz	}
1539223637Sbz	sa = (struct pfsync_del_c *)(mp->m_data + offp);
1540223637Sbz
1541223637Sbz	s = splsoftnet();
1542130613Smlaier#ifdef __FreeBSD__
1543223637Sbz	PF_LOCK();
1544130613Smlaier#endif
1545223637Sbz	for (i = 0; i < count; i++) {
1546223637Sbz		sp = &sa[i];
1547130613Smlaier
1548223637Sbz		bcopy(&sp->id, &id_key.id, sizeof(id_key.id));
1549223637Sbz		id_key.creatorid = sp->creatorid;
1550223637Sbz
1551223637Sbz		st = pf_find_state_byid(&id_key);
1552223637Sbz		if (st == NULL) {
1553223637Sbz			V_pfsyncstats.pfsyncs_badstate++;
1554223637Sbz			continue;
1555223637Sbz		}
1556223637Sbz
1557223637Sbz		SET(st->state_flags, PFSTATE_NOSYNC);
1558223637Sbz		pf_unlink_state(st);
1559223637Sbz	}
1560130613Smlaier#ifdef __FreeBSD__
1561223637Sbz	PF_LOCK();
1562223637Sbz#endif
1563223637Sbz	splx(s);
1564223637Sbz
1565223637Sbz	return (len);
1566223637Sbz}
1567223637Sbz
1568223637Sbzint
1569223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1570223637Sbz{
1571223637Sbz#ifdef __FreeBSD__
1572223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
1573130613Smlaier#else
1574223637Sbz	struct pfsync_softc *sc = pfsyncif;
1575130613Smlaier#endif
1576223637Sbz	struct pfsync_bus *bus;
1577223637Sbz	struct mbuf *mp;
1578223637Sbz	int len = count * sizeof(*bus);
1579223637Sbz	int offp;
1580223637Sbz
1581223637Sbz	/* If we're not waiting for a bulk update, who cares. */
1582223637Sbz	if (sc->sc_ureq_sent == 0)
1583223637Sbz		return (len);
1584223637Sbz
1585223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1586223637Sbz	if (mp == NULL) {
1587223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1588223637Sbz		return (-1);
1589223637Sbz	}
1590223637Sbz	bus = (struct pfsync_bus *)(mp->m_data + offp);
1591223637Sbz
1592223637Sbz	switch (bus->status) {
1593223637Sbz	case PFSYNC_BUS_START:
1594130613Smlaier#ifdef __FreeBSD__
1595223637Sbz		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail,
1596223637Sbz		    V_pfsyncif);
1597223637Sbz#else
1598223637Sbz		timeout_add_sec(&sc->sc_bulkfail_tmo, 5); /* XXX magic */
1599130613Smlaier#endif
1600223637Sbz#ifdef XXX
1601223637Sbz		    pf_pool_limits[PF_LIMIT_STATES].limit /
1602223637Sbz		    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
1603223637Sbz#endif
1604223637Sbz#ifdef __FreeBSD__
1605223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC)
1606223637Sbz#else
1607223637Sbz		if (pf_status.debug >= PF_DEBUG_MISC)
1608223637Sbz#endif
1609223637Sbz			printf("pfsync: received bulk update start\n");
1610130613Smlaier		break;
1611130613Smlaier
1612223637Sbz	case PFSYNC_BUS_END:
1613223637Sbz		if (time_uptime - ntohl(bus->endtime) >=
1614223637Sbz		    sc->sc_ureq_sent) {
1615223637Sbz			/* that's it, we're happy */
1616223637Sbz			sc->sc_ureq_sent = 0;
1617223637Sbz			sc->sc_bulk_tries = 0;
1618223637Sbz			timeout_del(&sc->sc_bulkfail_tmo);
1619223637Sbz#if NCARP > 0
1620223637Sbz#ifdef notyet
1621130613Smlaier#ifdef __FreeBSD__
1622223637Sbz			if (!sc->pfsync_sync_ok)
1623130613Smlaier#else
1624223637Sbz			if (!pfsync_sync_ok)
1625130613Smlaier#endif
1626223637Sbz				carp_group_demote_adj(&sc->sc_if, -1);
1627223637Sbz#endif
1628223637Sbz#endif
1629130613Smlaier#ifdef __FreeBSD__
1630223637Sbz			sc->pfsync_sync_ok = 1;
1631223637Sbz#else
1632223637Sbz			pfsync_sync_ok = 1;
1633171168Smlaier#endif
1634223637Sbz#ifdef __FreeBSD__
1635223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC)
1636130613Smlaier#else
1637223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC)
1638130613Smlaier#endif
1639223637Sbz				printf("pfsync: received valid "
1640223637Sbz				    "bulk update end\n");
1641223637Sbz		} else {
1642223637Sbz#ifdef __FreeBSD__
1643223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC)
1644223637Sbz#else
1645223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC)
1646145836Smlaier#endif
1647223637Sbz				printf("pfsync: received invalid "
1648223637Sbz				    "bulk update end: bad timestamp\n");
1649130613Smlaier		}
1650130613Smlaier		break;
1651223637Sbz	}
1652223637Sbz
1653223637Sbz	return (len);
1654223637Sbz}
1655223637Sbz
1656223637Sbzint
1657223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1658223637Sbz{
1659223637Sbz	int len = count * sizeof(struct pfsync_tdb);
1660223637Sbz
1661223637Sbz#if defined(IPSEC)
1662223637Sbz	struct pfsync_tdb *tp;
1663223637Sbz	struct mbuf *mp;
1664223637Sbz	int offp;
1665223637Sbz	int i;
1666223637Sbz	int s;
1667223637Sbz
1668223637Sbz	mp = m_pulldown(m, offset, len, &offp);
1669223637Sbz	if (mp == NULL) {
1670223637Sbz		V_pfsyncstats.pfsyncs_badlen++;
1671223637Sbz		return (-1);
1672223637Sbz	}
1673223637Sbz	tp = (struct pfsync_tdb *)(mp->m_data + offp);
1674223637Sbz
1675223637Sbz	s = splsoftnet();
1676171168Smlaier#ifdef __FreeBSD__
1677223637Sbz	PF_LOCK();
1678171168Smlaier#endif
1679223637Sbz	for (i = 0; i < count; i++)
1680223637Sbz		pfsync_update_net_tdb(&tp[i]);
1681171168Smlaier#ifdef __FreeBSD__
1682223637Sbz	PF_UNLOCK();
1683171168Smlaier#endif
1684223637Sbz	splx(s);
1685171168Smlaier#endif
1686223637Sbz
1687223637Sbz	return (len);
1688223637Sbz}
1689223637Sbz
1690223637Sbz#if defined(IPSEC)
1691223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */
1692223637Sbzvoid
1693223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt)
1694223637Sbz{
1695223637Sbz	struct tdb		*tdb;
1696223637Sbz	int			 s;
1697223637Sbz
1698223637Sbz	/* check for invalid values */
1699223637Sbz	if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
1700223637Sbz	    (pt->dst.sa.sa_family != AF_INET &&
1701223637Sbz	     pt->dst.sa.sa_family != AF_INET6))
1702223637Sbz		goto bad;
1703223637Sbz
1704223637Sbz	s = spltdb();
1705223637Sbz	tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
1706223637Sbz	if (tdb) {
1707223637Sbz		pt->rpl = ntohl(pt->rpl);
1708223637Sbz		pt->cur_bytes = betoh64(pt->cur_bytes);
1709223637Sbz
1710223637Sbz		/* Neither replay nor byte counter should ever decrease. */
1711223637Sbz		if (pt->rpl < tdb->tdb_rpl ||
1712223637Sbz		    pt->cur_bytes < tdb->tdb_cur_bytes) {
1713223637Sbz			splx(s);
1714223637Sbz			goto bad;
1715223637Sbz		}
1716223637Sbz
1717223637Sbz		tdb->tdb_rpl = pt->rpl;
1718223637Sbz		tdb->tdb_cur_bytes = pt->cur_bytes;
1719130613Smlaier	}
1720223637Sbz	splx(s);
1721223637Sbz	return;
1722130613Smlaier
1723223637Sbzbad:
1724223637Sbz#ifdef __FreeBSD__
1725223637Sbz	if (V_pf_status.debug >= PF_DEBUG_MISC)
1726223637Sbz#else
1727223637Sbz	if (pf_status.debug >= PF_DEBUG_MISC)
1728223637Sbz#endif
1729223637Sbz		printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
1730223637Sbz		    "invalid value\n");
1731223637Sbz	V_pfsyncstats.pfsyncs_badstate++;
1732223637Sbz	return;
1733130613Smlaier}
1734223637Sbz#endif
1735130613Smlaier
1736223637Sbz
1737130613Smlaierint
1738223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1739223637Sbz{
1740223637Sbz	/* check if we are at the right place in the packet */
1741223637Sbz	if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof))
1742223637Sbz		V_pfsyncstats.pfsyncs_badact++;
1743223637Sbz
1744223637Sbz	/* we're done. free and let the caller return */
1745223637Sbz	m_freem(m);
1746223637Sbz	return (-1);
1747223637Sbz}
1748223637Sbz
1749223637Sbzint
1750223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count)
1751223637Sbz{
1752223637Sbz	V_pfsyncstats.pfsyncs_badact++;
1753223637Sbz
1754223637Sbz	m_freem(m);
1755223637Sbz	return (-1);
1756223637Sbz}
1757223637Sbz
1758223637Sbzint
1759126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1760223637Sbz#ifdef __FreeBSD__
1761223637Sbz	struct route *rt)
1762223637Sbz#else
1763223637Sbz	struct rtentry *rt)
1764223637Sbz#endif
1765126258Smlaier{
1766126258Smlaier	m_freem(m);
1767126258Smlaier	return (0);
1768126258Smlaier}
1769126258Smlaier
1770126258Smlaier/* ARGSUSED */
1771126258Smlaierint
1772126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1773126258Smlaier{
1774130613Smlaier#ifndef __FreeBSD__
1775130613Smlaier	struct proc *p = curproc;
1776130613Smlaier#endif
1777126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1778126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
1779130613Smlaier	struct ip_moptions *imo = &sc->sc_imo;
1780130613Smlaier	struct pfsyncreq pfsyncr;
1781130613Smlaier	struct ifnet    *sifp;
1782223637Sbz	struct ip *ip;
1783130613Smlaier	int s, error;
1784126258Smlaier
1785126258Smlaier	switch (cmd) {
1786223637Sbz#if 0
1787126258Smlaier	case SIOCSIFADDR:
1788126258Smlaier	case SIOCAIFADDR:
1789126258Smlaier	case SIOCSIFDSTADDR:
1790223637Sbz#endif
1791126258Smlaier	case SIOCSIFFLAGS:
1792148891Smlaier#ifdef __FreeBSD__
1793126258Smlaier		if (ifp->if_flags & IFF_UP)
1794148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
1795126258Smlaier		else
1796148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1797148891Smlaier#else
1798148891Smlaier		if (ifp->if_flags & IFF_UP)
1799148891Smlaier			ifp->if_flags |= IFF_RUNNING;
1800148891Smlaier		else
1801148891Smlaier			ifp->if_flags &= ~IFF_RUNNING;
1802148891Smlaier#endif
1803126258Smlaier		break;
1804126258Smlaier	case SIOCSIFMTU:
1805223637Sbz		if (ifr->ifr_mtu <= PFSYNC_MINPKT)
1806126258Smlaier			return (EINVAL);
1807223637Sbz		if (ifr->ifr_mtu > MCLBYTES) /* XXX could be bigger */
1808126258Smlaier			ifr->ifr_mtu = MCLBYTES;
1809223637Sbz		if (ifr->ifr_mtu < ifp->if_mtu) {
1810223637Sbz			s = splnet();
1811130613Smlaier#ifdef __FreeBSD__
1812223637Sbz			PF_LOCK();
1813130613Smlaier#endif
1814223637Sbz			pfsync_sendout();
1815130613Smlaier#ifdef __FreeBSD__
1816223637Sbz			PF_UNLOCK();
1817130613Smlaier#endif
1818223637Sbz			splx(s);
1819223637Sbz		}
1820223637Sbz		ifp->if_mtu = ifr->ifr_mtu;
1821126258Smlaier		break;
1822130613Smlaier	case SIOCGETPFSYNC:
1823130613Smlaier		bzero(&pfsyncr, sizeof(pfsyncr));
1824223637Sbz		if (sc->sc_sync_if) {
1825145836Smlaier			strlcpy(pfsyncr.pfsyncr_syncdev,
1826223637Sbz			    sc->sc_sync_if->if_xname, IFNAMSIZ);
1827223637Sbz		}
1828145836Smlaier		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1829130613Smlaier		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1830223637Sbz		return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)));
1831223637Sbz
1832130613Smlaier	case SIOCSETPFSYNC:
1833130613Smlaier#ifdef __FreeBSD__
1834164033Srwatson		if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
1835130613Smlaier#else
1836130613Smlaier		if ((error = suser(p, p->p_acflag)) != 0)
1837130613Smlaier#endif
1838130613Smlaier			return (error);
1839130613Smlaier		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1840130613Smlaier			return (error);
1841130613Smlaier
1842171168Smlaier#ifdef __FreeBSD__
1843171168Smlaier		PF_LOCK();
1844171168Smlaier#endif
1845145836Smlaier		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1846159603Smlaier#ifdef __FreeBSD__
1847159603Smlaier			sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
1848159603Smlaier#else
1849145836Smlaier			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1850159603Smlaier#endif
1851145836Smlaier		else
1852145836Smlaier			sc->sc_sync_peer.s_addr =
1853145836Smlaier			    pfsyncr.pfsyncr_syncpeer.s_addr;
1854145836Smlaier
1855130613Smlaier		if (pfsyncr.pfsyncr_maxupdates > 255)
1856171168Smlaier#ifdef __FreeBSD__
1857171168Smlaier		{
1858171168Smlaier			PF_UNLOCK();
1859171168Smlaier#endif
1860130613Smlaier			return (EINVAL);
1861130613Smlaier#ifdef __FreeBSD__
1862171168Smlaier		}
1863130613Smlaier#endif
1864130613Smlaier		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1865130613Smlaier
1866145836Smlaier		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1867223637Sbz			sc->sc_sync_if = NULL;
1868171168Smlaier#ifdef __FreeBSD__
1869171168Smlaier			PF_UNLOCK();
1870171168Smlaier#endif
1871145836Smlaier			if (imo->imo_num_memberships > 0) {
1872223637Sbz				in_delmulti(imo->imo_membership[
1873223637Sbz				    --imo->imo_num_memberships]);
1874145836Smlaier				imo->imo_multicast_ifp = NULL;
1875145836Smlaier			}
1876130613Smlaier			break;
1877130613Smlaier		}
1878145836Smlaier
1879130613Smlaier#ifdef __FreeBSD__
1880171168Smlaier		PF_UNLOCK();
1881130613Smlaier#endif
1882171168Smlaier		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
1883130613Smlaier			return (EINVAL);
1884223637Sbz
1885171168Smlaier#ifdef __FreeBSD__
1886171168Smlaier		PF_LOCK();
1887171168Smlaier#endif
1888130613Smlaier		s = splnet();
1889141584Smlaier#ifdef __FreeBSD__
1890171168Smlaier		if (sifp->if_mtu < sc->sc_ifp->if_mtu ||
1891141584Smlaier#else
1892130613Smlaier		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1893141584Smlaier#endif
1894223637Sbz		    (sc->sc_sync_if != NULL &&
1895223637Sbz		    sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
1896130613Smlaier		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1897223637Sbz			pfsync_sendout();
1898223637Sbz		sc->sc_sync_if = sifp;
1899130613Smlaier
1900130613Smlaier		if (imo->imo_num_memberships > 0) {
1901171168Smlaier#ifdef __FreeBSD__
1902171168Smlaier			PF_UNLOCK();
1903171168Smlaier#endif
1904130613Smlaier			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1905171168Smlaier#ifdef __FreeBSD__
1906171168Smlaier			PF_LOCK();
1907171168Smlaier#endif
1908130613Smlaier			imo->imo_multicast_ifp = NULL;
1909130613Smlaier		}
1910130613Smlaier
1911223637Sbz		if (sc->sc_sync_if &&
1912159603Smlaier#ifdef __FreeBSD__
1913159603Smlaier		    sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
1914159603Smlaier#else
1915145836Smlaier		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1916159603Smlaier#endif
1917130613Smlaier			struct in_addr addr;
1918130613Smlaier
1919223637Sbz			if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) {
1920223637Sbz				sc->sc_sync_if = NULL;
1921130613Smlaier#ifdef __FreeBSD__
1922145836Smlaier				PF_UNLOCK();
1923145836Smlaier#endif
1924145836Smlaier				splx(s);
1925145836Smlaier				return (EADDRNOTAVAIL);
1926145836Smlaier			}
1927171168Smlaier
1928145836Smlaier#ifdef __FreeBSD__
1929130613Smlaier			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1930130613Smlaier#else
1931130613Smlaier			addr.s_addr = INADDR_PFSYNC_GROUP;
1932130613Smlaier#endif
1933145836Smlaier
1934171168Smlaier#ifdef __FreeBSD__
1935171168Smlaier			PF_UNLOCK();
1936171168Smlaier#endif
1937130613Smlaier			if ((imo->imo_membership[0] =
1938223637Sbz			    in_addmulti(&addr, sc->sc_sync_if)) == NULL) {
1939223637Sbz				sc->sc_sync_if = NULL;
1940130613Smlaier				splx(s);
1941130613Smlaier				return (ENOBUFS);
1942130613Smlaier			}
1943171168Smlaier#ifdef __FreeBSD__
1944171168Smlaier			PF_LOCK();
1945171168Smlaier#endif
1946130613Smlaier			imo->imo_num_memberships++;
1947223637Sbz			imo->imo_multicast_ifp = sc->sc_sync_if;
1948130613Smlaier			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1949130613Smlaier			imo->imo_multicast_loop = 0;
1950145836Smlaier		}
1951130613Smlaier
1952223637Sbz		ip = &sc->sc_template;
1953223637Sbz		bzero(ip, sizeof(*ip));
1954223637Sbz		ip->ip_v = IPVERSION;
1955223637Sbz		ip->ip_hl = sizeof(sc->sc_template) >> 2;
1956223637Sbz		ip->ip_tos = IPTOS_LOWDELAY;
1957223637Sbz		/* len and id are set later */
1958223637Sbz		ip->ip_off = htons(IP_DF);
1959223637Sbz		ip->ip_ttl = PFSYNC_DFLTTL;
1960223637Sbz		ip->ip_p = IPPROTO_PFSYNC;
1961223637Sbz		ip->ip_src.s_addr = INADDR_ANY;
1962223637Sbz		ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
1963223637Sbz
1964223637Sbz		if (sc->sc_sync_if) {
1965130613Smlaier			/* Request a full state table update. */
1966130613Smlaier			sc->sc_ureq_sent = time_uptime;
1967145836Smlaier#if NCARP > 0
1968223637Sbz#ifdef notyet
1969223637Sbz#ifdef __FreeBSD__
1970223637Sbz			if (sc->pfsync_sync_ok)
1971223637Sbz#else
1972145836Smlaier			if (pfsync_sync_ok)
1973130613Smlaier#endif
1974171168Smlaier				carp_group_demote_adj(&sc->sc_if, 1);
1975171168Smlaier#endif
1976171168Smlaier#endif
1977223637Sbz#ifdef __FreeBSD__
1978223637Sbz			sc->pfsync_sync_ok = 0;
1979223637Sbz#else
1980130613Smlaier			pfsync_sync_ok = 0;
1981223637Sbz#endif
1982223637Sbz#ifdef __FreeBSD__
1983223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC)
1984223637Sbz#else
1985130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1986223637Sbz#endif
1987130613Smlaier				printf("pfsync: requesting bulk update\n");
1988130613Smlaier#ifdef __FreeBSD__
1989223637Sbz				callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1990223637Sbz				    pfsync_bulk_fail, V_pfsyncif);
1991130613Smlaier#else
1992223637Sbz			timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
1993130613Smlaier#endif
1994223637Sbz			pfsync_request_update(0, 0);
1995130613Smlaier		}
1996130613Smlaier#ifdef __FreeBSD__
1997130613Smlaier		PF_UNLOCK();
1998130613Smlaier#endif
1999130613Smlaier		splx(s);
2000130613Smlaier
2001130613Smlaier		break;
2002130613Smlaier
2003126258Smlaier	default:
2004126258Smlaier		return (ENOTTY);
2005126258Smlaier	}
2006126258Smlaier
2007126258Smlaier	return (0);
2008126258Smlaier}
2009126258Smlaier
2010223637Sbzint
2011223637Sbzpfsync_out_state(struct pf_state *st, struct mbuf *m, int offset)
2012130613Smlaier{
2013223637Sbz	struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset);
2014130613Smlaier
2015223637Sbz	pfsync_state_export(sp, st);
2016223637Sbz
2017223637Sbz	return (sizeof(*sp));
2018223637Sbz}
2019223637Sbz
2020223637Sbzint
2021223637Sbzpfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset)
2022223637Sbz{
2023223637Sbz	struct pfsync_ins_ack *iack =
2024223637Sbz	    (struct pfsync_ins_ack *)(m->m_data + offset);
2025223637Sbz
2026223637Sbz	iack->id = st->id;
2027223637Sbz	iack->creatorid = st->creatorid;
2028223637Sbz
2029223637Sbz	return (sizeof(*iack));
2030223637Sbz}
2031223637Sbz
2032223637Sbzint
2033223637Sbzpfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset)
2034223637Sbz{
2035223637Sbz	struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset);
2036223637Sbz
2037223637Sbz	up->id = st->id;
2038223637Sbz	pf_state_peer_hton(&st->src, &up->src);
2039223637Sbz	pf_state_peer_hton(&st->dst, &up->dst);
2040223637Sbz	up->creatorid = st->creatorid;
2041223637Sbz
2042223637Sbz	up->expire = pf_state_expires(st);
2043223637Sbz	if (up->expire <= time_second)
2044223637Sbz		up->expire = htonl(0);
2045130613Smlaier	else
2046223637Sbz		up->expire = htonl(up->expire - time_second);
2047223637Sbz	up->timeout = st->timeout;
2048130613Smlaier
2049223637Sbz	bzero(up->_pad, sizeof(up->_pad)); /* XXX */
2050223637Sbz
2051223637Sbz	return (sizeof(*up));
2052223637Sbz}
2053223637Sbz
2054223637Sbzint
2055223637Sbzpfsync_out_del(struct pf_state *st, struct mbuf *m, int offset)
2056223637Sbz{
2057223637Sbz	struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset);
2058223637Sbz
2059223637Sbz	dp->id = st->id;
2060223637Sbz	dp->creatorid = st->creatorid;
2061223637Sbz
2062223637Sbz	SET(st->state_flags, PFSTATE_NOSYNC);
2063223637Sbz
2064223637Sbz	return (sizeof(*dp));
2065223637Sbz}
2066223637Sbz
2067223637Sbzvoid
2068223637Sbzpfsync_drop(struct pfsync_softc *sc)
2069223637Sbz{
2070223637Sbz	struct pf_state *st;
2071223637Sbz	struct pfsync_upd_req_item *ur;
2072223637Sbz#ifdef notyet
2073223637Sbz	struct tdb *t;
2074223637Sbz#endif
2075223637Sbz	int q;
2076223637Sbz
2077223637Sbz	for (q = 0; q < PFSYNC_S_COUNT; q++) {
2078223637Sbz		if (TAILQ_EMPTY(&sc->sc_qs[q]))
2079223637Sbz			continue;
2080223637Sbz
2081223637Sbz		TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
2082223637Sbz#ifdef PFSYNC_DEBUG
2083141584Smlaier#ifdef __FreeBSD__
2084223637Sbz			KASSERT(st->sync_state == q,
2085223637Sbz				("%s: st->sync_state == q",
2086223637Sbz					__FUNCTION__));
2087141584Smlaier#else
2088223637Sbz			KASSERT(st->sync_state == q);
2089171168Smlaier#endif
2090223637Sbz#endif
2091223637Sbz			st->sync_state = PFSYNC_S_NONE;
2092223637Sbz		}
2093223637Sbz		TAILQ_INIT(&sc->sc_qs[q]);
2094223637Sbz	}
2095223637Sbz
2096223637Sbz	while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
2097223637Sbz		TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
2098223637Sbz		pool_put(&sc->sc_pool, ur);
2099223637Sbz	}
2100223637Sbz
2101223637Sbz	sc->sc_plus = NULL;
2102223637Sbz
2103223637Sbz#ifdef notyet
2104223637Sbz	if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
2105223637Sbz		TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry)
2106223637Sbz			CLR(t->tdb_flags, TDBF_PFSYNC);
2107223637Sbz
2108223637Sbz		TAILQ_INIT(&sc->sc_tdb_q);
2109223637Sbz	}
2110223637Sbz#endif
2111223637Sbz
2112223637Sbz	sc->sc_len = PFSYNC_MINPKT;
2113126258Smlaier}
2114126258Smlaier
2115223637Sbzvoid
2116223637Sbzpfsync_sendout(void)
2117126258Smlaier{
2118223637Sbz#ifdef __FreeBSD__
2119223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2120223637Sbz#else
2121223637Sbz	struct pfsync_softc *sc = pfsyncif;
2122223637Sbz#endif
2123223637Sbz#if NBPFILTER > 0
2124223637Sbz#ifdef __FreeBSD__
2125223637Sbz	struct ifnet *ifp = sc->sc_ifp;
2126223637Sbz#else
2127223637Sbz	struct ifnet *ifp = &sc->sc_if;
2128223637Sbz#endif
2129126258Smlaier	struct mbuf *m;
2130223637Sbz#endif
2131223637Sbz	struct ip *ip;
2132223637Sbz	struct pfsync_header *ph;
2133223637Sbz	struct pfsync_subheader *subh;
2134223637Sbz	struct pf_state *st;
2135223637Sbz	struct pfsync_upd_req_item *ur;
2136223637Sbz#ifdef notyet
2137223637Sbz	struct tdb *t;
2138223637Sbz#endif
2139223637Sbz#ifdef __FreeBSD__
2140223637Sbz	size_t pktlen;
2141223637Sbz#endif
2142223637Sbz	int offset;
2143223637Sbz	int q, count = 0;
2144126258Smlaier
2145223637Sbz#ifdef __FreeBSD__
2146223637Sbz	PF_ASSERT(MA_OWNED);
2147223637Sbz#else
2148223637Sbz	splassert(IPL_NET);
2149223637Sbz#endif
2150223637Sbz
2151223637Sbz	if (sc == NULL || sc->sc_len == PFSYNC_MINPKT)
2152223637Sbz		return;
2153223637Sbz
2154223637Sbz#if NBPFILTER > 0
2155223637Sbz	if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) {
2156223637Sbz#else
2157223637Sbz	if (sc->sc_sync_if == NULL) {
2158223637Sbz#endif
2159223637Sbz		pfsync_drop(sc);
2160223637Sbz		return;
2161223637Sbz	}
2162223637Sbz
2163126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
2164126258Smlaier	if (m == NULL) {
2165141584Smlaier#ifdef __FreeBSD__
2166171168Smlaier		sc->sc_ifp->if_oerrors++;
2167141584Smlaier#else
2168126258Smlaier		sc->sc_if.if_oerrors++;
2169141584Smlaier#endif
2170223637Sbz		V_pfsyncstats.pfsyncs_onomem++;
2171223637Sbz		pfsync_drop(sc);
2172223637Sbz		return;
2173126258Smlaier	}
2174126258Smlaier
2175223637Sbz#ifdef __FreeBSD__
2176223637Sbz	pktlen = max_linkhdr + sc->sc_len;
2177223637Sbz	if (pktlen > MHLEN) {
2178223637Sbz		/* Find the right pool to allocate from. */
2179223637Sbz		/* XXX: This is ugly. */
2180223637Sbz		m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE :
2181223637Sbz			pktlen <= MCLBYTES ? MCLBYTES :
2182223637Sbz#if MJUMPAGESIZE != MCLBYTES
2183223637Sbz			pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE :
2184171168Smlaier#endif
2185223637Sbz			pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES);
2186223637Sbz#else
2187223637Sbz	if (max_linkhdr + sc->sc_len > MHLEN) {
2188223637Sbz		MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len);
2189223637Sbz#endif
2190223637Sbz		if (!ISSET(m->m_flags, M_EXT)) {
2191126258Smlaier			m_free(m);
2192141584Smlaier#ifdef __FreeBSD__
2193171168Smlaier			sc->sc_ifp->if_oerrors++;
2194141584Smlaier#else
2195126258Smlaier			sc->sc_if.if_oerrors++;
2196141584Smlaier#endif
2197223637Sbz			V_pfsyncstats.pfsyncs_onomem++;
2198223637Sbz			pfsync_drop(sc);
2199223637Sbz			return;
2200126258Smlaier		}
2201223637Sbz	}
2202223637Sbz	m->m_data += max_linkhdr;
2203223637Sbz	m->m_len = m->m_pkthdr.len = sc->sc_len;
2204130613Smlaier
2205223637Sbz	/* build the ip header */
2206223637Sbz	ip = (struct ip *)m->m_data;
2207223637Sbz	bcopy(&sc->sc_template, ip, sizeof(*ip));
2208223637Sbz	offset = sizeof(*ip);
2209126258Smlaier
2210223637Sbz	ip->ip_len = htons(m->m_pkthdr.len);
2211223637Sbz	ip->ip_id = htons(ip_randomid());
2212126258Smlaier
2213223637Sbz	/* build the pfsync header */
2214223637Sbz	ph = (struct pfsync_header *)(m->m_data + offset);
2215223637Sbz	bzero(ph, sizeof(*ph));
2216223637Sbz	offset += sizeof(*ph);
2217126258Smlaier
2218223637Sbz	ph->version = PFSYNC_VERSION;
2219223637Sbz	ph->len = htons(sc->sc_len - sizeof(*ip));
2220130613Smlaier#ifdef __FreeBSD__
2221223637Sbz	bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
2222171168Smlaier#else
2223223637Sbz	bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
2224130613Smlaier#endif
2225171168Smlaier
2226223637Sbz	/* walk the queues */
2227223637Sbz	for (q = 0; q < PFSYNC_S_COUNT; q++) {
2228223637Sbz		if (TAILQ_EMPTY(&sc->sc_qs[q]))
2229223637Sbz			continue;
2230223637Sbz
2231223637Sbz		subh = (struct pfsync_subheader *)(m->m_data + offset);
2232223637Sbz		offset += sizeof(*subh);
2233223637Sbz
2234223637Sbz		count = 0;
2235223637Sbz		TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) {
2236223637Sbz#ifdef PFSYNC_DEBUG
2237159603Smlaier#ifdef __FreeBSD__
2238223637Sbz			KASSERT(st->sync_state == q,
2239223637Sbz				("%s: st->sync_state == q",
2240223637Sbz					__FUNCTION__));
2241159603Smlaier#else
2242223637Sbz			KASSERT(st->sync_state == q);
2243159603Smlaier#endif
2244223637Sbz#endif
2245130613Smlaier
2246223637Sbz			offset += pfsync_qs[q].write(st, m, offset);
2247223637Sbz			st->sync_state = PFSYNC_S_NONE;
2248223637Sbz			count++;
2249126258Smlaier		}
2250223637Sbz		TAILQ_INIT(&sc->sc_qs[q]);
2251130613Smlaier
2252223637Sbz		bzero(subh, sizeof(*subh));
2253223637Sbz		subh->action = pfsync_qs[q].action;
2254223637Sbz		subh->count = htons(count);
2255126258Smlaier	}
2256126258Smlaier
2257223637Sbz	if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) {
2258223637Sbz		subh = (struct pfsync_subheader *)(m->m_data + offset);
2259223637Sbz		offset += sizeof(*subh);
2260126258Smlaier
2261223637Sbz		count = 0;
2262223637Sbz		while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) {
2263223637Sbz			TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry);
2264130613Smlaier
2265223637Sbz			bcopy(&ur->ur_msg, m->m_data + offset,
2266223637Sbz			    sizeof(ur->ur_msg));
2267223637Sbz			offset += sizeof(ur->ur_msg);
2268130613Smlaier
2269223637Sbz			pool_put(&sc->sc_pool, ur);
2270130613Smlaier
2271223637Sbz			count++;
2272223637Sbz		}
2273130613Smlaier
2274223637Sbz		bzero(subh, sizeof(*subh));
2275223637Sbz		subh->action = PFSYNC_ACT_UPD_REQ;
2276223637Sbz		subh->count = htons(count);
2277223637Sbz	}
2278130613Smlaier
2279223637Sbz	/* has someone built a custom region for us to add? */
2280223637Sbz	if (sc->sc_plus != NULL) {
2281223637Sbz		bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen);
2282223637Sbz		offset += sc->sc_pluslen;
2283130613Smlaier
2284223637Sbz		sc->sc_plus = NULL;
2285130613Smlaier	}
2286130613Smlaier
2287223637Sbz#ifdef notyet
2288223637Sbz	if (!TAILQ_EMPTY(&sc->sc_tdb_q)) {
2289223637Sbz		subh = (struct pfsync_subheader *)(m->m_data + offset);
2290223637Sbz		offset += sizeof(*subh);
2291126258Smlaier
2292223637Sbz		count = 0;
2293223637Sbz		TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) {
2294223637Sbz			offset += pfsync_out_tdb(t, m, offset);
2295223637Sbz			CLR(t->tdb_flags, TDBF_PFSYNC);
2296126258Smlaier
2297223637Sbz			count++;
2298130613Smlaier		}
2299223637Sbz		TAILQ_INIT(&sc->sc_tdb_q);
2300223637Sbz
2301223637Sbz		bzero(subh, sizeof(*subh));
2302223637Sbz		subh->action = PFSYNC_ACT_TDB;
2303223637Sbz		subh->count = htons(count);
2304130613Smlaier	}
2305223637Sbz#endif
2306130613Smlaier
2307223637Sbz	subh = (struct pfsync_subheader *)(m->m_data + offset);
2308223637Sbz	offset += sizeof(*subh);
2309130613Smlaier
2310223637Sbz	bzero(subh, sizeof(*subh));
2311223637Sbz	subh->action = PFSYNC_ACT_EOF;
2312223637Sbz	subh->count = htons(1);
2313130613Smlaier
2314223637Sbz	/* XXX write checksum in EOF here */
2315130613Smlaier
2316223637Sbz	/* we're done, let's put it on the wire */
2317223637Sbz#if NBPFILTER > 0
2318223637Sbz	if (ifp->if_bpf) {
2319223637Sbz		m->m_data += sizeof(*ip);
2320223637Sbz		m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip);
2321223637Sbz#ifdef __FreeBSD__
2322223637Sbz		BPF_MTAP(ifp, m);
2323223637Sbz#else
2324223637Sbz		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
2325223637Sbz#endif
2326223637Sbz		m->m_data -= sizeof(*ip);
2327223637Sbz		m->m_len = m->m_pkthdr.len = sc->sc_len;
2328130613Smlaier	}
2329130613Smlaier
2330223637Sbz	if (sc->sc_sync_if == NULL) {
2331223637Sbz		sc->sc_len = PFSYNC_MINPKT;
2332223637Sbz		m_freem(m);
2333223637Sbz		return;
2334223637Sbz	}
2335223637Sbz#endif
2336126258Smlaier
2337223637Sbz#ifdef __FreeBSD__
2338223637Sbz	sc->sc_ifp->if_opackets++;
2339223637Sbz	sc->sc_ifp->if_obytes += m->m_pkthdr.len;
2340223637Sbz#else
2341223637Sbz	sc->sc_if.if_opackets++;
2342223637Sbz	sc->sc_if.if_obytes += m->m_pkthdr.len;
2343223637Sbz#endif
2344223637Sbz
2345223637Sbz#ifdef __FreeBSD__
2346223637Sbz	PF_UNLOCK();
2347223637Sbz#endif
2348223637Sbz	if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0)
2349223637Sbz#ifdef __FreeBSD__
2350223637Sbz	{
2351223637Sbz		PF_LOCK();
2352223637Sbz#endif
2353223637Sbz		V_pfsyncstats.pfsyncs_opackets++;
2354223637Sbz#ifdef __FreeBSD__
2355223637Sbz	}
2356223637Sbz#endif
2357223637Sbz	else
2358223637Sbz#ifdef __FreeBSD__
2359223637Sbz	{
2360223637Sbz		PF_LOCK();
2361223637Sbz#endif
2362223637Sbz		V_pfsyncstats.pfsyncs_oerrors++;
2363223637Sbz#ifdef __FreeBSD__
2364223637Sbz	}
2365223637Sbz#endif
2366223637Sbz
2367223637Sbz	/* start again */
2368223637Sbz	sc->sc_len = PFSYNC_MINPKT;
2369126258Smlaier}
2370126258Smlaier
2371223637Sbzvoid
2372223637Sbzpfsync_insert_state(struct pf_state *st)
2373126258Smlaier{
2374223637Sbz#ifdef __FreeBSD__
2375223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2376223637Sbz#else
2377171168Smlaier	struct pfsync_softc *sc = pfsyncif;
2378223637Sbz#endif
2379130613Smlaier
2380130613Smlaier#ifdef __FreeBSD__
2381223637Sbz	PF_ASSERT(MA_OWNED);
2382171168Smlaier#else
2383223637Sbz	splassert(IPL_SOFTNET);
2384126261Smlaier#endif
2385130613Smlaier
2386223637Sbz	if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) ||
2387223637Sbz	    st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) {
2388223637Sbz		SET(st->state_flags, PFSTATE_NOSYNC);
2389223637Sbz		return;
2390130613Smlaier	}
2391130613Smlaier
2392223637Sbz	if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC))
2393223637Sbz		return;
2394130613Smlaier
2395223637Sbz#ifdef PFSYNC_DEBUG
2396223637Sbz#ifdef __FreeBSD__
2397223637Sbz	KASSERT(st->sync_state == PFSYNC_S_NONE,
2398223637Sbz		("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
2399223637Sbz#else
2400223637Sbz	KASSERT(st->sync_state == PFSYNC_S_NONE);
2401223637Sbz#endif
2402223637Sbz#endif
2403223637Sbz
2404223637Sbz	if (sc->sc_len == PFSYNC_MINPKT)
2405223637Sbz#ifdef __FreeBSD__
2406223637Sbz		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2407223637Sbz		    V_pfsyncif);
2408223637Sbz#else
2409223637Sbz		timeout_add_sec(&sc->sc_tmo, 1);
2410223637Sbz#endif
2411223637Sbz
2412223637Sbz	pfsync_q_ins(st, PFSYNC_S_INS);
2413223637Sbz
2414223637Sbz	if (ISSET(st->state_flags, PFSTATE_ACK))
2415223637Sbz		schednetisr(NETISR_PFSYNC);
2416223637Sbz	else
2417223637Sbz		st->sync_updates = 0;
2418130613Smlaier}
2419130613Smlaier
2420223637Sbzint defer = 10;
2421223637Sbz
2422130613Smlaierint
2423223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m)
2424130613Smlaier{
2425223637Sbz#ifdef __FreeBSD__
2426223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2427223637Sbz#else
2428171168Smlaier	struct pfsync_softc *sc = pfsyncif;
2429223637Sbz#endif
2430223637Sbz	struct pfsync_deferral *pd;
2431126258Smlaier
2432223637Sbz#ifdef __FreeBSD__
2433223637Sbz	PF_ASSERT(MA_OWNED);
2434223637Sbz#else
2435223637Sbz	splassert(IPL_SOFTNET);
2436223637Sbz#endif
2437223637Sbz
2438223637Sbz	if (sc->sc_deferred >= 128)
2439223637Sbz		pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0);
2440223637Sbz
2441223637Sbz	pd = pool_get(&sc->sc_pool, M_NOWAIT);
2442223637Sbz	if (pd == NULL)
2443171168Smlaier		return (0);
2444223637Sbz	sc->sc_deferred++;
2445171168Smlaier
2446130613Smlaier#ifdef __FreeBSD__
2447223637Sbz	m->m_flags |= M_SKIP_FIREWALL;
2448171168Smlaier#else
2449223637Sbz	m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
2450171168Smlaier#endif
2451223637Sbz	SET(st->state_flags, PFSTATE_ACK);
2452223637Sbz
2453223637Sbz	pd->pd_st = st;
2454223637Sbz	pd->pd_m = m;
2455223637Sbz
2456223637Sbz	TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry);
2457171168Smlaier#ifdef __FreeBSD__
2458223637Sbz	callout_init(&pd->pd_tmo, CALLOUT_MPSAFE);
2459223637Sbz	callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo,
2460223637Sbz		pd);
2461223637Sbz#else
2462223637Sbz	timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd);
2463223637Sbz	timeout_add(&pd->pd_tmo, defer);
2464130613Smlaier#endif
2465126258Smlaier
2466223637Sbz	return (1);
2467126258Smlaier}
2468126258Smlaier
2469126258Smlaiervoid
2470223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop)
2471126258Smlaier{
2472223637Sbz#ifdef __FreeBSD__
2473223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2474223637Sbz#else
2475223637Sbz	struct pfsync_softc *sc = pfsyncif;
2476223637Sbz#endif
2477126258Smlaier	int s;
2478126258Smlaier
2479130613Smlaier#ifdef __FreeBSD__
2480223637Sbz	PF_ASSERT(MA_OWNED);
2481223637Sbz#else
2482223637Sbz	splassert(IPL_SOFTNET);
2483130613Smlaier#endif
2484223637Sbz
2485223637Sbz	TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry);
2486223637Sbz	sc->sc_deferred--;
2487223637Sbz
2488223637Sbz	CLR(pd->pd_st->state_flags, PFSTATE_ACK);
2489223637Sbz	timeout_del(&pd->pd_tmo); /* bah */
2490223637Sbz	if (drop)
2491223637Sbz		m_freem(pd->pd_m);
2492223637Sbz	else {
2493223637Sbz		s = splnet();
2494130613Smlaier#ifdef __FreeBSD__
2495223637Sbz		/* XXX: use pf_defered?! */
2496223637Sbz		PF_UNLOCK();
2497130613Smlaier#endif
2498223637Sbz		ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0,
2499223637Sbz		    (void *)NULL, (void *)NULL);
2500223637Sbz#ifdef __FreeBSD__
2501223637Sbz		PF_LOCK();
2502223637Sbz#endif
2503223637Sbz		splx(s);
2504223637Sbz	}
2505223637Sbz
2506223637Sbz	pool_put(&sc->sc_pool, pd);
2507126258Smlaier}
2508126258Smlaier
2509171168Smlaiervoid
2510223637Sbzpfsync_defer_tmo(void *arg)
2511171168Smlaier{
2512223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE)
2513223637Sbz	struct pfsync_deferral *pd = arg;
2514223637Sbz#endif
2515171168Smlaier	int s;
2516171168Smlaier
2517223637Sbz	s = splsoftnet();
2518171168Smlaier#ifdef __FreeBSD__
2519223637Sbz	CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */
2520171168Smlaier	PF_LOCK();
2521171168Smlaier#endif
2522223637Sbz	pfsync_undefer(arg, 0);
2523171168Smlaier#ifdef __FreeBSD__
2524171168Smlaier	PF_UNLOCK();
2525223637Sbz	CURVNET_RESTORE();
2526171168Smlaier#endif
2527171168Smlaier	splx(s);
2528171168Smlaier}
2529223637Sbz
2530223637Sbzvoid
2531223637Sbzpfsync_deferred(struct pf_state *st, int drop)
2532223637Sbz{
2533223637Sbz#ifdef __FreeBSD__
2534223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2535223637Sbz#else
2536223637Sbz	struct pfsync_softc *sc = pfsyncif;
2537171168Smlaier#endif
2538223637Sbz	struct pfsync_deferral *pd;
2539171168Smlaier
2540223637Sbz	TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) {
2541223637Sbz		 if (pd->pd_st == st) {
2542223637Sbz			pfsync_undefer(pd, drop);
2543223637Sbz			return;
2544223637Sbz		}
2545223637Sbz	}
2546223637Sbz
2547223637Sbz	panic("pfsync_send_deferred: unable to find deferred state");
2548223637Sbz}
2549223637Sbz
2550223637Sbzu_int pfsync_upds = 0;
2551223637Sbz
2552130613Smlaiervoid
2553223637Sbzpfsync_update_state(struct pf_state *st)
2554130613Smlaier{
2555223637Sbz#ifdef __FreeBSD__
2556223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2557223637Sbz#else
2558223637Sbz	struct pfsync_softc *sc = pfsyncif;
2559223637Sbz#endif
2560223637Sbz	int sync = 0;
2561130613Smlaier
2562130613Smlaier#ifdef __FreeBSD__
2563130613Smlaier	PF_ASSERT(MA_OWNED);
2564223637Sbz#else
2565223637Sbz	splassert(IPL_SOFTNET);
2566130613Smlaier#endif
2567130613Smlaier
2568223637Sbz	if (sc == NULL)
2569223637Sbz		return;
2570223637Sbz
2571223637Sbz	if (ISSET(st->state_flags, PFSTATE_ACK))
2572223637Sbz		pfsync_deferred(st, 0);
2573223637Sbz	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2574223637Sbz		if (st->sync_state != PFSYNC_S_NONE)
2575223637Sbz			pfsync_q_del(st);
2576223637Sbz		return;
2577130613Smlaier	}
2578223637Sbz
2579223637Sbz	if (sc->sc_len == PFSYNC_MINPKT)
2580223637Sbz#ifdef __FreeBSD__
2581223637Sbz		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2582223637Sbz		    V_pfsyncif);
2583223637Sbz#else
2584223637Sbz		timeout_add_sec(&sc->sc_tmo, 1);
2585223637Sbz#endif
2586223637Sbz
2587223637Sbz	switch (st->sync_state) {
2588223637Sbz	case PFSYNC_S_UPD_C:
2589223637Sbz	case PFSYNC_S_UPD:
2590223637Sbz	case PFSYNC_S_INS:
2591223637Sbz		/* we're already handling it */
2592223637Sbz
2593223637Sbz		st->sync_updates++;
2594223637Sbz		if (st->sync_updates >= sc->sc_maxupdates)
2595223637Sbz			sync = 1;
2596223637Sbz		break;
2597223637Sbz
2598223637Sbz	case PFSYNC_S_IACK:
2599223637Sbz		pfsync_q_del(st);
2600223637Sbz	case PFSYNC_S_NONE:
2601223637Sbz		pfsync_q_ins(st, PFSYNC_S_UPD_C);
2602223637Sbz		st->sync_updates = 0;
2603223637Sbz		break;
2604223637Sbz
2605223637Sbz	default:
2606223637Sbz		panic("pfsync_update_state: unexpected sync state %d",
2607223637Sbz		    st->sync_state);
2608223637Sbz	}
2609223637Sbz
2610223637Sbz	if (sync || (time_second - st->pfsync_time) < 2) {
2611223637Sbz		pfsync_upds++;
2612223637Sbz		schednetisr(NETISR_PFSYNC);
2613223637Sbz	}
2614130613Smlaier}
2615130613Smlaier
2616130613Smlaiervoid
2617223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id)
2618130613Smlaier{
2619130613Smlaier#ifdef __FreeBSD__
2620223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2621223637Sbz#else
2622223637Sbz	struct pfsync_softc *sc = pfsyncif;
2623130613Smlaier#endif
2624223637Sbz	struct pfsync_upd_req_item *item;
2625223637Sbz	size_t nlen = sizeof(struct pfsync_upd_req);
2626223637Sbz	int s;
2627130613Smlaier
2628130613Smlaier	/*
2629223637Sbz	 * this code does nothing to prevent multiple update requests for the
2630223637Sbz	 * same state being generated.
2631130613Smlaier	 */
2632130613Smlaier
2633223637Sbz	item = pool_get(&sc->sc_pool, PR_NOWAIT);
2634223637Sbz	if (item == NULL) {
2635223637Sbz		/* XXX stats */
2636223637Sbz		return;
2637223637Sbz	}
2638171168Smlaier
2639223637Sbz	item->ur_msg.id = id;
2640223637Sbz	item->ur_msg.creatorid = creatorid;
2641171168Smlaier
2642223637Sbz	if (TAILQ_EMPTY(&sc->sc_upd_req_list))
2643223637Sbz		nlen += sizeof(struct pfsync_subheader);
2644223637Sbz
2645130613Smlaier#ifdef __FreeBSD__
2646223637Sbz	if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) {
2647130613Smlaier#else
2648223637Sbz	if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2649130613Smlaier#endif
2650223637Sbz		s = splnet();
2651223637Sbz		pfsync_sendout();
2652223637Sbz		splx(s);
2653223637Sbz
2654223637Sbz		nlen = sizeof(struct pfsync_subheader) +
2655223637Sbz		    sizeof(struct pfsync_upd_req);
2656130613Smlaier	}
2657223637Sbz
2658223637Sbz	TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry);
2659223637Sbz	sc->sc_len += nlen;
2660223637Sbz
2661223637Sbz	schednetisr(NETISR_PFSYNC);
2662223637Sbz}
2663223637Sbz
2664223637Sbzvoid
2665223637Sbzpfsync_update_state_req(struct pf_state *st)
2666223637Sbz{
2667130613Smlaier#ifdef __FreeBSD__
2668223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2669223637Sbz#else
2670223637Sbz	struct pfsync_softc *sc = pfsyncif;
2671130613Smlaier#endif
2672223637Sbz
2673223637Sbz	if (sc == NULL)
2674223637Sbz		panic("pfsync_update_state_req: nonexistant instance");
2675223637Sbz
2676223637Sbz	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2677223637Sbz		if (st->sync_state != PFSYNC_S_NONE)
2678223637Sbz			pfsync_q_del(st);
2679223637Sbz		return;
2680223637Sbz	}
2681223637Sbz
2682223637Sbz	switch (st->sync_state) {
2683223637Sbz	case PFSYNC_S_UPD_C:
2684223637Sbz	case PFSYNC_S_IACK:
2685223637Sbz		pfsync_q_del(st);
2686223637Sbz	case PFSYNC_S_NONE:
2687223637Sbz		pfsync_q_ins(st, PFSYNC_S_UPD);
2688223637Sbz		schednetisr(NETISR_PFSYNC);
2689223637Sbz		return;
2690223637Sbz
2691223637Sbz	case PFSYNC_S_INS:
2692223637Sbz	case PFSYNC_S_UPD:
2693223637Sbz	case PFSYNC_S_DEL:
2694223637Sbz		/* we're already handling it */
2695223637Sbz		return;
2696223637Sbz
2697223637Sbz	default:
2698223637Sbz		panic("pfsync_update_state_req: unexpected sync state %d",
2699223637Sbz		    st->sync_state);
2700223637Sbz	}
2701130613Smlaier}
2702130613Smlaier
2703130613Smlaiervoid
2704223637Sbzpfsync_delete_state(struct pf_state *st)
2705130613Smlaier{
2706130613Smlaier#ifdef __FreeBSD__
2707223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2708223637Sbz#else
2709223637Sbz	struct pfsync_softc *sc = pfsyncif;
2710130613Smlaier#endif
2711223637Sbz
2712130613Smlaier#ifdef __FreeBSD__
2713223637Sbz	PF_ASSERT(MA_OWNED);
2714130613Smlaier#else
2715223637Sbz	splassert(IPL_SOFTNET);
2716130613Smlaier#endif
2717223637Sbz
2718223637Sbz	if (sc == NULL)
2719223637Sbz		return;
2720223637Sbz
2721223637Sbz	if (ISSET(st->state_flags, PFSTATE_ACK))
2722223637Sbz		pfsync_deferred(st, 1);
2723223637Sbz	if (ISSET(st->state_flags, PFSTATE_NOSYNC)) {
2724223637Sbz		if (st->sync_state != PFSYNC_S_NONE)
2725223637Sbz			pfsync_q_del(st);
2726223637Sbz		return;
2727223637Sbz	}
2728223637Sbz
2729223637Sbz	if (sc->sc_len == PFSYNC_MINPKT)
2730171168Smlaier#ifdef __FreeBSD__
2731223637Sbz		callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout,
2732223637Sbz		    V_pfsyncif);
2733171168Smlaier#else
2734223637Sbz		timeout_add_sec(&sc->sc_tmo, 1);
2735171168Smlaier#endif
2736223637Sbz
2737223637Sbz	switch (st->sync_state) {
2738223637Sbz	case PFSYNC_S_INS:
2739223637Sbz		/* we never got to tell the world so just forget about it */
2740223637Sbz		pfsync_q_del(st);
2741223637Sbz		return;
2742223637Sbz
2743223637Sbz	case PFSYNC_S_UPD_C:
2744223637Sbz	case PFSYNC_S_UPD:
2745223637Sbz	case PFSYNC_S_IACK:
2746223637Sbz		pfsync_q_del(st);
2747223637Sbz		/* FALLTHROUGH to putting it on the del list */
2748223637Sbz
2749223637Sbz	case PFSYNC_S_NONE:
2750223637Sbz		pfsync_q_ins(st, PFSYNC_S_DEL);
2751223637Sbz		return;
2752223637Sbz
2753223637Sbz	default:
2754223637Sbz		panic("pfsync_delete_state: unexpected sync state %d",
2755223637Sbz		    st->sync_state);
2756130613Smlaier	}
2757223637Sbz}
2758223637Sbz
2759223637Sbzvoid
2760223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname)
2761223637Sbz{
2762223637Sbz	struct {
2763223637Sbz		struct pfsync_subheader subh;
2764223637Sbz		struct pfsync_clr clr;
2765223637Sbz	} __packed r;
2766223637Sbz
2767130613Smlaier#ifdef __FreeBSD__
2768223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2769223637Sbz#else
2770223637Sbz	struct pfsync_softc *sc = pfsyncif;
2771130613Smlaier#endif
2772223637Sbz
2773223637Sbz#ifdef __FreeBSD__
2774223637Sbz	PF_ASSERT(MA_OWNED);
2775223637Sbz#else
2776223637Sbz	splassert(IPL_SOFTNET);
2777223637Sbz#endif
2778223637Sbz
2779223637Sbz	if (sc == NULL)
2780223637Sbz		return;
2781223637Sbz
2782223637Sbz	bzero(&r, sizeof(r));
2783223637Sbz
2784223637Sbz	r.subh.action = PFSYNC_ACT_CLR;
2785223637Sbz	r.subh.count = htons(1);
2786223637Sbz
2787223637Sbz	strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname));
2788223637Sbz	r.clr.creatorid = creatorid;
2789223637Sbz
2790223637Sbz	pfsync_send_plus(&r, sizeof(r));
2791130613Smlaier}
2792130613Smlaier
2793223637Sbzvoid
2794223637Sbzpfsync_q_ins(struct pf_state *st, int q)
2795126258Smlaier{
2796171168Smlaier#ifdef __FreeBSD__
2797223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2798171168Smlaier#else
2799223637Sbz	struct pfsync_softc *sc = pfsyncif;
2800138666Smlaier#endif
2801223637Sbz	size_t nlen = pfsync_qs[q].len;
2802223637Sbz	int s;
2803223637Sbz
2804223637Sbz#ifdef __FreeBSD__
2805223637Sbz	KASSERT(st->sync_state == PFSYNC_S_NONE,
2806223637Sbz		("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__));
2807223637Sbz#else
2808223637Sbz	KASSERT(st->sync_state == PFSYNC_S_NONE);
2809171168Smlaier#endif
2810126258Smlaier
2811223637Sbz#if 1 || defined(PFSYNC_DEBUG)
2812223637Sbz	if (sc->sc_len < PFSYNC_MINPKT)
2813127145Smlaier#ifdef __FreeBSD__
2814223637Sbz		panic("pfsync pkt len is too low %zu", sc->sc_len);
2815223637Sbz#else
2816223637Sbz		panic("pfsync pkt len is too low %d", sc->sc_len);
2817171168Smlaier#endif
2818223637Sbz#endif
2819223637Sbz	if (TAILQ_EMPTY(&sc->sc_qs[q]))
2820223637Sbz		nlen += sizeof(struct pfsync_subheader);
2821130613Smlaier
2822165632Sjhb#ifdef __FreeBSD__
2823223637Sbz	if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) {
2824165632Sjhb#else
2825223637Sbz	if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2826126258Smlaier#endif
2827223637Sbz		s = splnet();
2828223637Sbz#ifdef __FreeBSD__
2829223637Sbz		PF_LOCK();
2830165632Sjhb#endif
2831223637Sbz		pfsync_sendout();
2832223637Sbz#ifdef __FreeBSD__
2833223637Sbz		PF_UNLOCK();
2834223637Sbz#endif
2835223637Sbz		splx(s);
2836126258Smlaier
2837223637Sbz		nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len;
2838130613Smlaier	}
2839126258Smlaier
2840223637Sbz	sc->sc_len += nlen;
2841223637Sbz	TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
2842223637Sbz	st->sync_state = q;
2843171168Smlaier}
2844171168Smlaier
2845223637Sbzvoid
2846223637Sbzpfsync_q_del(struct pf_state *st)
2847171168Smlaier{
2848159603Smlaier#ifdef __FreeBSD__
2849223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2850171168Smlaier#else
2851223637Sbz	struct pfsync_softc *sc = pfsyncif;
2852171168Smlaier#endif
2853223637Sbz	int q = st->sync_state;
2854171168Smlaier
2855171168Smlaier#ifdef __FreeBSD__
2856223637Sbz	KASSERT(st->sync_state != PFSYNC_S_NONE,
2857223637Sbz		("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__));
2858223637Sbz#else
2859223637Sbz	KASSERT(st->sync_state != PFSYNC_S_NONE);
2860171168Smlaier#endif
2861171168Smlaier
2862223637Sbz	sc->sc_len -= pfsync_qs[q].len;
2863223637Sbz	TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
2864223637Sbz	st->sync_state = PFSYNC_S_NONE;
2865171168Smlaier
2866223637Sbz	if (TAILQ_EMPTY(&sc->sc_qs[q]))
2867223637Sbz		sc->sc_len -= sizeof(struct pfsync_subheader);
2868223637Sbz}
2869223637Sbz
2870223637Sbz#ifdef notyet
2871223637Sbzvoid
2872223637Sbzpfsync_update_tdb(struct tdb *t, int output)
2873223637Sbz{
2874171168Smlaier#ifdef __FreeBSD__
2875223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2876171168Smlaier#else
2877223637Sbz	struct pfsync_softc *sc = pfsyncif;
2878171168Smlaier#endif
2879223637Sbz	size_t nlen = sizeof(struct pfsync_tdb);
2880223637Sbz	int s;
2881171168Smlaier
2882223637Sbz	if (sc == NULL)
2883223637Sbz		return;
2884223637Sbz
2885223637Sbz	if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) {
2886223637Sbz		if (TAILQ_EMPTY(&sc->sc_tdb_q))
2887223637Sbz			nlen += sizeof(struct pfsync_subheader);
2888223637Sbz
2889223637Sbz		if (sc->sc_len + nlen > sc->sc_if.if_mtu) {
2890223637Sbz			s = splnet();
2891223637Sbz			pfsync_sendout();
2892223637Sbz			splx(s);
2893223637Sbz
2894223637Sbz			nlen = sizeof(struct pfsync_subheader) +
2895223637Sbz			    sizeof(struct pfsync_tdb);
2896223637Sbz		}
2897223637Sbz
2898223637Sbz		sc->sc_len += nlen;
2899223637Sbz		TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry);
2900223637Sbz		SET(t->tdb_flags, TDBF_PFSYNC);
2901223637Sbz		t->tdb_updates = 0;
2902223637Sbz	} else {
2903223637Sbz		if (++t->tdb_updates >= sc->sc_maxupdates)
2904223637Sbz			schednetisr(NETISR_PFSYNC);
2905223637Sbz	}
2906223637Sbz
2907223637Sbz	if (output)
2908223637Sbz		SET(t->tdb_flags, TDBF_PFSYNC_RPL);
2909223637Sbz	else
2910223637Sbz		CLR(t->tdb_flags, TDBF_PFSYNC_RPL);
2911171168Smlaier}
2912223637Sbz
2913223637Sbzvoid
2914223637Sbzpfsync_delete_tdb(struct tdb *t)
2915223637Sbz{
2916223637Sbz#ifdef __FreeBSD__
2917223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2918223637Sbz#else
2919223637Sbz	struct pfsync_softc *sc = pfsyncif;
2920171168Smlaier#endif
2921171168Smlaier
2922223637Sbz	if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC))
2923223637Sbz		return;
2924223637Sbz
2925223637Sbz	sc->sc_len -= sizeof(struct pfsync_tdb);
2926223637Sbz	TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry);
2927223637Sbz	CLR(t->tdb_flags, TDBF_PFSYNC);
2928223637Sbz
2929223637Sbz	if (TAILQ_EMPTY(&sc->sc_tdb_q))
2930223637Sbz		sc->sc_len -= sizeof(struct pfsync_subheader);
2931223637Sbz}
2932223637Sbz
2933171168Smlaierint
2934223637Sbzpfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset)
2935171168Smlaier{
2936223637Sbz	struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset);
2937171168Smlaier
2938223637Sbz	bzero(ut, sizeof(*ut));
2939223637Sbz	ut->spi = t->tdb_spi;
2940223637Sbz	bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst));
2941223637Sbz	/*
2942223637Sbz	 * When a failover happens, the master's rpl is probably above
2943223637Sbz	 * what we see here (we may be up to a second late), so
2944223637Sbz	 * increase it a bit for outbound tdbs to manage most such
2945223637Sbz	 * situations.
2946223637Sbz	 *
2947223637Sbz	 * For now, just add an offset that is likely to be larger
2948223637Sbz	 * than the number of packets we can see in one second. The RFC
2949223637Sbz	 * just says the next packet must have a higher seq value.
2950223637Sbz	 *
2951223637Sbz	 * XXX What is a good algorithm for this? We could use
2952223637Sbz	 * a rate-determined increase, but to know it, we would have
2953223637Sbz	 * to extend struct tdb.
2954223637Sbz	 * XXX pt->rpl can wrap over MAXINT, but if so the real tdb
2955223637Sbz	 * will soon be replaced anyway. For now, just don't handle
2956223637Sbz	 * this edge case.
2957223637Sbz	 */
2958223637Sbz#define RPL_INCR 16384
2959223637Sbz	ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ?
2960223637Sbz	    RPL_INCR : 0));
2961223637Sbz	ut->cur_bytes = htobe64(t->tdb_cur_bytes);
2962223637Sbz	ut->sproto = t->tdb_sproto;
2963223637Sbz
2964223637Sbz	return (sizeof(*ut));
2965223637Sbz}
2966223637Sbz#endif
2967223637Sbz
2968223637Sbzvoid
2969223637Sbzpfsync_bulk_start(void)
2970223637Sbz{
2971171168Smlaier#ifdef __FreeBSD__
2972223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
2973223637Sbz#else
2974223637Sbz	struct pfsync_softc *sc = pfsyncif;
2975171168Smlaier#endif
2976223637Sbz
2977223637Sbz	sc->sc_ureq_received = time_uptime;
2978223637Sbz
2979223637Sbz	if (sc->sc_bulk_next == NULL)
2980171168Smlaier#ifdef __FreeBSD__
2981223637Sbz		sc->sc_bulk_next = TAILQ_FIRST(&V_state_list);
2982159603Smlaier#else
2983223637Sbz		sc->sc_bulk_next = TAILQ_FIRST(&state_list);
2984159603Smlaier#endif
2985223637Sbz	sc->sc_bulk_last = sc->sc_bulk_next;
2986223637Sbz
2987223637Sbz#ifdef __FreeBSD__
2988223637Sbz	if (V_pf_status.debug >= PF_DEBUG_MISC)
2989223637Sbz#else
2990223637Sbz	if (pf_status.debug >= PF_DEBUG_MISC)
2991223637Sbz#endif
2992223637Sbz		printf("pfsync: received bulk update request\n");
2993223637Sbz
2994223637Sbz	pfsync_bulk_status(PFSYNC_BUS_START);
2995223637Sbz	pfsync_bulk_update(sc);
2996223637Sbz}
2997223637Sbz
2998223637Sbzvoid
2999223637Sbzpfsync_bulk_update(void *arg)
3000223637Sbz{
3001223637Sbz	struct pfsync_softc *sc = arg;
3002223637Sbz	struct pf_state *st = sc->sc_bulk_next;
3003223637Sbz	int i = 0;
3004223637Sbz	int s;
3005223637Sbz
3006223637Sbz	s = splsoftnet();
3007223637Sbz#ifdef __FreeBSD__
3008223637Sbz	CURVNET_SET(sc->sc_ifp->if_vnet);
3009223637Sbz	PF_LOCK();
3010223637Sbz#endif
3011223637Sbz	do {
3012223637Sbz		if (st->sync_state == PFSYNC_S_NONE &&
3013223637Sbz		    st->timeout < PFTM_MAX &&
3014223637Sbz		    st->pfsync_time <= sc->sc_ureq_received) {
3015223637Sbz			pfsync_update_state_req(st);
3016223637Sbz			i++;
3017130613Smlaier		}
3018223637Sbz
3019223637Sbz		st = TAILQ_NEXT(st, entry_list);
3020223637Sbz		if (st == NULL)
3021130613Smlaier#ifdef __FreeBSD__
3022223637Sbz			st = TAILQ_FIRST(&V_state_list);
3023130613Smlaier#else
3024223637Sbz			st = TAILQ_FIRST(&state_list);
3025130613Smlaier#endif
3026223637Sbz
3027223637Sbz		if (i > 0 && TAILQ_EMPTY(&sc->sc_qs[PFSYNC_S_UPD])) {
3028223637Sbz			sc->sc_bulk_next = st;
3029130613Smlaier#ifdef __FreeBSD__
3030223637Sbz			callout_reset(&sc->sc_bulk_tmo, 1,
3031223637Sbz			    pfsync_bulk_fail, sc);
3032130613Smlaier#else
3033223637Sbz			timeout_add(&sc->sc_bulk_tmo, 1);
3034130613Smlaier#endif
3035223637Sbz			goto out;
3036223637Sbz		}
3037223637Sbz	} while (st != sc->sc_bulk_last);
3038130613Smlaier
3039223637Sbz	/* we're done */
3040223637Sbz	sc->sc_bulk_next = NULL;
3041223637Sbz	sc->sc_bulk_last = NULL;
3042223637Sbz	pfsync_bulk_status(PFSYNC_BUS_END);
3043130613Smlaier
3044223637Sbzout:
3045130613Smlaier#ifdef __FreeBSD__
3046223637Sbz	PF_UNLOCK();
3047223637Sbz	CURVNET_RESTORE();
3048223637Sbz#endif
3049223637Sbz	splx(s);
3050223637Sbz}
3051223637Sbz
3052223637Sbzvoid
3053223637Sbzpfsync_bulk_status(u_int8_t status)
3054223637Sbz{
3055223637Sbz	struct {
3056223637Sbz		struct pfsync_subheader subh;
3057223637Sbz		struct pfsync_bus bus;
3058223637Sbz	} __packed r;
3059223637Sbz
3060223637Sbz#ifdef __FreeBSD__
3061223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
3062130613Smlaier#else
3063223637Sbz	struct pfsync_softc *sc = pfsyncif;
3064130613Smlaier#endif
3065130613Smlaier
3066223637Sbz	bzero(&r, sizeof(r));
3067171168Smlaier
3068223637Sbz	r.subh.action = PFSYNC_ACT_BUS;
3069223637Sbz	r.subh.count = htons(1);
3070223637Sbz
3071130613Smlaier#ifdef __FreeBSD__
3072223637Sbz	r.bus.creatorid = V_pf_status.hostid;
3073147261Smlaier#else
3074223637Sbz	r.bus.creatorid = pf_status.hostid;
3075130613Smlaier#endif
3076223637Sbz	r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received);
3077223637Sbz	r.bus.status = status;
3078130613Smlaier
3079223637Sbz	pfsync_send_plus(&r, sizeof(r));
3080126258Smlaier}
3081126261Smlaier
3082171168Smlaiervoid
3083223637Sbzpfsync_bulk_fail(void *arg)
3084171168Smlaier{
3085223637Sbz	struct pfsync_softc *sc = arg;
3086171168Smlaier
3087223637Sbz#ifdef __FreeBSD__
3088223637Sbz	CURVNET_SET(sc->sc_ifp->if_vnet);
3089223637Sbz#endif
3090171168Smlaier
3091223637Sbz	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
3092223637Sbz		/* Try again */
3093223637Sbz#ifdef __FreeBSD__
3094223637Sbz		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
3095223637Sbz		    pfsync_bulk_fail, V_pfsyncif);
3096223637Sbz#else
3097223637Sbz		timeout_add_sec(&sc->sc_bulkfail_tmo, 5);
3098223637Sbz#endif
3099223637Sbz		pfsync_request_update(0, 0);
3100223637Sbz	} else {
3101223637Sbz		/* Pretend like the transfer was ok */
3102223637Sbz		sc->sc_ureq_sent = 0;
3103223637Sbz		sc->sc_bulk_tries = 0;
3104223637Sbz#if NCARP > 0
3105223637Sbz#ifdef notyet
3106223637Sbz#ifdef __FreeBSD__
3107223637Sbz		if (!sc->pfsync_sync_ok)
3108223637Sbz#else
3109223637Sbz		if (!pfsync_sync_ok)
3110223637Sbz#endif
3111223637Sbz			carp_group_demote_adj(&sc->sc_if, -1);
3112223637Sbz#endif
3113223637Sbz#endif
3114223637Sbz#ifdef __FreeBSD__
3115223637Sbz		sc->pfsync_sync_ok = 1;
3116223637Sbz#else
3117223637Sbz		pfsync_sync_ok = 1;
3118223637Sbz#endif
3119223637Sbz#ifdef __FreeBSD__
3120223637Sbz		if (V_pf_status.debug >= PF_DEBUG_MISC)
3121223637Sbz#else
3122223637Sbz		if (pf_status.debug >= PF_DEBUG_MISC)
3123223637Sbz#endif
3124223637Sbz			printf("pfsync: failed to receive bulk update\n");
3125223637Sbz	}
3126171168Smlaier
3127223637Sbz#ifdef __FreeBSD__
3128223637Sbz	CURVNET_RESTORE();
3129223637Sbz#endif
3130223637Sbz}
3131171168Smlaier
3132223637Sbzvoid
3133223637Sbzpfsync_send_plus(void *plus, size_t pluslen)
3134223637Sbz{
3135223637Sbz#ifdef __FreeBSD__
3136223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
3137223637Sbz#else
3138223637Sbz	struct pfsync_softc *sc = pfsyncif;
3139223637Sbz#endif
3140223637Sbz	int s;
3141223637Sbz
3142223637Sbz#ifdef __FreeBSD__
3143223637Sbz	if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) {
3144223637Sbz#else
3145223637Sbz	if (sc->sc_len + pluslen > sc->sc_if.if_mtu) {
3146223637Sbz#endif
3147223637Sbz		s = splnet();
3148223637Sbz#ifdef __FreeBSD__
3149223637Sbz		PF_LOCK();
3150223637Sbz#endif
3151223637Sbz		pfsync_sendout();
3152223637Sbz#ifdef __FreeBSD__
3153223637Sbz		PF_UNLOCK();
3154223637Sbz#endif
3155223637Sbz		splx(s);
3156171168Smlaier	}
3157223637Sbz
3158223637Sbz	sc->sc_plus = plus;
3159223637Sbz	sc->sc_len += (sc->sc_pluslen = pluslen);
3160223637Sbz
3161223637Sbz	s = splnet();
3162223637Sbz#ifdef __FreeBSD__
3163223637Sbz	PF_LOCK();
3164223637Sbz#endif
3165223637Sbz	pfsync_sendout();
3166223637Sbz#ifdef __FreeBSD__
3167223637Sbz	PF_UNLOCK();
3168223637Sbz#endif
3169171168Smlaier	splx(s);
3170171168Smlaier}
3171171168Smlaier
3172171168Smlaierint
3173223637Sbzpfsync_up(void)
3174171168Smlaier{
3175223637Sbz#ifdef __FreeBSD__
3176223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
3177223637Sbz#else
3178171168Smlaier	struct pfsync_softc *sc = pfsyncif;
3179223637Sbz#endif
3180171168Smlaier
3181147261Smlaier#ifdef __FreeBSD__
3182223637Sbz	if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING))
3183171168Smlaier#else
3184223637Sbz	if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING))
3185171168Smlaier#endif
3186223637Sbz		return (0);
3187223637Sbz
3188223637Sbz	return (1);
3189223637Sbz}
3190223637Sbz
3191223637Sbzint
3192223637Sbzpfsync_state_in_use(struct pf_state *st)
3193223637Sbz{
3194171168Smlaier#ifdef __FreeBSD__
3195223637Sbz	struct pfsync_softc *sc = V_pfsyncif;
3196171168Smlaier#else
3197223637Sbz	struct pfsync_softc *sc = pfsyncif;
3198171168Smlaier#endif
3199223637Sbz
3200223637Sbz	if (sc == NULL)
3201171168Smlaier		return (0);
3202171168Smlaier
3203223637Sbz	if (st->sync_state != PFSYNC_S_NONE)
3204223637Sbz		return (1);
3205223637Sbz
3206223637Sbz	if (sc->sc_bulk_next == NULL && sc->sc_bulk_last == NULL)
3207223637Sbz		return (0);
3208223637Sbz
3209223637Sbz	return (1);
3210223637Sbz}
3211223637Sbz
3212223637Sbzu_int pfsync_ints;
3213223637Sbzu_int pfsync_tmos;
3214223637Sbz
3215223637Sbzvoid
3216223637Sbzpfsync_timeout(void *arg)
3217223637Sbz{
3218223637Sbz#if defined(__FreeBSD__) && defined(VIMAGE)
3219223637Sbz	struct pfsync_softc *sc = arg;
3220223637Sbz#endif
3221223637Sbz	int s;
3222223637Sbz
3223171168Smlaier#ifdef __FreeBSD__
3224223637Sbz	CURVNET_SET(sc->sc_ifp->if_vnet);
3225171168Smlaier#endif
3226223637Sbz
3227223637Sbz	pfsync_tmos++;
3228223637Sbz
3229171168Smlaier	s = splnet();
3230223637Sbz#ifdef __FreeBSD__
3231223637Sbz	PF_LOCK();
3232223637Sbz#endif
3233223637Sbz	pfsync_sendout();
3234223637Sbz#ifdef __FreeBSD__
3235223637Sbz	PF_UNLOCK();
3236223637Sbz#endif
3237223637Sbz	splx(s);
3238171168Smlaier
3239223637Sbz#ifdef __FreeBSD__
3240223637Sbz	CURVNET_RESTORE();
3241223637Sbz#endif
3242223637Sbz}
3243171168Smlaier
3244223637Sbz/* this is a softnet/netisr handler */
3245223637Sbzvoid
3246223637Sbz#ifdef __FreeBSD__
3247223637Sbzpfsyncintr(void *arg)
3248223637Sbz#else
3249223637Sbzpfsyncintr(void)
3250223637Sbz#endif
3251223637Sbz{
3252223637Sbz#ifdef __FreeBSD__
3253223637Sbz	struct pfsync_softc *sc = arg;
3254223637Sbz#endif
3255223637Sbz	int s;
3256171168Smlaier
3257223637Sbz#ifdef __FreeBSD__
3258223637Sbz	if (sc == NULL)
3259223637Sbz		return;
3260171168Smlaier
3261223637Sbz	CURVNET_SET(sc->sc_ifp->if_vnet);
3262223637Sbz#endif
3263223637Sbz	pfsync_ints++;
3264171168Smlaier
3265223637Sbz	s = splnet();
3266223637Sbz#ifdef __FreeBSD__
3267223637Sbz	PF_LOCK();
3268223637Sbz#endif
3269223637Sbz	pfsync_sendout();
3270223637Sbz#ifdef __FreeBSD__
3271223637Sbz	PF_UNLOCK();
3272223637Sbz#endif
3273223637Sbz	splx(s);
3274171168Smlaier
3275223637Sbz#ifdef __FreeBSD__
3276223637Sbz	CURVNET_RESTORE();
3277223637Sbz#endif
3278171168Smlaier}
3279171168Smlaier
3280223637Sbzint
3281223637Sbzpfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
3282223637Sbz    size_t newlen)
3283223637Sbz{
3284223637Sbz
3285223637Sbz#ifdef notyet
3286223637Sbz	/* All sysctl names at this level are terminal. */
3287223637Sbz	if (namelen != 1)
3288223637Sbz		return (ENOTDIR);
3289223637Sbz
3290223637Sbz	switch (name[0]) {
3291223637Sbz	case PFSYNCCTL_STATS:
3292223637Sbz		if (newp != NULL)
3293223637Sbz			return (EPERM);
3294223637Sbz		return (sysctl_struct(oldp, oldlenp, newp, newlen,
3295223637Sbz		    &V_pfsyncstats, sizeof(V_pfsyncstats)));
3296223637Sbz	}
3297223637Sbz#endif
3298223637Sbz	return (ENOPROTOOPT);
3299223637Sbz}
3300223637Sbz
3301171168Smlaier#ifdef __FreeBSD__
3302171168Smlaiervoid
3303167710Sbmspfsync_ifdetach(void *arg, struct ifnet *ifp)
3304167710Sbms{
3305167710Sbms	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
3306167710Sbms	struct ip_moptions *imo;
3307167710Sbms
3308223637Sbz	if (sc == NULL || sc->sc_sync_if != ifp)
3309171168Smlaier		return;         /* not for us; unlocked read */
3310167710Sbms
3311223637Sbz	CURVNET_SET(sc->sc_ifp->if_vnet);
3312223637Sbz
3313167710Sbms	PF_LOCK();
3314167710Sbms
3315167710Sbms	/* Deal with a member interface going away from under us. */
3316223637Sbz	sc->sc_sync_if = NULL;
3317167710Sbms	imo = &sc->sc_imo;
3318167710Sbms	if (imo->imo_num_memberships > 0) {
3319168700Sbms		KASSERT(imo->imo_num_memberships == 1,
3320171168Smlaier		    ("%s: imo_num_memberships != 1", __func__));
3321168700Sbms		/*
3322168700Sbms		 * Our event handler is always called after protocol
3323168700Sbms		 * domains have been detached from the underlying ifnet.
3324168700Sbms		 * Do not call in_delmulti(); we held a single reference
3325168700Sbms		 * which the protocol domain has purged in in_purgemaddrs().
3326168700Sbms		 */
3327171168Smlaier		PF_UNLOCK();
3328168700Sbms		imo->imo_membership[--imo->imo_num_memberships] = NULL;
3329171168Smlaier		PF_LOCK();
3330167710Sbms		imo->imo_multicast_ifp = NULL;
3331167710Sbms	}
3332167710Sbms
3333167710Sbms	PF_UNLOCK();
3334223637Sbz
3335223637Sbz	CURVNET_RESTORE();
3336167710Sbms}
3337167710Sbms
3338223637Sbzstatic int
3339223637Sbzvnet_pfsync_init(const void *unused)
3340147261Smlaier{
3341223637Sbz	int error = 0;
3342126261Smlaier
3343223637Sbz	pfsyncattach(0);
3344223637Sbz
3345223637Sbz	error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif,
3346223637Sbz		SWI_NET, INTR_MPSAFE, &pfsync_swi.pfsync_swi_cookie);
3347223637Sbz	if (error)
3348223637Sbz		panic("%s: swi_add %d", __func__, error);
3349223637Sbz
3350223637Sbz	pfsync_state_import_ptr = pfsync_state_import;
3351223637Sbz	pfsync_up_ptr = pfsync_up;
3352223637Sbz	pfsync_insert_state_ptr = pfsync_insert_state;
3353223637Sbz	pfsync_update_state_ptr = pfsync_update_state;
3354223637Sbz	pfsync_delete_state_ptr = pfsync_delete_state;
3355223637Sbz	pfsync_clear_states_ptr = pfsync_clear_states;
3356223637Sbz	pfsync_state_in_use_ptr = pfsync_state_in_use;
3357223637Sbz	pfsync_defer_ptr = pfsync_defer;
3358223637Sbz
3359223637Sbz	return (0);
3360147261Smlaier}
3361147261Smlaier
3362126261Smlaierstatic int
3363223637Sbzvnet_pfsync_uninit(const void *unused)
3364223637Sbz{
3365223637Sbz
3366223637Sbz	swi_remove(pfsync_swi.pfsync_swi_cookie);
3367223637Sbz
3368223637Sbz	pfsync_state_import_ptr = NULL;
3369223637Sbz	pfsync_up_ptr = NULL;
3370223637Sbz	pfsync_insert_state_ptr = NULL;
3371223637Sbz	pfsync_update_state_ptr = NULL;
3372223637Sbz	pfsync_delete_state_ptr = NULL;
3373223637Sbz	pfsync_clear_states_ptr = NULL;
3374223637Sbz	pfsync_state_in_use_ptr = NULL;
3375223637Sbz	pfsync_defer_ptr = NULL;
3376223637Sbz
3377223637Sbz	if_clone_detach(&pfsync_cloner);
3378223637Sbz
3379223637Sbz	return (0);
3380223637Sbz}
3381223637Sbz
3382223637Sbz/* Define startup order. */
3383223637Sbz#define	PFSYNC_SYSINIT_ORDER	SI_SUB_PROTO_BEGIN
3384223637Sbz#define	PFSYNC_MODEVENT_ORDER	(SI_ORDER_FIRST) /* On boot slot in here. */
3385223637Sbz#define	PFSYNC_VNET_ORDER	(PFSYNC_MODEVENT_ORDER + 2) /* Later still. */
3386223637Sbz
3387223637Sbz/*
3388223637Sbz * Starting up.
3389223637Sbz * VNET_SYSINIT is called for each existing vnet and each new vnet.
3390223637Sbz */
3391223637SbzVNET_SYSINIT(vnet_pfsync_init, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER,
3392223637Sbz    vnet_pfsync_init, NULL);
3393223637Sbz
3394223637Sbz/*
3395223637Sbz * Closing up shop. These are done in REVERSE ORDER,
3396223637Sbz * Not called on reboot.
3397223637Sbz * VNET_SYSUNINIT is called for each exiting vnet as it exits.
3398223637Sbz */
3399223637SbzVNET_SYSUNINIT(vnet_pfsync_uninit, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER,
3400223637Sbz    vnet_pfsync_uninit, NULL);
3401223637Sbzstatic int
3402126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
3403126261Smlaier{
3404126261Smlaier	int error = 0;
3405126261Smlaier
3406126261Smlaier	switch (type) {
3407126261Smlaier	case MOD_LOAD:
3408223637Sbz#ifndef __FreeBSD__
3409171168Smlaier		pfsyncattach(0);
3410223637Sbz#endif
3411126261Smlaier		break;
3412126261Smlaier	case MOD_UNLOAD:
3413223637Sbz#ifndef __FreeBSD__
3414126261Smlaier		if_clone_detach(&pfsync_cloner);
3415223637Sbz#endif
3416126261Smlaier		break;
3417126261Smlaier	default:
3418126261Smlaier		error = EINVAL;
3419126261Smlaier		break;
3420126261Smlaier	}
3421126261Smlaier
3422126261Smlaier	return error;
3423126261Smlaier}
3424126261Smlaier
3425126261Smlaierstatic moduledata_t pfsync_mod = {
3426126261Smlaier	"pfsync",
3427126261Smlaier	pfsync_modevent,
3428126261Smlaier	0
3429126261Smlaier};
3430126261Smlaier
3431126261Smlaier#define PFSYNC_MODVER 1
3432126261Smlaier
3433135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
3434126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
3435223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER);
3436126261Smlaier#endif /* __FreeBSD__ */
3437