if_pfsync.c revision 148887
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 148887 2005-08-09 10:20:02Z rwatson $	*/
2145836Smlaier/*	$OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $	*/
3126258Smlaier
4126258Smlaier/*
5126258Smlaier * Copyright (c) 2002 Michael Shalayeff
6126258Smlaier * All rights reserved.
7126258Smlaier *
8126258Smlaier * Redistribution and use in source and binary forms, with or without
9126258Smlaier * modification, are permitted provided that the following conditions
10126258Smlaier * are met:
11126258Smlaier * 1. Redistributions of source code must retain the above copyright
12126258Smlaier *    notice, this list of conditions and the following disclaimer.
13126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright
14126258Smlaier *    notice, this list of conditions and the following disclaimer in the
15126258Smlaier *    documentation and/or other materials provided with the distribution.
16126258Smlaier *
17126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE.
28126258Smlaier */
29126258Smlaier
30127145Smlaier#ifdef __FreeBSD__
31126261Smlaier#include "opt_inet.h"
32126261Smlaier#include "opt_inet6.h"
33126261Smlaier#endif
34126261Smlaier
35127145Smlaier#ifndef __FreeBSD__
36126258Smlaier#include "bpfilter.h"
37126258Smlaier#include "pfsync.h"
38126261Smlaier#elif __FreeBSD__ >= 5
39126261Smlaier#include "opt_bpf.h"
40126261Smlaier#include "opt_pf.h"
41127145Smlaier#define	NBPFILTER	DEV_BPF
42127145Smlaier#define	NPFSYNC		DEV_PFSYNC
43126261Smlaier#endif
44126258Smlaier
45126258Smlaier#include <sys/param.h>
46130613Smlaier#include <sys/proc.h>
47126258Smlaier#include <sys/systm.h>
48126258Smlaier#include <sys/time.h>
49126258Smlaier#include <sys/mbuf.h>
50126258Smlaier#include <sys/socket.h>
51145836Smlaier#include <sys/kernel.h>
52127145Smlaier#ifdef __FreeBSD__
53145836Smlaier#include <sys/endian.h>
54126261Smlaier#include <sys/malloc.h>
55129907Smlaier#include <sys/module.h>
56126261Smlaier#include <sys/sockio.h>
57130613Smlaier#include <sys/lock.h>
58130613Smlaier#include <sys/mutex.h>
59148015Smlaier#include <sys/sysctl.h>
60126261Smlaier#else
61126258Smlaier#include <sys/ioctl.h>
62126258Smlaier#include <sys/timeout.h>
63126261Smlaier#endif
64126258Smlaier
65126258Smlaier#include <net/if.h>
66130933Sbrooks#if defined(__FreeBSD__)
67130933Sbrooks#include <net/if_clone.h>
68130933Sbrooks#endif
69126258Smlaier#include <net/if_types.h>
70126258Smlaier#include <net/route.h>
71126258Smlaier#include <net/bpf.h>
72145836Smlaier#include <netinet/tcp.h>
73145836Smlaier#include <netinet/tcp_seq.h>
74126258Smlaier
75126258Smlaier#ifdef	INET
76126258Smlaier#include <netinet/in.h>
77130613Smlaier#include <netinet/in_systm.h>
78126258Smlaier#include <netinet/in_var.h>
79130613Smlaier#include <netinet/ip.h>
80130613Smlaier#include <netinet/ip_var.h>
81126258Smlaier#endif
82126258Smlaier
83126258Smlaier#ifdef INET6
84126258Smlaier#ifndef INET
85126258Smlaier#include <netinet/in.h>
86126258Smlaier#endif
87126258Smlaier#include <netinet6/nd6.h>
88126258Smlaier#endif /* INET6 */
89126258Smlaier
90145836Smlaier#ifdef __FreeBSD__
91145836Smlaier#include "opt_carp.h"
92145836Smlaier#ifdef DEV_CARP
93145836Smlaier#define	NCARP	1
94145836Smlaier#endif
95145836Smlaier#else
96145836Smlaier#include "carp.h"
97145836Smlaier#endif
98145836Smlaier#if NCARP > 0
99145836Smlaierextern int carp_suppress_preempt;
100145836Smlaier#endif
101145836Smlaier
102126258Smlaier#include <net/pfvar.h>
103126258Smlaier#include <net/if_pfsync.h>
104126258Smlaier
105127145Smlaier#ifdef __FreeBSD__
106127145Smlaier#define	PFSYNCNAME	"pfsync"
107126261Smlaier#endif
108126261Smlaier
109126258Smlaier#define PFSYNC_MINMTU	\
110126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
111126258Smlaier
112126258Smlaier#ifdef PFSYNCDEBUG
113126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
114126258Smlaierint pfsyncdebug;
115126258Smlaier#else
116126258Smlaier#define DPRINTF(x)
117126258Smlaier#endif
118126258Smlaier
119127145Smlaier#ifndef __FreeBSD__
120130613Smlaierstruct pfsync_softc	pfsyncif;
121126261Smlaier#endif
122130613Smlaierstruct pfsyncstats	pfsyncstats;
123127145Smlaier#ifdef __FreeBSD__
124148015SmlaierSYSCTL_DECL(_net_inet_pfsync);
125148015SmlaierSYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
126148015Smlaier    &pfsyncstats, pfsyncstats,
127148015Smlaier    "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
128130613Smlaier
129130613Smlaier/*
130130613Smlaier * Locking notes:
131130613Smlaier * Whenever we really touch/look at the state table we have to hold the
132130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per
133130613Smlaier * softc lock instead.
134130613Smlaier *
135130613Smlaier */
136130613Smlaier
137128209Sbrooksstatic void	pfsync_clone_destroy(struct ifnet *);
138128209Sbrooksstatic int	pfsync_clone_create(struct if_clone *, int);
139147261Smlaierstatic void	pfsync_senddef(void *);
140126261Smlaier#else
141126258Smlaiervoid	pfsyncattach(int);
142126261Smlaier#endif
143130613Smlaiervoid	pfsync_setmtu(struct pfsync_softc *, int);
144130613Smlaierint	pfsync_insert_net_state(struct pfsync_state *);
145126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
146130613Smlaier	    struct rtentry *);
147126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
148126258Smlaiervoid	pfsyncstart(struct ifnet *);
149126258Smlaier
150130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
151130613Smlaierint	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
152130613Smlaierint	pfsync_sendout(struct pfsync_softc *);
153130613Smlaiervoid	pfsync_timeout(void *);
154130613Smlaiervoid	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
155130613Smlaiervoid	pfsync_bulk_update(void *);
156130613Smlaiervoid	pfsync_bulkfail(void *);
157126258Smlaier
158145836Smlaierint	pfsync_sync_ok;
159127145Smlaier#ifndef __FreeBSD__
160126258Smlaierextern int ifqmaxlen;
161130613Smlaierextern struct timeval time;
162130613Smlaierextern struct timeval mono_time;
163130613Smlaierextern int hz;
164126261Smlaier#endif
165126258Smlaier
166127145Smlaier#ifdef __FreeBSD__
167126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
168126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
169147256Sbrooks#define	SCP2IFP(sc)		((sc)->sc_ifp)
170130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1);
171126261Smlaier
172128209Sbrooksstatic void
173126261Smlaierpfsync_clone_destroy(struct ifnet *ifp)
174126261Smlaier{
175126261Smlaier        struct pfsync_softc *sc;
176126261Smlaier
177130613Smlaier	sc = ifp->if_softc;
178126261Smlaier	callout_stop(&sc->sc_tmo);
179130613Smlaier	callout_stop(&sc->sc_bulk_tmo);
180130613Smlaier	callout_stop(&sc->sc_bulkfail_tmo);
181126261Smlaier
182147261Smlaier	callout_stop(&sc->sc_send_tmo);
183147261Smlaier
184126261Smlaier#if NBPFILTER > 0
185126261Smlaier        bpfdetach(ifp);
186126261Smlaier#endif
187126261Smlaier        if_detach(ifp);
188147256Sbrooks	if_free(ifp);
189126261Smlaier        LIST_REMOVE(sc, sc_next);
190126261Smlaier        free(sc, M_PFSYNC);
191126261Smlaier}
192126261Smlaier
193128209Sbrooksstatic int
194126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
195126261Smlaier{
196126261Smlaier	struct pfsync_softc *sc;
197130613Smlaier	struct ifnet *ifp;
198126261Smlaier
199126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
200130613Smlaier	    M_WAITOK|M_ZERO);
201147256Sbrooks	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
202147256Sbrooks	if (ifp == NULL) {
203147256Sbrooks		free(sc, M_PFSYNC);
204147256Sbrooks		return (ENOSPC);
205147256Sbrooks	}
206126261Smlaier
207130613Smlaier	pfsync_sync_ok = 1;
208130613Smlaier	sc->sc_mbuf = NULL;
209130613Smlaier	sc->sc_mbuf_net = NULL;
210130613Smlaier	sc->sc_statep.s = NULL;
211130613Smlaier	sc->sc_statep_net.s = NULL;
212130613Smlaier	sc->sc_maxupdates = 128;
213130613Smlaier	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
214130613Smlaier	sc->sc_ureq_received = 0;
215130613Smlaier	sc->sc_ureq_sent = 0;
216130613Smlaier
217141584Smlaier	ifp = SCP2IFP(sc);
218130613Smlaier	if_initname(ifp, ifc->ifc_name, unit);
219130613Smlaier	ifp->if_ioctl = pfsyncioctl;
220130613Smlaier	ifp->if_output = pfsyncoutput;
221130613Smlaier	ifp->if_start = pfsyncstart;
222130613Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
223130613Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
224130613Smlaier	ifp->if_baudrate = IF_Mbps(100);
225130613Smlaier	ifp->if_softc = sc;
226126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
227147321Smlaier	callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
228147321Smlaier	callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
229147321Smlaier	callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
230147321Smlaier	callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
231147614Smlaier	sc->sc_ifq.ifq_maxlen = ifqmaxlen;
232147261Smlaier	mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
233147261Smlaier	    MTX_DEF);
234141584Smlaier	if_attach(ifp);
235126261Smlaier
236126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
237126261Smlaier#if NBPFILTER > 0
238141584Smlaier	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
239126261Smlaier#endif
240126261Smlaier
241126261Smlaier	return (0);
242126261Smlaier}
243126261Smlaier#else /* !__FreeBSD__ */
244126261Smlaiervoid
245126258Smlaierpfsyncattach(int npfsync)
246126258Smlaier{
247126258Smlaier	struct ifnet *ifp;
248126258Smlaier
249130613Smlaier	pfsync_sync_ok = 1;
250130613Smlaier	bzero(&pfsyncif, sizeof(pfsyncif));
251126258Smlaier	pfsyncif.sc_mbuf = NULL;
252130613Smlaier	pfsyncif.sc_mbuf_net = NULL;
253130613Smlaier	pfsyncif.sc_statep.s = NULL;
254130613Smlaier	pfsyncif.sc_statep_net.s = NULL;
255130613Smlaier	pfsyncif.sc_maxupdates = 128;
256145836Smlaier	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
257130613Smlaier	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
258130613Smlaier	pfsyncif.sc_ureq_received = 0;
259130613Smlaier	pfsyncif.sc_ureq_sent = 0;
260126258Smlaier	ifp = &pfsyncif.sc_if;
261126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
262126258Smlaier	ifp->if_softc = &pfsyncif;
263126258Smlaier	ifp->if_ioctl = pfsyncioctl;
264126258Smlaier	ifp->if_output = pfsyncoutput;
265126258Smlaier	ifp->if_start = pfsyncstart;
266126258Smlaier	ifp->if_type = IFT_PFSYNC;
267126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
268126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
269126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
270126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
271130613Smlaier	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
272130613Smlaier	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
273126258Smlaier	if_attach(ifp);
274126258Smlaier	if_alloc_sadl(ifp);
275126258Smlaier
276126258Smlaier#if NBPFILTER > 0
277126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
278126258Smlaier#endif
279126258Smlaier}
280126261Smlaier#endif
281126258Smlaier
282126258Smlaier/*
283126258Smlaier * Start output on the pfsync interface.
284126258Smlaier */
285126258Smlaiervoid
286126258Smlaierpfsyncstart(struct ifnet *ifp)
287126258Smlaier{
288130613Smlaier#ifdef __FreeBSD__
289130613Smlaier	IF_LOCK(&ifp->if_snd);
290130613Smlaier	_IF_DROP(&ifp->if_snd);
291130613Smlaier	_IF_DRAIN(&ifp->if_snd);
292130613Smlaier	IF_UNLOCK(&ifp->if_snd);
293130613Smlaier#else
294126258Smlaier	struct mbuf *m;
295126258Smlaier	int s;
296126258Smlaier
297126258Smlaier	for (;;) {
298126258Smlaier		s = splimp();
299126258Smlaier		IF_DROP(&ifp->if_snd);
300126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
301126258Smlaier		splx(s);
302126258Smlaier
303126258Smlaier		if (m == NULL)
304126258Smlaier			return;
305126258Smlaier		else
306126258Smlaier			m_freem(m);
307126258Smlaier	}
308130613Smlaier#endif
309126258Smlaier}
310126258Smlaier
311126258Smlaierint
312130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp)
313130613Smlaier{
314130613Smlaier	struct pf_state	*st = NULL;
315130613Smlaier	struct pf_rule *r = NULL;
316130613Smlaier	struct pfi_kif	*kif;
317130613Smlaier
318130613Smlaier#ifdef __FreeBSD__
319130613Smlaier	PF_ASSERT(MA_OWNED);
320130613Smlaier#endif
321130613Smlaier	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
322130613Smlaier		printf("pfsync_insert_net_state: invalid creator id:"
323130613Smlaier		    " %08x\n", ntohl(sp->creatorid));
324130613Smlaier		return (EINVAL);
325130613Smlaier	}
326130613Smlaier
327130613Smlaier	kif = pfi_lookup_create(sp->ifname);
328130613Smlaier	if (kif == NULL) {
329130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
330130613Smlaier			printf("pfsync_insert_net_state: "
331130613Smlaier			    "unknown interface: %s\n", sp->ifname);
332130613Smlaier		/* skip this state */
333130613Smlaier		return (0);
334130613Smlaier	}
335130613Smlaier
336130613Smlaier	/*
337130613Smlaier	 * Just use the default rule until we have infrastructure to find the
338130613Smlaier	 * best matching rule.
339130613Smlaier	 */
340130613Smlaier	r = &pf_default_rule;
341130613Smlaier
342130613Smlaier	if (!r->max_states || r->states < r->max_states)
343130613Smlaier		st = pool_get(&pf_state_pl, PR_NOWAIT);
344130613Smlaier	if (st == NULL) {
345130613Smlaier		pfi_maybe_destroy(kif);
346130613Smlaier		return (ENOMEM);
347130613Smlaier	}
348130613Smlaier	bzero(st, sizeof(*st));
349130613Smlaier
350130613Smlaier	st->rule.ptr = r;
351130613Smlaier	/* XXX get pointers to nat_rule and anchor */
352130613Smlaier
353145836Smlaier	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
354145836Smlaier	r->states++;
355145836Smlaier
356130613Smlaier	/* fill in the rest of the state entry */
357130613Smlaier	pf_state_host_ntoh(&sp->lan, &st->lan);
358130613Smlaier	pf_state_host_ntoh(&sp->gwy, &st->gwy);
359130613Smlaier	pf_state_host_ntoh(&sp->ext, &st->ext);
360130613Smlaier
361130613Smlaier	pf_state_peer_ntoh(&sp->src, &st->src);
362130613Smlaier	pf_state_peer_ntoh(&sp->dst, &st->dst);
363130613Smlaier
364130613Smlaier	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
365145836Smlaier	st->creation = time_second - ntohl(sp->creation);
366130613Smlaier	st->expire = ntohl(sp->expire) + time_second;
367130613Smlaier
368130613Smlaier	st->af = sp->af;
369130613Smlaier	st->proto = sp->proto;
370130613Smlaier	st->direction = sp->direction;
371130613Smlaier	st->log = sp->log;
372130613Smlaier	st->timeout = sp->timeout;
373130613Smlaier	st->allow_opts = sp->allow_opts;
374130613Smlaier
375130613Smlaier	bcopy(sp->id, &st->id, sizeof(st->id));
376130613Smlaier	st->creatorid = sp->creatorid;
377145836Smlaier	st->sync_flags = PFSTATE_FROMSYNC;
378130613Smlaier
379130613Smlaier
380130613Smlaier	if (pf_insert_state(kif, st)) {
381130613Smlaier		pfi_maybe_destroy(kif);
382145836Smlaier		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
383145836Smlaier		r->states--;
384130613Smlaier		pool_put(&pf_state_pl, st);
385130613Smlaier		return (EINVAL);
386130613Smlaier	}
387130613Smlaier
388130613Smlaier	return (0);
389130613Smlaier}
390130613Smlaier
391130613Smlaiervoid
392130613Smlaier#ifdef __FreeBSD__
393130613Smlaierpfsync_input(struct mbuf *m, __unused int off)
394130613Smlaier#else
395130613Smlaierpfsync_input(struct mbuf *m, ...)
396130613Smlaier#endif
397130613Smlaier{
398130613Smlaier	struct ip *ip = mtod(m, struct ip *);
399130613Smlaier	struct pfsync_header *ph;
400130613Smlaier#ifdef __FreeBSD__
401130613Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
402130613Smlaier#else
403130613Smlaier	struct pfsync_softc *sc = &pfsyncif;
404130613Smlaier#endif
405130613Smlaier	struct pf_state *st, key;
406130613Smlaier	struct pfsync_state *sp;
407130613Smlaier	struct pfsync_state_upd *up;
408130613Smlaier	struct pfsync_state_del *dp;
409130613Smlaier	struct pfsync_state_clr *cp;
410130613Smlaier	struct pfsync_state_upd_req *rup;
411130613Smlaier	struct pfsync_state_bus *bus;
412130613Smlaier	struct in_addr src;
413130613Smlaier	struct mbuf *mp;
414145836Smlaier	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
415130613Smlaier
416130613Smlaier	pfsyncstats.pfsyncs_ipackets++;
417130613Smlaier
418130613Smlaier	/* verify that we have a sync interface configured */
419130613Smlaier	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
420130613Smlaier		goto done;
421130613Smlaier
422130613Smlaier	/* verify that the packet came in on the right interface */
423130613Smlaier	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
424130613Smlaier		pfsyncstats.pfsyncs_badif++;
425130613Smlaier		goto done;
426130613Smlaier	}
427130613Smlaier
428130613Smlaier	/* verify that the IP TTL is 255.  */
429130613Smlaier	if (ip->ip_ttl != PFSYNC_DFLTTL) {
430130613Smlaier		pfsyncstats.pfsyncs_badttl++;
431130613Smlaier		goto done;
432130613Smlaier	}
433130613Smlaier
434130613Smlaier	iplen = ip->ip_hl << 2;
435130613Smlaier
436130613Smlaier	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
437130613Smlaier		pfsyncstats.pfsyncs_hdrops++;
438130613Smlaier		goto done;
439130613Smlaier	}
440130613Smlaier
441130613Smlaier	if (iplen + sizeof(*ph) > m->m_len) {
442130613Smlaier		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
443130613Smlaier			pfsyncstats.pfsyncs_hdrops++;
444130613Smlaier			goto done;
445130613Smlaier		}
446130613Smlaier		ip = mtod(m, struct ip *);
447130613Smlaier	}
448130613Smlaier	ph = (struct pfsync_header *)((char *)ip + iplen);
449130613Smlaier
450130613Smlaier	/* verify the version */
451130613Smlaier	if (ph->version != PFSYNC_VERSION) {
452130613Smlaier		pfsyncstats.pfsyncs_badver++;
453130613Smlaier		goto done;
454130613Smlaier	}
455130613Smlaier
456130613Smlaier	action = ph->action;
457130613Smlaier	count = ph->count;
458130613Smlaier
459130613Smlaier	/* make sure it's a valid action code */
460130613Smlaier	if (action >= PFSYNC_ACT_MAX) {
461130613Smlaier		pfsyncstats.pfsyncs_badact++;
462130613Smlaier		goto done;
463130613Smlaier	}
464130613Smlaier
465130613Smlaier	/* Cheaper to grab this now than having to mess with mbufs later */
466130613Smlaier	src = ip->ip_src;
467130613Smlaier
468130613Smlaier	switch (action) {
469130613Smlaier	case PFSYNC_ACT_CLR: {
470145836Smlaier		struct pf_state *nexts;
471130613Smlaier		struct pfi_kif	*kif;
472130613Smlaier		u_int32_t creatorid;
473130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
474130613Smlaier		    sizeof(*cp), &offp)) == NULL) {
475130613Smlaier			pfsyncstats.pfsyncs_badlen++;
476130613Smlaier			return;
477130613Smlaier		}
478130613Smlaier		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
479130613Smlaier		creatorid = cp->creatorid;
480130613Smlaier
481130613Smlaier		s = splsoftnet();
482130613Smlaier#ifdef __FreeBSD__
483130613Smlaier		PF_LOCK();
484130613Smlaier#endif
485130613Smlaier		if (cp->ifname[0] == '\0') {
486145836Smlaier			for (st = RB_MIN(pf_state_tree_id, &tree_id);
487145836Smlaier			    st; st = nexts) {
488145836Smlaier                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
489145836Smlaier				if (st->creatorid == creatorid) {
490130613Smlaier					st->timeout = PFTM_PURGE;
491145836Smlaier					pf_purge_expired_state(st);
492145836Smlaier				}
493130613Smlaier			}
494130613Smlaier		} else {
495130613Smlaier			kif = pfi_lookup_if(cp->ifname);
496130613Smlaier			if (kif == NULL) {
497130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
498130613Smlaier					printf("pfsync_input: PFSYNC_ACT_CLR "
499130613Smlaier					    "bad interface: %s\n", cp->ifname);
500130613Smlaier				splx(s);
501130613Smlaier#ifdef __FreeBSD__
502130613Smlaier				PF_UNLOCK();
503130613Smlaier#endif
504130613Smlaier				goto done;
505130613Smlaier			}
506145836Smlaier			for (st = RB_MIN(pf_state_tree_lan_ext,
507145836Smlaier			    &kif->pfik_lan_ext); st; st = nexts) {
508145836Smlaier				nexts = RB_NEXT(pf_state_tree_lan_ext,
509145836Smlaier				    &kif->pfik_lan_ext, st);
510145836Smlaier				if (st->creatorid == creatorid) {
511130613Smlaier					st->timeout = PFTM_PURGE;
512145836Smlaier					pf_purge_expired_state(st);
513145836Smlaier				}
514130613Smlaier			}
515130613Smlaier		}
516130613Smlaier#ifdef __FreeBSD__
517130613Smlaier		PF_UNLOCK();
518130613Smlaier#endif
519130613Smlaier		splx(s);
520130613Smlaier
521130613Smlaier		break;
522130613Smlaier	}
523130613Smlaier	case PFSYNC_ACT_INS:
524130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
525130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
526130613Smlaier			pfsyncstats.pfsyncs_badlen++;
527130613Smlaier			return;
528130613Smlaier		}
529130613Smlaier
530130613Smlaier		s = splsoftnet();
531130613Smlaier#ifdef __FreeBSD__
532130613Smlaier		PF_LOCK();
533130613Smlaier#endif
534130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
535130613Smlaier		    i < count; i++, sp++) {
536130613Smlaier			/* check for invalid values */
537130613Smlaier			if (sp->timeout >= PFTM_MAX ||
538130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
539130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST ||
540130613Smlaier			    sp->direction > PF_OUT ||
541130613Smlaier			    (sp->af != AF_INET && sp->af != AF_INET6)) {
542130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
543130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_INS: "
544130613Smlaier					    "invalid value\n");
545130613Smlaier				pfsyncstats.pfsyncs_badstate++;
546130613Smlaier				continue;
547130613Smlaier			}
548130613Smlaier
549130613Smlaier			if ((error = pfsync_insert_net_state(sp))) {
550130613Smlaier				if (error == ENOMEM) {
551130613Smlaier					splx(s);
552130613Smlaier#ifdef __FreeBSD__
553130613Smlaier					PF_UNLOCK();
554130613Smlaier#endif
555130613Smlaier					goto done;
556130613Smlaier				}
557130613Smlaier				continue;
558130613Smlaier			}
559130613Smlaier		}
560130613Smlaier#ifdef __FreeBSD__
561130613Smlaier		PF_UNLOCK();
562130613Smlaier#endif
563130613Smlaier		splx(s);
564130613Smlaier		break;
565130613Smlaier	case PFSYNC_ACT_UPD:
566130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
567130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
568130613Smlaier			pfsyncstats.pfsyncs_badlen++;
569130613Smlaier			return;
570130613Smlaier		}
571130613Smlaier
572130613Smlaier		s = splsoftnet();
573130613Smlaier#ifdef __FreeBSD__
574130613Smlaier		PF_LOCK();
575130613Smlaier#endif
576130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
577130613Smlaier		    i < count; i++, sp++) {
578145836Smlaier			int flags = PFSYNC_FLAG_STALE;
579145836Smlaier
580130613Smlaier			/* check for invalid values */
581130613Smlaier			if (sp->timeout >= PFTM_MAX ||
582130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
583130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST) {
584130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
585130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_UPD: "
586130613Smlaier					    "invalid value\n");
587130613Smlaier				pfsyncstats.pfsyncs_badstate++;
588130613Smlaier				continue;
589130613Smlaier			}
590130613Smlaier
591130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
592130613Smlaier			key.creatorid = sp->creatorid;
593130613Smlaier
594130613Smlaier			st = pf_find_state_byid(&key);
595130613Smlaier			if (st == NULL) {
596130613Smlaier				/* insert the update */
597130613Smlaier				if (pfsync_insert_net_state(sp))
598130613Smlaier					pfsyncstats.pfsyncs_badstate++;
599130613Smlaier				continue;
600130613Smlaier			}
601145836Smlaier			sfail = 0;
602145836Smlaier			if (st->proto == IPPROTO_TCP) {
603145836Smlaier				/*
604145836Smlaier				 * The state should never go backwards except
605145836Smlaier				 * for syn-proxy states.  Neither should the
606145836Smlaier				 * sequence window slide backwards.
607145836Smlaier				 */
608145836Smlaier				if (st->src.state > sp->src.state &&
609145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
610145836Smlaier				    sp->src.state >= PF_TCPS_PROXY_SRC))
611145836Smlaier					sfail = 1;
612145836Smlaier				else if (SEQ_GT(st->src.seqlo,
613145836Smlaier				    ntohl(sp->src.seqlo)))
614145836Smlaier					sfail = 3;
615145836Smlaier				else if (st->dst.state > sp->dst.state) {
616145836Smlaier					/* There might still be useful
617145836Smlaier					 * information about the src state here,
618145836Smlaier					 * so import that part of the update,
619145836Smlaier					 * then "fail" so we send the updated
620145836Smlaier					 * state back to the peer who is missing
621145836Smlaier					 * our what we know. */
622145836Smlaier					pf_state_peer_ntoh(&sp->src, &st->src);
623145836Smlaier					/* XXX do anything with timeouts? */
624145836Smlaier					sfail = 7;
625145836Smlaier					flags = 0;
626145836Smlaier				} else if (st->dst.state >= TCPS_SYN_SENT &&
627145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
628145836Smlaier					sfail = 4;
629145836Smlaier			} else {
630145836Smlaier				/*
631145836Smlaier				 * Non-TCP protocol state machine always go
632145836Smlaier				 * forwards
633145836Smlaier				 */
634145836Smlaier				if (st->src.state > sp->src.state)
635145836Smlaier					sfail = 5;
636145836Smlaier				else if ( st->dst.state > sp->dst.state)
637145836Smlaier					sfail = 6;
638145836Smlaier			}
639145836Smlaier			if (sfail) {
640145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
641145836Smlaier					printf("pfsync: %s stale update "
642145836Smlaier					    "(%d) id: %016llx "
643145836Smlaier					    "creatorid: %08x\n",
644145836Smlaier					    (sfail < 7 ?  "ignoring"
645145836Smlaier					     : "partial"), sfail,
646145836Smlaier#ifdef __FreeBSD__
647145836Smlaier					    (unsigned long long)be64toh(st->id),
648145836Smlaier#else
649145836Smlaier					    betoh64(st->id),
650145836Smlaier#endif
651145836Smlaier					    ntohl(st->creatorid));
652145836Smlaier				pfsyncstats.pfsyncs_badstate++;
653145836Smlaier
654145836Smlaier				if (!(sp->sync_flags & PFSTATE_STALE)) {
655145836Smlaier					/* we have a better state, send it */
656145836Smlaier					if (sc->sc_mbuf != NULL && !stale)
657145836Smlaier						pfsync_sendout(sc);
658145836Smlaier					stale++;
659145836Smlaier					if (!st->sync_flags)
660145836Smlaier						pfsync_pack_state(
661145836Smlaier						    PFSYNC_ACT_UPD, st, flags);
662145836Smlaier				}
663145836Smlaier				continue;
664145836Smlaier			}
665130613Smlaier			pf_state_peer_ntoh(&sp->src, &st->src);
666130613Smlaier			pf_state_peer_ntoh(&sp->dst, &st->dst);
667130613Smlaier			st->expire = ntohl(sp->expire) + time_second;
668130613Smlaier			st->timeout = sp->timeout;
669130613Smlaier		}
670145836Smlaier		if (stale && sc->sc_mbuf != NULL)
671145836Smlaier			pfsync_sendout(sc);
672130613Smlaier#ifdef __FreeBSD__
673130613Smlaier		PF_UNLOCK();
674130613Smlaier#endif
675130613Smlaier		splx(s);
676130613Smlaier		break;
677130613Smlaier	/*
678130613Smlaier	 * It's not strictly necessary for us to support the "uncompressed"
679130613Smlaier	 * delete action, but it's relatively simple and maintains consistency.
680130613Smlaier	 */
681130613Smlaier	case PFSYNC_ACT_DEL:
682130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
683130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
684130613Smlaier			pfsyncstats.pfsyncs_badlen++;
685130613Smlaier			return;
686130613Smlaier		}
687130613Smlaier
688130613Smlaier		s = splsoftnet();
689130613Smlaier#ifdef __FreeBSD__
690130613Smlaier		PF_LOCK();
691130613Smlaier#endif
692130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
693130613Smlaier		    i < count; i++, sp++) {
694130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
695130613Smlaier			key.creatorid = sp->creatorid;
696130613Smlaier
697130613Smlaier			st = pf_find_state_byid(&key);
698130613Smlaier			if (st == NULL) {
699130613Smlaier				pfsyncstats.pfsyncs_badstate++;
700130613Smlaier				continue;
701130613Smlaier			}
702130613Smlaier			st->timeout = PFTM_PURGE;
703130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
704145836Smlaier			pf_purge_expired_state(st);
705130613Smlaier		}
706130613Smlaier#ifdef __FreeBSD__
707130613Smlaier		PF_UNLOCK();
708130613Smlaier#endif
709130613Smlaier		splx(s);
710130613Smlaier		break;
711130613Smlaier	case PFSYNC_ACT_UPD_C: {
712130613Smlaier		int update_requested = 0;
713130613Smlaier
714130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
715130613Smlaier		    count * sizeof(*up), &offp)) == NULL) {
716130613Smlaier			pfsyncstats.pfsyncs_badlen++;
717130613Smlaier			return;
718130613Smlaier		}
719130613Smlaier
720130613Smlaier		s = splsoftnet();
721130613Smlaier#ifdef __FreeBSD__
722130613Smlaier		PF_LOCK();
723130613Smlaier#endif
724130613Smlaier		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
725130613Smlaier		    i < count; i++, up++) {
726130613Smlaier			/* check for invalid values */
727130613Smlaier			if (up->timeout >= PFTM_MAX ||
728130613Smlaier			    up->src.state > PF_TCPS_PROXY_DST ||
729130613Smlaier			    up->dst.state > PF_TCPS_PROXY_DST) {
730130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
731130613Smlaier					printf("pfsync_insert: "
732130613Smlaier					    "PFSYNC_ACT_UPD_C: "
733130613Smlaier					    "invalid value\n");
734130613Smlaier				pfsyncstats.pfsyncs_badstate++;
735130613Smlaier				continue;
736130613Smlaier			}
737130613Smlaier
738130613Smlaier			bcopy(up->id, &key.id, sizeof(key.id));
739130613Smlaier			key.creatorid = up->creatorid;
740130613Smlaier
741130613Smlaier			st = pf_find_state_byid(&key);
742130613Smlaier			if (st == NULL) {
743130613Smlaier				/* We don't have this state. Ask for it. */
744145836Smlaier				error = pfsync_request_update(up, &src);
745145836Smlaier				if (error == ENOMEM) {
746145836Smlaier					splx(s);
747145836Smlaier					goto done;
748145836Smlaier				}
749130613Smlaier				update_requested = 1;
750130613Smlaier				pfsyncstats.pfsyncs_badstate++;
751130613Smlaier				continue;
752130613Smlaier			}
753145836Smlaier			sfail = 0;
754145836Smlaier			if (st->proto == IPPROTO_TCP) {
755145836Smlaier				/*
756145836Smlaier				 * The state should never go backwards except
757145836Smlaier				 * for syn-proxy states.  Neither should the
758145836Smlaier				 * sequence window slide backwards.
759145836Smlaier				 */
760145836Smlaier				if (st->src.state > up->src.state &&
761145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
762145836Smlaier				    up->src.state >= PF_TCPS_PROXY_SRC))
763145836Smlaier					sfail = 1;
764145836Smlaier				else if (st->dst.state > up->dst.state)
765145836Smlaier					sfail = 2;
766145836Smlaier				else if (SEQ_GT(st->src.seqlo,
767145836Smlaier				    ntohl(up->src.seqlo)))
768145836Smlaier					sfail = 3;
769145836Smlaier				else if (st->dst.state >= TCPS_SYN_SENT &&
770145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
771145836Smlaier					sfail = 4;
772145836Smlaier			} else {
773145836Smlaier				/*
774145836Smlaier				 * Non-TCP protocol state machine always go
775145836Smlaier				 * forwards
776145836Smlaier				 */
777145836Smlaier				if (st->src.state > up->src.state)
778145836Smlaier					sfail = 5;
779145836Smlaier				else if (st->dst.state > up->dst.state)
780145836Smlaier					sfail = 6;
781145836Smlaier			}
782145836Smlaier			if (sfail) {
783145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
784145836Smlaier					printf("pfsync: ignoring stale update "
785145836Smlaier					    "(%d) id: %016llx "
786145836Smlaier					    "creatorid: %08x\n", sfail,
787145836Smlaier#ifdef __FreeBSD__
788145836Smlaier					    (unsigned long long)be64toh(st->id),
789145836Smlaier#else
790145836Smlaier					    betoh64(st->id),
791145836Smlaier#endif
792145836Smlaier					    ntohl(st->creatorid));
793145836Smlaier				pfsyncstats.pfsyncs_badstate++;
794145836Smlaier
795145836Smlaier				/* we have a better state, send it out */
796145836Smlaier				if ((!stale || update_requested) &&
797145836Smlaier				    sc->sc_mbuf != NULL) {
798145836Smlaier					pfsync_sendout(sc);
799145836Smlaier					update_requested = 0;
800145836Smlaier				}
801145836Smlaier				stale++;
802145836Smlaier				if (!st->sync_flags)
803145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD, st,
804145836Smlaier					    PFSYNC_FLAG_STALE);
805145836Smlaier				continue;
806145836Smlaier			}
807130613Smlaier			pf_state_peer_ntoh(&up->src, &st->src);
808130613Smlaier			pf_state_peer_ntoh(&up->dst, &st->dst);
809130613Smlaier			st->expire = ntohl(up->expire) + time_second;
810130613Smlaier			st->timeout = up->timeout;
811130613Smlaier		}
812145836Smlaier		if ((update_requested || stale) && sc->sc_mbuf)
813130613Smlaier			pfsync_sendout(sc);
814130613Smlaier#ifdef __FreeBSD__
815130613Smlaier		PF_UNLOCK();
816130613Smlaier#endif
817130613Smlaier		splx(s);
818130613Smlaier		break;
819130613Smlaier	}
820130613Smlaier	case PFSYNC_ACT_DEL_C:
821130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
822130613Smlaier		    count * sizeof(*dp), &offp)) == NULL) {
823130613Smlaier			pfsyncstats.pfsyncs_badlen++;
824130613Smlaier			return;
825130613Smlaier		}
826130613Smlaier
827130613Smlaier		s = splsoftnet();
828130613Smlaier#ifdef __FreeBSD__
829130613Smlaier		PF_LOCK();
830130613Smlaier#endif
831130613Smlaier		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
832130613Smlaier		    i < count; i++, dp++) {
833130613Smlaier			bcopy(dp->id, &key.id, sizeof(key.id));
834130613Smlaier			key.creatorid = dp->creatorid;
835130613Smlaier
836130613Smlaier			st = pf_find_state_byid(&key);
837130613Smlaier			if (st == NULL) {
838130613Smlaier				pfsyncstats.pfsyncs_badstate++;
839130613Smlaier				continue;
840130613Smlaier			}
841130613Smlaier			st->timeout = PFTM_PURGE;
842130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
843145836Smlaier			pf_purge_expired_state(st);
844130613Smlaier		}
845130613Smlaier#ifdef __FreeBSD__
846130613Smlaier		PF_UNLOCK();
847130613Smlaier#endif
848130613Smlaier		splx(s);
849130613Smlaier		break;
850130613Smlaier	case PFSYNC_ACT_INS_F:
851130613Smlaier	case PFSYNC_ACT_DEL_F:
852130613Smlaier		/* not implemented */
853130613Smlaier		break;
854130613Smlaier	case PFSYNC_ACT_UREQ:
855130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
856130613Smlaier		    count * sizeof(*rup), &offp)) == NULL) {
857130613Smlaier			pfsyncstats.pfsyncs_badlen++;
858130613Smlaier			return;
859130613Smlaier		}
860130613Smlaier
861130613Smlaier		s = splsoftnet();
862130613Smlaier#ifdef __FreeBSD__
863130613Smlaier		PF_LOCK();
864130613Smlaier#endif
865130613Smlaier		if (sc->sc_mbuf != NULL)
866130613Smlaier			pfsync_sendout(sc);
867130613Smlaier		for (i = 0,
868130613Smlaier		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
869130613Smlaier		    i < count; i++, rup++) {
870130613Smlaier			bcopy(rup->id, &key.id, sizeof(key.id));
871130613Smlaier			key.creatorid = rup->creatorid;
872130613Smlaier
873130613Smlaier			if (key.id == 0 && key.creatorid == 0) {
874130613Smlaier				sc->sc_ureq_received = time_uptime;
875130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
876130613Smlaier					printf("pfsync: received "
877130613Smlaier					    "bulk update request\n");
878130613Smlaier				pfsync_send_bus(sc, PFSYNC_BUS_START);
879130613Smlaier#ifdef __FreeBSD__
880130613Smlaier				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
881130613Smlaier				    pfsync_bulk_update,
882130613Smlaier				    LIST_FIRST(&pfsync_list));
883130613Smlaier#else
884130613Smlaier				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
885130613Smlaier#endif
886130613Smlaier			} else {
887130613Smlaier				st = pf_find_state_byid(&key);
888130613Smlaier				if (st == NULL) {
889130613Smlaier					pfsyncstats.pfsyncs_badstate++;
890130613Smlaier					continue;
891130613Smlaier				}
892145836Smlaier				if (!st->sync_flags)
893145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD,
894145836Smlaier					    st, 0);
895130613Smlaier			}
896130613Smlaier		}
897130613Smlaier		if (sc->sc_mbuf != NULL)
898130613Smlaier			pfsync_sendout(sc);
899130613Smlaier#ifdef __FreeBSD__
900130613Smlaier		PF_UNLOCK();
901130613Smlaier#endif
902130613Smlaier		splx(s);
903130613Smlaier		break;
904130613Smlaier	case PFSYNC_ACT_BUS:
905130613Smlaier		/* If we're not waiting for a bulk update, who cares. */
906130613Smlaier		if (sc->sc_ureq_sent == 0)
907130613Smlaier			break;
908130613Smlaier
909130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
910130613Smlaier		    sizeof(*bus), &offp)) == NULL) {
911130613Smlaier			pfsyncstats.pfsyncs_badlen++;
912130613Smlaier			return;
913130613Smlaier		}
914130613Smlaier		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
915130613Smlaier		switch (bus->status) {
916130613Smlaier		case PFSYNC_BUS_START:
917130613Smlaier#ifdef __FreeBSD__
918130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo,
919130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
920130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
921130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
922130613Smlaier#else
923130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo,
924130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
925130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
926130613Smlaier#endif
927130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
928130613Smlaier				printf("pfsync: received bulk "
929130613Smlaier				    "update start\n");
930130613Smlaier			break;
931130613Smlaier		case PFSYNC_BUS_END:
932130613Smlaier			if (time_uptime - ntohl(bus->endtime) >=
933130613Smlaier			    sc->sc_ureq_sent) {
934130613Smlaier				/* that's it, we're happy */
935130613Smlaier				sc->sc_ureq_sent = 0;
936130613Smlaier				sc->sc_bulk_tries = 0;
937130613Smlaier#ifdef __FreeBSD__
938130613Smlaier				callout_stop(&sc->sc_bulkfail_tmo);
939130613Smlaier#else
940130613Smlaier				timeout_del(&sc->sc_bulkfail_tmo);
941130613Smlaier#endif
942145836Smlaier#if NCARP > 0	/* XXX_IMPORT */
943145836Smlaier				if (!pfsync_sync_ok)
944145836Smlaier					carp_suppress_preempt--;
945145836Smlaier#endif
946130613Smlaier				pfsync_sync_ok = 1;
947130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
948130613Smlaier					printf("pfsync: received valid "
949130613Smlaier					    "bulk update end\n");
950130613Smlaier			} else {
951130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
952130613Smlaier					printf("pfsync: received invalid "
953130613Smlaier					    "bulk update end: bad timestamp\n");
954130613Smlaier			}
955130613Smlaier			break;
956130613Smlaier		}
957130613Smlaier		break;
958130613Smlaier	}
959130613Smlaier
960130613Smlaierdone:
961130613Smlaier	if (m)
962130613Smlaier		m_freem(m);
963130613Smlaier}
964130613Smlaier
965130613Smlaierint
966126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
967126258Smlaier	struct rtentry *rt)
968126258Smlaier{
969126258Smlaier	m_freem(m);
970126258Smlaier	return (0);
971126258Smlaier}
972126258Smlaier
973126258Smlaier/* ARGSUSED */
974126258Smlaierint
975126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
976126258Smlaier{
977130613Smlaier#ifndef __FreeBSD__
978130613Smlaier	struct proc *p = curproc;
979130613Smlaier#endif
980126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
981126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
982130613Smlaier	struct ip_moptions *imo = &sc->sc_imo;
983130613Smlaier	struct pfsyncreq pfsyncr;
984130613Smlaier	struct ifnet    *sifp;
985130613Smlaier	int s, error;
986126258Smlaier
987126258Smlaier	switch (cmd) {
988126258Smlaier	case SIOCSIFADDR:
989126258Smlaier	case SIOCAIFADDR:
990126258Smlaier	case SIOCSIFDSTADDR:
991126258Smlaier	case SIOCSIFFLAGS:
992126258Smlaier		if (ifp->if_flags & IFF_UP)
993148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
994126258Smlaier		else
995148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
996126258Smlaier		break;
997126258Smlaier	case SIOCSIFMTU:
998126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
999126258Smlaier			return (EINVAL);
1000126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
1001126258Smlaier			ifr->ifr_mtu = MCLBYTES;
1002126258Smlaier		s = splnet();
1003130613Smlaier#ifdef __FreeBSD__
1004130613Smlaier		PF_LOCK();
1005130613Smlaier#endif
1006130613Smlaier		if (ifr->ifr_mtu < ifp->if_mtu) {
1007126258Smlaier			pfsync_sendout(sc);
1008130613Smlaier		}
1009126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
1010130613Smlaier#ifdef __FreeBSD__
1011130613Smlaier		PF_UNLOCK();
1012130613Smlaier#endif
1013126258Smlaier		splx(s);
1014126258Smlaier		break;
1015130613Smlaier	case SIOCGETPFSYNC:
1016130613Smlaier#ifdef __FreeBSD__
1017130613Smlaier		/* XXX: read unlocked */
1018130613Smlaier#endif
1019130613Smlaier		bzero(&pfsyncr, sizeof(pfsyncr));
1020130613Smlaier		if (sc->sc_sync_ifp)
1021145836Smlaier			strlcpy(pfsyncr.pfsyncr_syncdev,
1022130613Smlaier			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
1023145836Smlaier		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1024130613Smlaier		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1025130613Smlaier		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
1026130613Smlaier			return (error);
1027130613Smlaier		break;
1028130613Smlaier	case SIOCSETPFSYNC:
1029130613Smlaier#ifdef __FreeBSD__
1030130613Smlaier		if ((error = suser(curthread)) != 0)
1031130613Smlaier#else
1032130613Smlaier		if ((error = suser(p, p->p_acflag)) != 0)
1033130613Smlaier#endif
1034130613Smlaier			return (error);
1035130613Smlaier		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1036130613Smlaier			return (error);
1037130613Smlaier
1038145836Smlaier		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1039145836Smlaier			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1040145836Smlaier		else
1041145836Smlaier			sc->sc_sync_peer.s_addr =
1042145836Smlaier			    pfsyncr.pfsyncr_syncpeer.s_addr;
1043145836Smlaier
1044130613Smlaier		if (pfsyncr.pfsyncr_maxupdates > 255)
1045130613Smlaier			return (EINVAL);
1046130613Smlaier#ifdef __FreeBSD__
1047147261Smlaier		callout_drain(&sc->sc_send_tmo);
1048130613Smlaier		PF_LOCK();
1049130613Smlaier#endif
1050130613Smlaier		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1051130613Smlaier
1052145836Smlaier		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1053130613Smlaier			sc->sc_sync_ifp = NULL;
1054130613Smlaier			if (sc->sc_mbuf_net != NULL) {
1055130613Smlaier				/* Don't keep stale pfsync packets around. */
1056130613Smlaier				s = splnet();
1057130613Smlaier				m_freem(sc->sc_mbuf_net);
1058130613Smlaier				sc->sc_mbuf_net = NULL;
1059130613Smlaier				sc->sc_statep_net.s = NULL;
1060130613Smlaier				splx(s);
1061130613Smlaier			}
1062145836Smlaier			if (imo->imo_num_memberships > 0) {
1063145836Smlaier				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1064145836Smlaier				imo->imo_multicast_ifp = NULL;
1065145836Smlaier			}
1066130613Smlaier#ifdef __FreeBSD__
1067130613Smlaier			PF_UNLOCK();
1068130613Smlaier#endif
1069130613Smlaier			break;
1070130613Smlaier		}
1071145836Smlaier
1072145836Smlaier		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
1073130613Smlaier#ifdef __FreeBSD__
1074130613Smlaier			PF_UNLOCK();
1075130613Smlaier#endif
1076130613Smlaier			return (EINVAL);
1077130613Smlaier		}
1078130613Smlaier
1079130613Smlaier		s = splnet();
1080141584Smlaier#ifdef __FreeBSD__
1081141584Smlaier		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
1082141584Smlaier#else
1083130613Smlaier		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1084141584Smlaier#endif
1085130613Smlaier		    (sc->sc_sync_ifp != NULL &&
1086130613Smlaier		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
1087130613Smlaier		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1088130613Smlaier			pfsync_sendout(sc);
1089130613Smlaier		sc->sc_sync_ifp = sifp;
1090130613Smlaier
1091141584Smlaier#ifdef __FreeBSD__
1092141584Smlaier		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
1093141584Smlaier#else
1094130613Smlaier		pfsync_setmtu(sc, sc->sc_if.if_mtu);
1095141584Smlaier#endif
1096130613Smlaier
1097130613Smlaier		if (imo->imo_num_memberships > 0) {
1098130613Smlaier			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1099130613Smlaier			imo->imo_multicast_ifp = NULL;
1100130613Smlaier		}
1101130613Smlaier
1102145836Smlaier		if (sc->sc_sync_ifp &&
1103145836Smlaier		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1104130613Smlaier			struct in_addr addr;
1105130613Smlaier
1106145836Smlaier			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
1107145836Smlaier				sc->sc_sync_ifp = NULL;
1108130613Smlaier#ifdef __FreeBSD__
1109145836Smlaier				PF_UNLOCK();
1110145836Smlaier#endif
1111145836Smlaier				splx(s);
1112145836Smlaier				return (EADDRNOTAVAIL);
1113145836Smlaier			}
1114145836Smlaier#ifdef __FreeBSD__
1115130613Smlaier			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
1116130613Smlaier			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1117130613Smlaier#else
1118130613Smlaier			addr.s_addr = INADDR_PFSYNC_GROUP;
1119130613Smlaier#endif
1120145836Smlaier
1121130613Smlaier			if ((imo->imo_membership[0] =
1122130613Smlaier			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
1123145836Smlaier				sc->sc_sync_ifp = NULL;
1124130613Smlaier				splx(s);
1125130613Smlaier				return (ENOBUFS);
1126130613Smlaier			}
1127130613Smlaier			imo->imo_num_memberships++;
1128130613Smlaier			imo->imo_multicast_ifp = sc->sc_sync_ifp;
1129130613Smlaier			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1130130613Smlaier			imo->imo_multicast_loop = 0;
1131145836Smlaier		}
1132130613Smlaier
1133145836Smlaier		if (sc->sc_sync_ifp ||
1134145836Smlaier		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
1135130613Smlaier			/* Request a full state table update. */
1136130613Smlaier#ifdef __FreeBSD__
1137130613Smlaier			PF_LOCK();
1138145836Smlaier#endif
1139130613Smlaier			sc->sc_ureq_sent = time_uptime;
1140145836Smlaier#if NCARP > 0
1141145836Smlaier			if (pfsync_sync_ok)
1142145836Smlaier				carp_suppress_preempt++;
1143130613Smlaier#endif
1144130613Smlaier			pfsync_sync_ok = 0;
1145130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1146130613Smlaier				printf("pfsync: requesting bulk update\n");
1147130613Smlaier#ifdef __FreeBSD__
1148130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1149130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
1150130613Smlaier#else
1151130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1152130613Smlaier#endif
1153145836Smlaier			error = pfsync_request_update(NULL, NULL);
1154145836Smlaier			if (error == ENOMEM) {
1155145836Smlaier#ifdef __FreeBSD__
1156145836Smlaier				PF_UNLOCK();
1157145836Smlaier#endif
1158145836Smlaier				splx(s);
1159145836Smlaier				return (ENOMEM);
1160145836Smlaier			}
1161130613Smlaier			pfsync_sendout(sc);
1162130613Smlaier		}
1163130613Smlaier#ifdef __FreeBSD__
1164130613Smlaier		PF_UNLOCK();
1165130613Smlaier#endif
1166130613Smlaier		splx(s);
1167130613Smlaier
1168130613Smlaier		break;
1169130613Smlaier
1170126258Smlaier	default:
1171126258Smlaier		return (ENOTTY);
1172126258Smlaier	}
1173126258Smlaier
1174126258Smlaier	return (0);
1175126258Smlaier}
1176126258Smlaier
1177126258Smlaiervoid
1178130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1179130613Smlaier{
1180126258Smlaier	int mtu;
1181130613Smlaier
1182130613Smlaier	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1183130613Smlaier		mtu = sc->sc_sync_ifp->if_mtu;
1184130613Smlaier	else
1185130613Smlaier		mtu = mtu_req;
1186130613Smlaier
1187130613Smlaier	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1188130613Smlaier	    sizeof(struct pfsync_state);
1189130613Smlaier	if (sc->sc_maxcount > 254)
1190130613Smlaier	    sc->sc_maxcount = 254;
1191141584Smlaier#ifdef __FreeBSD__
1192141584Smlaier	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
1193141584Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1194141584Smlaier#else
1195126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1196130613Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1197141584Smlaier#endif
1198126258Smlaier}
1199126258Smlaier
1200126258Smlaierstruct mbuf *
1201130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1202126258Smlaier{
1203126258Smlaier	struct pfsync_header *h;
1204126258Smlaier	struct mbuf *m;
1205126258Smlaier	int len;
1206126258Smlaier
1207130613Smlaier#ifdef __FreeBSD__
1208130613Smlaier	PF_ASSERT(MA_OWNED);
1209130613Smlaier#endif
1210126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
1211126258Smlaier	if (m == NULL) {
1212141584Smlaier#ifdef __FreeBSD__
1213141584Smlaier		SCP2IFP(sc)->if_oerrors++;
1214141584Smlaier#else
1215126258Smlaier		sc->sc_if.if_oerrors++;
1216141584Smlaier#endif
1217126258Smlaier		return (NULL);
1218126258Smlaier	}
1219126258Smlaier
1220130613Smlaier	switch (action) {
1221130613Smlaier	case PFSYNC_ACT_CLR:
1222130613Smlaier		len = sizeof(struct pfsync_header) +
1223130613Smlaier		    sizeof(struct pfsync_state_clr);
1224130613Smlaier		break;
1225130613Smlaier	case PFSYNC_ACT_UPD_C:
1226130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1227130613Smlaier		    sizeof(struct pfsync_header);
1228130613Smlaier		break;
1229130613Smlaier	case PFSYNC_ACT_DEL_C:
1230130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1231130613Smlaier		    sizeof(struct pfsync_header);
1232130613Smlaier		break;
1233130613Smlaier	case PFSYNC_ACT_UREQ:
1234130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1235130613Smlaier		    sizeof(struct pfsync_header);
1236130613Smlaier		break;
1237130613Smlaier	case PFSYNC_ACT_BUS:
1238130613Smlaier		len = sizeof(struct pfsync_header) +
1239130613Smlaier		    sizeof(struct pfsync_state_bus);
1240130613Smlaier		break;
1241130613Smlaier	default:
1242130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1243130613Smlaier		    sizeof(struct pfsync_header);
1244130613Smlaier		break;
1245130613Smlaier	}
1246130613Smlaier
1247126258Smlaier	if (len > MHLEN) {
1248126258Smlaier		MCLGET(m, M_DONTWAIT);
1249126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
1250126258Smlaier			m_free(m);
1251141584Smlaier#ifdef __FreeBSD__
1252141584Smlaier			SCP2IFP(sc)->if_oerrors++;
1253141584Smlaier#else
1254126258Smlaier			sc->sc_if.if_oerrors++;
1255141584Smlaier#endif
1256126258Smlaier			return (NULL);
1257126258Smlaier		}
1258130613Smlaier		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1259130613Smlaier	} else
1260130613Smlaier		MH_ALIGN(m, len);
1261130613Smlaier
1262126258Smlaier	m->m_pkthdr.rcvif = NULL;
1263130613Smlaier	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1264126258Smlaier	h = mtod(m, struct pfsync_header *);
1265126258Smlaier	h->version = PFSYNC_VERSION;
1266126258Smlaier	h->af = 0;
1267126258Smlaier	h->count = 0;
1268126258Smlaier	h->action = action;
1269126258Smlaier
1270130613Smlaier	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
1271127145Smlaier#ifdef __FreeBSD__
1272126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1273126261Smlaier	    LIST_FIRST(&pfsync_list));
1274126261Smlaier#else
1275126258Smlaier	timeout_add(&sc->sc_tmo, hz);
1276126261Smlaier#endif
1277126258Smlaier	return (m);
1278126258Smlaier}
1279126258Smlaier
1280126258Smlaierint
1281145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
1282126258Smlaier{
1283127145Smlaier#ifdef __FreeBSD__
1284141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1285126261Smlaier#else
1286126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1287130613Smlaier#endif
1288126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1289130613Smlaier	struct pfsync_header *h, *h_net;
1290130613Smlaier	struct pfsync_state *sp = NULL;
1291130613Smlaier	struct pfsync_state_upd *up = NULL;
1292130613Smlaier	struct pfsync_state_del *dp = NULL;
1293130613Smlaier	struct pf_rule *r;
1294126258Smlaier	u_long secs;
1295130613Smlaier	int s, ret = 0;
1296130613Smlaier	u_int8_t i = 255, newaction = 0;
1297126258Smlaier
1298130613Smlaier#ifdef __FreeBSD__
1299130613Smlaier	PF_ASSERT(MA_OWNED);
1300130613Smlaier#endif
1301130613Smlaier	/*
1302130613Smlaier	 * If a packet falls in the forest and there's nobody around to
1303130613Smlaier	 * hear, does it make a sound?
1304130613Smlaier	 */
1305145836Smlaier	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
1306145836Smlaier	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1307130613Smlaier		/* Don't leave any stale pfsync packets hanging around. */
1308130613Smlaier		if (sc->sc_mbuf != NULL) {
1309130613Smlaier			m_freem(sc->sc_mbuf);
1310130613Smlaier			sc->sc_mbuf = NULL;
1311130613Smlaier			sc->sc_statep.s = NULL;
1312130613Smlaier		}
1313130613Smlaier		return (0);
1314130613Smlaier	}
1315130613Smlaier
1316126258Smlaier	if (action >= PFSYNC_ACT_MAX)
1317126258Smlaier		return (EINVAL);
1318126258Smlaier
1319126258Smlaier	s = splnet();
1320130613Smlaier	if (sc->sc_mbuf == NULL) {
1321130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1322130613Smlaier		    (void *)&sc->sc_statep.s)) == NULL) {
1323126258Smlaier			splx(s);
1324126258Smlaier			return (ENOMEM);
1325126258Smlaier		}
1326130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1327126258Smlaier	} else {
1328130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1329126258Smlaier		if (h->action != action) {
1330126258Smlaier			pfsync_sendout(sc);
1331130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1332130613Smlaier			    (void *)&sc->sc_statep.s)) == NULL) {
1333126258Smlaier				splx(s);
1334126258Smlaier				return (ENOMEM);
1335126258Smlaier			}
1336130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1337130613Smlaier		} else {
1338130613Smlaier			/*
1339130613Smlaier			 * If it's an update, look in the packet to see if
1340130613Smlaier			 * we already have an update for the state.
1341130613Smlaier			 */
1342130613Smlaier			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1343130613Smlaier				struct pfsync_state *usp =
1344130613Smlaier				    (void *)((char *)h + PFSYNC_HDRLEN);
1345130613Smlaier
1346130613Smlaier				for (i = 0; i < h->count; i++) {
1347130613Smlaier					if (!memcmp(usp->id, &st->id,
1348130613Smlaier					    PFSYNC_ID_LEN) &&
1349130613Smlaier					    usp->creatorid == st->creatorid) {
1350130613Smlaier						sp = usp;
1351130613Smlaier						sp->updates++;
1352130613Smlaier						break;
1353130613Smlaier					}
1354130613Smlaier					usp++;
1355130613Smlaier				}
1356130613Smlaier			}
1357126258Smlaier		}
1358126258Smlaier	}
1359126258Smlaier
1360130613Smlaier	secs = time_second;
1361126258Smlaier
1362130613Smlaier	st->pfsync_time = time_uptime;
1363130613Smlaier	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1364130613Smlaier	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1365130613Smlaier
1366130613Smlaier	if (sp == NULL) {
1367130613Smlaier		/* not a "duplicate" update */
1368130613Smlaier		i = 255;
1369130613Smlaier		sp = sc->sc_statep.s++;
1370130613Smlaier		sc->sc_mbuf->m_pkthdr.len =
1371130613Smlaier		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1372130613Smlaier		h->count++;
1373130613Smlaier		bzero(sp, sizeof(*sp));
1374130613Smlaier
1375130613Smlaier		bcopy(&st->id, sp->id, sizeof(sp->id));
1376130613Smlaier		sp->creatorid = st->creatorid;
1377130613Smlaier
1378130613Smlaier		strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1379130613Smlaier		pf_state_host_hton(&st->lan, &sp->lan);
1380130613Smlaier		pf_state_host_hton(&st->gwy, &sp->gwy);
1381130613Smlaier		pf_state_host_hton(&st->ext, &sp->ext);
1382130613Smlaier
1383130613Smlaier		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1384130613Smlaier
1385130613Smlaier		sp->creation = htonl(secs - st->creation);
1386130613Smlaier		sp->packets[0] = htonl(st->packets[0]);
1387130613Smlaier		sp->packets[1] = htonl(st->packets[1]);
1388130613Smlaier		sp->bytes[0] = htonl(st->bytes[0]);
1389130613Smlaier		sp->bytes[1] = htonl(st->bytes[1]);
1390130613Smlaier		if ((r = st->rule.ptr) == NULL)
1391130613Smlaier			sp->rule = htonl(-1);
1392130613Smlaier		else
1393130613Smlaier			sp->rule = htonl(r->nr);
1394130613Smlaier		if ((r = st->anchor.ptr) == NULL)
1395130613Smlaier			sp->anchor = htonl(-1);
1396130613Smlaier		else
1397130613Smlaier			sp->anchor = htonl(r->nr);
1398130613Smlaier		sp->af = st->af;
1399130613Smlaier		sp->proto = st->proto;
1400130613Smlaier		sp->direction = st->direction;
1401130613Smlaier		sp->log = st->log;
1402130613Smlaier		sp->allow_opts = st->allow_opts;
1403130613Smlaier		sp->timeout = st->timeout;
1404130613Smlaier
1405145836Smlaier		if (flags & PFSYNC_FLAG_STALE)
1406145836Smlaier			sp->sync_flags |= PFSTATE_STALE;
1407130613Smlaier	}
1408130613Smlaier
1409126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
1410126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
1411126258Smlaier
1412126258Smlaier	if (st->expire <= secs)
1413126258Smlaier		sp->expire = htonl(0);
1414126258Smlaier	else
1415126258Smlaier		sp->expire = htonl(st->expire - secs);
1416126258Smlaier
1417130613Smlaier	/* do we need to build "compressed" actions for network transfer? */
1418145836Smlaier	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
1419130613Smlaier		switch (action) {
1420130613Smlaier		case PFSYNC_ACT_UPD:
1421130613Smlaier			newaction = PFSYNC_ACT_UPD_C;
1422130613Smlaier			break;
1423130613Smlaier		case PFSYNC_ACT_DEL:
1424130613Smlaier			newaction = PFSYNC_ACT_DEL_C;
1425130613Smlaier			break;
1426130613Smlaier		default:
1427130613Smlaier			/* by default we just send the uncompressed states */
1428130613Smlaier			break;
1429130613Smlaier		}
1430130613Smlaier	}
1431130613Smlaier
1432130613Smlaier	if (newaction) {
1433130613Smlaier		if (sc->sc_mbuf_net == NULL) {
1434130613Smlaier			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1435130613Smlaier			    (void *)&sc->sc_statep_net.s)) == NULL) {
1436130613Smlaier				splx(s);
1437130613Smlaier				return (ENOMEM);
1438130613Smlaier			}
1439130613Smlaier		}
1440130613Smlaier		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1441130613Smlaier
1442130613Smlaier		switch (newaction) {
1443130613Smlaier		case PFSYNC_ACT_UPD_C:
1444130613Smlaier			if (i != 255) {
1445130613Smlaier				up = (void *)((char *)h_net +
1446130613Smlaier				    PFSYNC_HDRLEN + (i * sizeof(*up)));
1447130613Smlaier				up->updates++;
1448130613Smlaier			} else {
1449130613Smlaier				h_net->count++;
1450130613Smlaier				sc->sc_mbuf_net->m_pkthdr.len =
1451130613Smlaier				    sc->sc_mbuf_net->m_len += sizeof(*up);
1452130613Smlaier				up = sc->sc_statep_net.u++;
1453130613Smlaier
1454130613Smlaier				bzero(up, sizeof(*up));
1455130613Smlaier				bcopy(&st->id, up->id, sizeof(up->id));
1456130613Smlaier				up->creatorid = st->creatorid;
1457130613Smlaier			}
1458130613Smlaier			up->timeout = st->timeout;
1459130613Smlaier			up->expire = sp->expire;
1460130613Smlaier			up->src = sp->src;
1461130613Smlaier			up->dst = sp->dst;
1462130613Smlaier			break;
1463130613Smlaier		case PFSYNC_ACT_DEL_C:
1464130613Smlaier			sc->sc_mbuf_net->m_pkthdr.len =
1465130613Smlaier			    sc->sc_mbuf_net->m_len += sizeof(*dp);
1466130613Smlaier			dp = sc->sc_statep_net.d++;
1467130613Smlaier			h_net->count++;
1468130613Smlaier
1469130613Smlaier			bzero(dp, sizeof(*dp));
1470130613Smlaier			bcopy(&st->id, dp->id, sizeof(dp->id));
1471130613Smlaier			dp->creatorid = st->creatorid;
1472130613Smlaier			break;
1473130613Smlaier		}
1474130613Smlaier	}
1475130613Smlaier
1476130613Smlaier	if (h->count == sc->sc_maxcount ||
1477130613Smlaier	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1478126258Smlaier		ret = pfsync_sendout(sc);
1479126258Smlaier
1480126258Smlaier	splx(s);
1481130613Smlaier	return (ret);
1482126258Smlaier}
1483126258Smlaier
1484130613Smlaier/* This must be called in splnet() */
1485126258Smlaierint
1486130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1487126258Smlaier{
1488127145Smlaier#ifdef __FreeBSD__
1489141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1490126261Smlaier#else
1491126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1492130613Smlaier#endif
1493130613Smlaier	struct pfsync_header *h;
1494126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1495130613Smlaier	struct pfsync_state_upd_req *rup;
1496145836Smlaier	int ret = 0;
1497130613Smlaier
1498130613Smlaier#ifdef __FreeBSD__
1499130613Smlaier	PF_ASSERT(MA_OWNED);
1500126261Smlaier#endif
1501130613Smlaier	if (sc->sc_mbuf == NULL) {
1502130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1503145836Smlaier		    (void *)&sc->sc_statep.s)) == NULL)
1504130613Smlaier			return (ENOMEM);
1505130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1506130613Smlaier	} else {
1507130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1508130613Smlaier		if (h->action != PFSYNC_ACT_UREQ) {
1509130613Smlaier			pfsync_sendout(sc);
1510130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1511145836Smlaier			    (void *)&sc->sc_statep.s)) == NULL)
1512130613Smlaier				return (ENOMEM);
1513130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1514130613Smlaier		}
1515130613Smlaier	}
1516130613Smlaier
1517130613Smlaier	if (src != NULL)
1518130613Smlaier		sc->sc_sendaddr = *src;
1519130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1520130613Smlaier	h->count++;
1521130613Smlaier	rup = sc->sc_statep.r++;
1522130613Smlaier	bzero(rup, sizeof(*rup));
1523130613Smlaier	if (up != NULL) {
1524130613Smlaier		bcopy(up->id, rup->id, sizeof(rup->id));
1525130613Smlaier		rup->creatorid = up->creatorid;
1526130613Smlaier	}
1527130613Smlaier
1528130613Smlaier	if (h->count == sc->sc_maxcount)
1529130613Smlaier		ret = pfsync_sendout(sc);
1530130613Smlaier
1531130613Smlaier	return (ret);
1532130613Smlaier}
1533130613Smlaier
1534130613Smlaierint
1535130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname)
1536130613Smlaier{
1537130613Smlaier#ifdef __FreeBSD__
1538141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1539130613Smlaier#else
1540130613Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1541130613Smlaier#endif
1542130613Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1543130613Smlaier	struct pfsync_state_clr *cp;
1544126258Smlaier	int s, ret;
1545126258Smlaier
1546126258Smlaier	s = splnet();
1547130613Smlaier#ifdef __FreeBSD__
1548130613Smlaier	PF_ASSERT(MA_OWNED);
1549130613Smlaier#endif
1550130613Smlaier	if (sc->sc_mbuf != NULL)
1551130613Smlaier		pfsync_sendout(sc);
1552130613Smlaier	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1553130613Smlaier	    (void *)&sc->sc_statep.c)) == NULL) {
1554126258Smlaier		splx(s);
1555126258Smlaier		return (ENOMEM);
1556126258Smlaier	}
1557130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1558130613Smlaier	cp = sc->sc_statep.c;
1559130613Smlaier	cp->creatorid = creatorid;
1560130613Smlaier	if (ifname != NULL)
1561130613Smlaier		strlcpy(cp->ifname, ifname, IFNAMSIZ);
1562126258Smlaier
1563126258Smlaier	ret = (pfsync_sendout(sc));
1564126258Smlaier	splx(s);
1565126258Smlaier	return (ret);
1566126258Smlaier}
1567126258Smlaier
1568126258Smlaiervoid
1569126258Smlaierpfsync_timeout(void *v)
1570126258Smlaier{
1571126258Smlaier	struct pfsync_softc *sc = v;
1572126258Smlaier	int s;
1573126258Smlaier
1574126258Smlaier	s = splnet();
1575130613Smlaier#ifdef __FreeBSD__
1576130613Smlaier	PF_LOCK();
1577130613Smlaier#endif
1578126258Smlaier	pfsync_sendout(sc);
1579130613Smlaier#ifdef __FreeBSD__
1580130613Smlaier	PF_UNLOCK();
1581130613Smlaier#endif
1582126258Smlaier	splx(s);
1583126258Smlaier}
1584126258Smlaier
1585145836Smlaier/* This must be called in splnet() */
1586130613Smlaiervoid
1587130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1588130613Smlaier{
1589130613Smlaier	struct pfsync_state_bus *bus;
1590130613Smlaier
1591130613Smlaier#ifdef __FreeBSD__
1592130613Smlaier	PF_ASSERT(MA_OWNED);
1593130613Smlaier#endif
1594130613Smlaier	if (sc->sc_mbuf != NULL)
1595130613Smlaier		pfsync_sendout(sc);
1596130613Smlaier
1597130613Smlaier	if (pfsync_sync_ok &&
1598130613Smlaier	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1599130613Smlaier	    (void *)&sc->sc_statep.b)) != NULL) {
1600130613Smlaier		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1601130613Smlaier		bus = sc->sc_statep.b;
1602130613Smlaier		bus->creatorid = pf_status.hostid;
1603130613Smlaier		bus->status = status;
1604130613Smlaier		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1605130613Smlaier		pfsync_sendout(sc);
1606130613Smlaier	}
1607130613Smlaier}
1608130613Smlaier
1609130613Smlaiervoid
1610130613Smlaierpfsync_bulk_update(void *v)
1611130613Smlaier{
1612130613Smlaier	struct pfsync_softc *sc = v;
1613130613Smlaier	int s, i = 0;
1614130613Smlaier	struct pf_state *state;
1615130613Smlaier
1616130613Smlaier#ifdef __FreeBSD__
1617130613Smlaier	PF_LOCK();
1618130613Smlaier#endif
1619130613Smlaier	s = splnet();
1620130613Smlaier	if (sc->sc_mbuf != NULL)
1621130613Smlaier		pfsync_sendout(sc);
1622130613Smlaier
1623130613Smlaier	/*
1624130613Smlaier	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1625130613Smlaier	 * been sent since the latest request was made.
1626130613Smlaier	 */
1627130613Smlaier	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1628130613Smlaier	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1629130613Smlaier		if (state->pfsync_time > sc->sc_ureq_received) {
1630130613Smlaier			/* we're done */
1631130613Smlaier			pfsync_send_bus(sc, PFSYNC_BUS_END);
1632130613Smlaier			sc->sc_ureq_received = 0;
1633130613Smlaier#ifdef __FreeBSD__
1634130613Smlaier			callout_stop(&sc->sc_bulk_tmo);
1635130613Smlaier#else
1636130613Smlaier			timeout_del(&sc->sc_bulk_tmo);
1637130613Smlaier#endif
1638130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1639130613Smlaier				printf("pfsync: bulk update complete\n");
1640130613Smlaier			break;
1641130613Smlaier		} else {
1642130613Smlaier			/* send an update and move to end of list */
1643130613Smlaier			if (!state->sync_flags)
1644130613Smlaier				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1645130613Smlaier			state->pfsync_time = time_uptime;
1646130613Smlaier			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1647130613Smlaier			TAILQ_INSERT_TAIL(&state_updates, state,
1648130613Smlaier			    u.s.entry_updates);
1649130613Smlaier
1650130613Smlaier			/* look again for more in a bit */
1651130613Smlaier#ifdef __FreeBSD__
1652130613Smlaier			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1653130613Smlaier			    LIST_FIRST(&pfsync_list));
1654130613Smlaier#else
1655130613Smlaier			timeout_add(&sc->sc_bulk_tmo, 1);
1656130613Smlaier#endif
1657130613Smlaier		}
1658130613Smlaier	}
1659130613Smlaier	if (sc->sc_mbuf != NULL)
1660130613Smlaier		pfsync_sendout(sc);
1661130613Smlaier	splx(s);
1662130613Smlaier#ifdef __FreeBSD__
1663130613Smlaier	PF_UNLOCK();
1664130613Smlaier#endif
1665130613Smlaier}
1666130613Smlaier
1667130613Smlaiervoid
1668130613Smlaierpfsync_bulkfail(void *v)
1669130613Smlaier{
1670130613Smlaier	struct pfsync_softc *sc = v;
1671145836Smlaier	int s, error;
1672130613Smlaier
1673130613Smlaier#ifdef __FreeBSD__
1674130613Smlaier	PF_LOCK();
1675130613Smlaier#endif
1676130613Smlaier	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1677130613Smlaier		/* Try again in a bit */
1678130613Smlaier#ifdef __FreeBSD__
1679130613Smlaier		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1680130613Smlaier		    LIST_FIRST(&pfsync_list));
1681130613Smlaier#else
1682130613Smlaier		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1683130613Smlaier#endif
1684145836Smlaier		s = splnet();
1685145836Smlaier		error = pfsync_request_update(NULL, NULL);
1686145836Smlaier		if (error == ENOMEM) {
1687145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1688145836Smlaier				printf("pfsync: cannot allocate mbufs for "
1689145836Smlaier				    "bulk update\n");
1690145836Smlaier		} else
1691145836Smlaier			pfsync_sendout(sc);
1692145836Smlaier		splx(s);
1693130613Smlaier	} else {
1694130613Smlaier		/* Pretend like the transfer was ok */
1695130613Smlaier		sc->sc_ureq_sent = 0;
1696130613Smlaier		sc->sc_bulk_tries = 0;
1697145836Smlaier#if NCARP > 0
1698145836Smlaier		if (!pfsync_sync_ok)
1699145836Smlaier			carp_suppress_preempt--;
1700145836Smlaier#endif
1701130613Smlaier		pfsync_sync_ok = 1;
1702130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
1703130613Smlaier			printf("pfsync: failed to receive "
1704130613Smlaier			    "bulk update status\n");
1705130613Smlaier#ifdef __FreeBSD__
1706130613Smlaier		callout_stop(&sc->sc_bulkfail_tmo);
1707130613Smlaier#else
1708130613Smlaier		timeout_del(&sc->sc_bulkfail_tmo);
1709130613Smlaier#endif
1710130613Smlaier	}
1711130613Smlaier#ifdef __FreeBSD__
1712130613Smlaier	PF_UNLOCK();
1713130613Smlaier#endif
1714130613Smlaier}
1715130613Smlaier
1716145836Smlaier/* This must be called in splnet() */
1717126258Smlaierint
1718126258Smlaierpfsync_sendout(sc)
1719126258Smlaier	struct pfsync_softc *sc;
1720126258Smlaier{
1721138666Smlaier#if NBPFILTER > 0
1722141584Smlaier# ifdef __FreeBSD__
1723141584Smlaier	struct ifnet *ifp = SCP2IFP(sc);
1724141584Smlaier# else
1725141584Smlaier	struct ifnet *ifp = &sc->if_sc;
1726141584Smlaier# endif
1727138666Smlaier#endif
1728130613Smlaier	struct mbuf *m;
1729126258Smlaier
1730127145Smlaier#ifdef __FreeBSD__
1731130613Smlaier	PF_ASSERT(MA_OWNED);
1732126261Smlaier	callout_stop(&sc->sc_tmo);
1733126261Smlaier#else
1734126258Smlaier	timeout_del(&sc->sc_tmo);
1735126261Smlaier#endif
1736130613Smlaier
1737130613Smlaier	if (sc->sc_mbuf == NULL)
1738130613Smlaier		return (0);
1739130613Smlaier	m = sc->sc_mbuf;
1740126258Smlaier	sc->sc_mbuf = NULL;
1741130613Smlaier	sc->sc_statep.s = NULL;
1742126258Smlaier
1743127145Smlaier#ifdef __FreeBSD__
1744126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1745126261Smlaier#endif
1746126258Smlaier#if NBPFILTER > 0
1747126258Smlaier	if (ifp->if_bpf)
1748126258Smlaier		bpf_mtap(ifp->if_bpf, m);
1749126258Smlaier#endif
1750126258Smlaier
1751130613Smlaier	if (sc->sc_mbuf_net) {
1752130613Smlaier		m_freem(m);
1753130613Smlaier		m = sc->sc_mbuf_net;
1754130613Smlaier		sc->sc_mbuf_net = NULL;
1755130613Smlaier		sc->sc_statep_net.s = NULL;
1756130613Smlaier	}
1757126258Smlaier
1758145836Smlaier	if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1759130613Smlaier		struct ip *ip;
1760130613Smlaier		struct sockaddr sa;
1761130613Smlaier
1762130613Smlaier		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1763130613Smlaier		if (m == NULL) {
1764130613Smlaier			pfsyncstats.pfsyncs_onomem++;
1765130613Smlaier			return (0);
1766130613Smlaier		}
1767130613Smlaier		ip = mtod(m, struct ip *);
1768130613Smlaier		ip->ip_v = IPVERSION;
1769130613Smlaier		ip->ip_hl = sizeof(*ip) >> 2;
1770130613Smlaier		ip->ip_tos = IPTOS_LOWDELAY;
1771130613Smlaier#ifdef __FreeBSD__
1772130613Smlaier		ip->ip_len = m->m_pkthdr.len;
1773130613Smlaier#else
1774130613Smlaier		ip->ip_len = htons(m->m_pkthdr.len);
1775130613Smlaier#endif
1776130613Smlaier		ip->ip_id = htons(ip_randomid());
1777130613Smlaier#ifdef __FreeBSD__
1778130613Smlaier		ip->ip_off = IP_DF;
1779130613Smlaier#else
1780130613Smlaier		ip->ip_off = htons(IP_DF);
1781130613Smlaier#endif
1782130613Smlaier		ip->ip_ttl = PFSYNC_DFLTTL;
1783130613Smlaier		ip->ip_p = IPPROTO_PFSYNC;
1784130613Smlaier		ip->ip_sum = 0;
1785130613Smlaier
1786130613Smlaier		bzero(&sa, sizeof(sa));
1787145836Smlaier		ip->ip_src.s_addr = INADDR_ANY;
1788130613Smlaier
1789130613Smlaier#ifdef __FreeBSD__
1790130613Smlaier		if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1791130613Smlaier#else
1792130613Smlaier		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1793130613Smlaier#endif
1794130613Smlaier			m->m_flags |= M_MCAST;
1795130613Smlaier		ip->ip_dst = sc->sc_sendaddr;
1796130613Smlaier#ifdef __FreeBSD__
1797145836Smlaier		/* XXX_IMPORT */
1798145836Smlaier		sc->sc_sendaddr.s_addr = htonl(sc->sc_sync_peer.s_addr);
1799130613Smlaier#else
1800145836Smlaier		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
1801130613Smlaier#endif
1802130613Smlaier
1803130613Smlaier		pfsyncstats.pfsyncs_opackets++;
1804130613Smlaier#ifdef __FreeBSD__
1805147614Smlaier		if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
1806147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1807147261Smlaier		callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
1808147261Smlaier#else
1809130613Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1810130613Smlaier			pfsyncstats.pfsyncs_oerrors++;
1811130613Smlaier#endif
1812130613Smlaier	} else
1813130613Smlaier		m_freem(m);
1814130613Smlaier
1815126258Smlaier	return (0);
1816126258Smlaier}
1817126261Smlaier
1818147261Smlaier#ifdef __FreeBSD__
1819147261Smlaierstatic void
1820147261Smlaierpfsync_senddef(void *arg)
1821147261Smlaier{
1822147261Smlaier	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
1823147261Smlaier	struct mbuf *m;
1824126261Smlaier
1825147261Smlaier	for(;;) {
1826147261Smlaier		IF_DEQUEUE(&sc->sc_ifq, m);
1827147261Smlaier		if (m == NULL)
1828147261Smlaier			break;
1829147261Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1830147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1831147261Smlaier	}
1832147261Smlaier}
1833147261Smlaier
1834126261Smlaierstatic int
1835126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
1836126261Smlaier{
1837126261Smlaier	int error = 0;
1838126261Smlaier
1839126261Smlaier	switch (type) {
1840126261Smlaier	case MOD_LOAD:
1841126261Smlaier		LIST_INIT(&pfsync_list);
1842126261Smlaier		if_clone_attach(&pfsync_cloner);
1843126261Smlaier		break;
1844126261Smlaier
1845126261Smlaier	case MOD_UNLOAD:
1846126261Smlaier		if_clone_detach(&pfsync_cloner);
1847126261Smlaier		while (!LIST_EMPTY(&pfsync_list))
1848126261Smlaier			pfsync_clone_destroy(
1849141584Smlaier			    SCP2IFP(LIST_FIRST(&pfsync_list)));
1850126261Smlaier		break;
1851126261Smlaier
1852126261Smlaier	default:
1853126261Smlaier		error = EINVAL;
1854126261Smlaier		break;
1855126261Smlaier	}
1856126261Smlaier
1857126261Smlaier	return error;
1858126261Smlaier}
1859126261Smlaier
1860126261Smlaierstatic moduledata_t pfsync_mod = {
1861126261Smlaier	"pfsync",
1862126261Smlaier	pfsync_modevent,
1863126261Smlaier	0
1864126261Smlaier};
1865126261Smlaier
1866126261Smlaier#define PFSYNC_MODVER 1
1867126261Smlaier
1868135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1869126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
1870126261Smlaier#endif /* __FreeBSD__ */
1871