if_pfsync.c revision 147321
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 147321 2005-06-12 16:46:20Z mlaier $	*/
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>
59126261Smlaier#else
60126258Smlaier#include <sys/ioctl.h>
61126258Smlaier#include <sys/timeout.h>
62126261Smlaier#endif
63126258Smlaier
64126258Smlaier#include <net/if.h>
65130933Sbrooks#if defined(__FreeBSD__)
66130933Sbrooks#include <net/if_clone.h>
67130933Sbrooks#endif
68126258Smlaier#include <net/if_types.h>
69126258Smlaier#include <net/route.h>
70126258Smlaier#include <net/bpf.h>
71145836Smlaier#include <netinet/tcp.h>
72145836Smlaier#include <netinet/tcp_seq.h>
73126258Smlaier
74126258Smlaier#ifdef	INET
75126258Smlaier#include <netinet/in.h>
76130613Smlaier#include <netinet/in_systm.h>
77126258Smlaier#include <netinet/in_var.h>
78130613Smlaier#include <netinet/ip.h>
79130613Smlaier#include <netinet/ip_var.h>
80126258Smlaier#endif
81126258Smlaier
82126258Smlaier#ifdef INET6
83126258Smlaier#ifndef INET
84126258Smlaier#include <netinet/in.h>
85126258Smlaier#endif
86126258Smlaier#include <netinet6/nd6.h>
87126258Smlaier#endif /* INET6 */
88126258Smlaier
89145836Smlaier#ifdef __FreeBSD__
90145836Smlaier#include "opt_carp.h"
91145836Smlaier#ifdef DEV_CARP
92145836Smlaier#define	NCARP	1
93145836Smlaier#endif
94145836Smlaier#else
95145836Smlaier#include "carp.h"
96145836Smlaier#endif
97145836Smlaier#if NCARP > 0
98145836Smlaierextern int carp_suppress_preempt;
99145836Smlaier#endif
100145836Smlaier
101126258Smlaier#include <net/pfvar.h>
102126258Smlaier#include <net/if_pfsync.h>
103126258Smlaier
104127145Smlaier#ifdef __FreeBSD__
105127145Smlaier#define	PFSYNCNAME	"pfsync"
106126261Smlaier#endif
107126261Smlaier
108126258Smlaier#define PFSYNC_MINMTU	\
109126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
110126258Smlaier
111126258Smlaier#ifdef PFSYNCDEBUG
112126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
113126258Smlaierint pfsyncdebug;
114126258Smlaier#else
115126258Smlaier#define DPRINTF(x)
116126258Smlaier#endif
117126258Smlaier
118127145Smlaier#ifndef __FreeBSD__
119130613Smlaierstruct pfsync_softc	pfsyncif;
120126261Smlaier#endif
121130613Smlaierstruct pfsyncstats	pfsyncstats;
122126258Smlaier
123127145Smlaier#ifdef __FreeBSD__
124130613Smlaier
125130613Smlaier/*
126130613Smlaier * Locking notes:
127130613Smlaier * Whenever we really touch/look at the state table we have to hold the
128130613Smlaier * PF_LOCK. Functions that do just the interface handling, grab the per
129130613Smlaier * softc lock instead.
130130613Smlaier *
131130613Smlaier */
132130613Smlaier
133128209Sbrooksstatic void	pfsync_clone_destroy(struct ifnet *);
134128209Sbrooksstatic int	pfsync_clone_create(struct if_clone *, int);
135147261Smlaierstatic void	pfsync_senddef(void *);
136126261Smlaier#else
137126258Smlaiervoid	pfsyncattach(int);
138126261Smlaier#endif
139130613Smlaiervoid	pfsync_setmtu(struct pfsync_softc *, int);
140130613Smlaierint	pfsync_insert_net_state(struct pfsync_state *);
141126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
142130613Smlaier	    struct rtentry *);
143126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
144126258Smlaiervoid	pfsyncstart(struct ifnet *);
145126258Smlaier
146130613Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
147130613Smlaierint	pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
148130613Smlaierint	pfsync_sendout(struct pfsync_softc *);
149130613Smlaiervoid	pfsync_timeout(void *);
150130613Smlaiervoid	pfsync_send_bus(struct pfsync_softc *, u_int8_t);
151130613Smlaiervoid	pfsync_bulk_update(void *);
152130613Smlaiervoid	pfsync_bulkfail(void *);
153126258Smlaier
154145836Smlaierint	pfsync_sync_ok;
155127145Smlaier#ifndef __FreeBSD__
156126258Smlaierextern int ifqmaxlen;
157130613Smlaierextern struct timeval time;
158130613Smlaierextern struct timeval mono_time;
159130613Smlaierextern int hz;
160126261Smlaier#endif
161126258Smlaier
162127145Smlaier#ifdef __FreeBSD__
163126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
164126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
165147256Sbrooks#define	SCP2IFP(sc)		((sc)->sc_ifp)
166130933SbrooksIFC_SIMPLE_DECLARE(pfsync, 1);
167126261Smlaier
168128209Sbrooksstatic void
169126261Smlaierpfsync_clone_destroy(struct ifnet *ifp)
170126261Smlaier{
171126261Smlaier        struct pfsync_softc *sc;
172126261Smlaier
173130613Smlaier	sc = ifp->if_softc;
174126261Smlaier	callout_stop(&sc->sc_tmo);
175130613Smlaier	callout_stop(&sc->sc_bulk_tmo);
176130613Smlaier	callout_stop(&sc->sc_bulkfail_tmo);
177126261Smlaier
178147261Smlaier	callout_stop(&sc->sc_send_tmo);
179147261Smlaier
180126261Smlaier#if NBPFILTER > 0
181126261Smlaier        bpfdetach(ifp);
182126261Smlaier#endif
183126261Smlaier        if_detach(ifp);
184147256Sbrooks	if_free(ifp);
185126261Smlaier        LIST_REMOVE(sc, sc_next);
186126261Smlaier        free(sc, M_PFSYNC);
187126261Smlaier}
188126261Smlaier
189128209Sbrooksstatic int
190126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
191126261Smlaier{
192126261Smlaier	struct pfsync_softc *sc;
193130613Smlaier	struct ifnet *ifp;
194126261Smlaier
195126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
196130613Smlaier	    M_WAITOK|M_ZERO);
197147256Sbrooks	ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
198147256Sbrooks	if (ifp == NULL) {
199147256Sbrooks		free(sc, M_PFSYNC);
200147256Sbrooks		return (ENOSPC);
201147256Sbrooks	}
202126261Smlaier
203130613Smlaier	pfsync_sync_ok = 1;
204130613Smlaier	sc->sc_mbuf = NULL;
205130613Smlaier	sc->sc_mbuf_net = NULL;
206130613Smlaier	sc->sc_statep.s = NULL;
207130613Smlaier	sc->sc_statep_net.s = NULL;
208130613Smlaier	sc->sc_maxupdates = 128;
209130613Smlaier	sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
210130613Smlaier	sc->sc_ureq_received = 0;
211130613Smlaier	sc->sc_ureq_sent = 0;
212130613Smlaier
213141584Smlaier	ifp = SCP2IFP(sc);
214130613Smlaier	if_initname(ifp, ifc->ifc_name, unit);
215130613Smlaier	ifp->if_ioctl = pfsyncioctl;
216130613Smlaier	ifp->if_output = pfsyncoutput;
217130613Smlaier	ifp->if_start = pfsyncstart;
218130613Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
219130613Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
220130613Smlaier	ifp->if_baudrate = IF_Mbps(100);
221130613Smlaier	ifp->if_softc = sc;
222126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
223147321Smlaier	callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
224147321Smlaier	callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
225147321Smlaier	callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
226147321Smlaier	callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
227147261Smlaier	mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
228147261Smlaier	    MTX_DEF);
229141584Smlaier	if_attach(ifp);
230126261Smlaier
231126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
232126261Smlaier#if NBPFILTER > 0
233141584Smlaier	bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
234126261Smlaier#endif
235126261Smlaier
236126261Smlaier	return (0);
237126261Smlaier}
238126261Smlaier#else /* !__FreeBSD__ */
239126261Smlaiervoid
240126258Smlaierpfsyncattach(int npfsync)
241126258Smlaier{
242126258Smlaier	struct ifnet *ifp;
243126258Smlaier
244130613Smlaier	pfsync_sync_ok = 1;
245130613Smlaier	bzero(&pfsyncif, sizeof(pfsyncif));
246126258Smlaier	pfsyncif.sc_mbuf = NULL;
247130613Smlaier	pfsyncif.sc_mbuf_net = NULL;
248130613Smlaier	pfsyncif.sc_statep.s = NULL;
249130613Smlaier	pfsyncif.sc_statep_net.s = NULL;
250130613Smlaier	pfsyncif.sc_maxupdates = 128;
251145836Smlaier	pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
252130613Smlaier	pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
253130613Smlaier	pfsyncif.sc_ureq_received = 0;
254130613Smlaier	pfsyncif.sc_ureq_sent = 0;
255126258Smlaier	ifp = &pfsyncif.sc_if;
256126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
257126258Smlaier	ifp->if_softc = &pfsyncif;
258126258Smlaier	ifp->if_ioctl = pfsyncioctl;
259126258Smlaier	ifp->if_output = pfsyncoutput;
260126258Smlaier	ifp->if_start = pfsyncstart;
261126258Smlaier	ifp->if_type = IFT_PFSYNC;
262126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
263126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
264126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
265126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
266130613Smlaier	timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
267130613Smlaier	timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
268126258Smlaier	if_attach(ifp);
269126258Smlaier	if_alloc_sadl(ifp);
270126258Smlaier
271126258Smlaier#if NBPFILTER > 0
272126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
273126258Smlaier#endif
274126258Smlaier}
275126261Smlaier#endif
276126258Smlaier
277126258Smlaier/*
278126258Smlaier * Start output on the pfsync interface.
279126258Smlaier */
280126258Smlaiervoid
281126258Smlaierpfsyncstart(struct ifnet *ifp)
282126258Smlaier{
283130613Smlaier#ifdef __FreeBSD__
284130613Smlaier	IF_LOCK(&ifp->if_snd);
285130613Smlaier	_IF_DROP(&ifp->if_snd);
286130613Smlaier	_IF_DRAIN(&ifp->if_snd);
287130613Smlaier	IF_UNLOCK(&ifp->if_snd);
288130613Smlaier#else
289126258Smlaier	struct mbuf *m;
290126258Smlaier	int s;
291126258Smlaier
292126258Smlaier	for (;;) {
293126258Smlaier		s = splimp();
294126258Smlaier		IF_DROP(&ifp->if_snd);
295126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
296126258Smlaier		splx(s);
297126258Smlaier
298126258Smlaier		if (m == NULL)
299126258Smlaier			return;
300126258Smlaier		else
301126258Smlaier			m_freem(m);
302126258Smlaier	}
303130613Smlaier#endif
304126258Smlaier}
305126258Smlaier
306126258Smlaierint
307130613Smlaierpfsync_insert_net_state(struct pfsync_state *sp)
308130613Smlaier{
309130613Smlaier	struct pf_state	*st = NULL;
310130613Smlaier	struct pf_rule *r = NULL;
311130613Smlaier	struct pfi_kif	*kif;
312130613Smlaier
313130613Smlaier#ifdef __FreeBSD__
314130613Smlaier	PF_ASSERT(MA_OWNED);
315130613Smlaier#endif
316130613Smlaier	if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
317130613Smlaier		printf("pfsync_insert_net_state: invalid creator id:"
318130613Smlaier		    " %08x\n", ntohl(sp->creatorid));
319130613Smlaier		return (EINVAL);
320130613Smlaier	}
321130613Smlaier
322130613Smlaier	kif = pfi_lookup_create(sp->ifname);
323130613Smlaier	if (kif == NULL) {
324130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
325130613Smlaier			printf("pfsync_insert_net_state: "
326130613Smlaier			    "unknown interface: %s\n", sp->ifname);
327130613Smlaier		/* skip this state */
328130613Smlaier		return (0);
329130613Smlaier	}
330130613Smlaier
331130613Smlaier	/*
332130613Smlaier	 * Just use the default rule until we have infrastructure to find the
333130613Smlaier	 * best matching rule.
334130613Smlaier	 */
335130613Smlaier	r = &pf_default_rule;
336130613Smlaier
337130613Smlaier	if (!r->max_states || r->states < r->max_states)
338130613Smlaier		st = pool_get(&pf_state_pl, PR_NOWAIT);
339130613Smlaier	if (st == NULL) {
340130613Smlaier		pfi_maybe_destroy(kif);
341130613Smlaier		return (ENOMEM);
342130613Smlaier	}
343130613Smlaier	bzero(st, sizeof(*st));
344130613Smlaier
345130613Smlaier	st->rule.ptr = r;
346130613Smlaier	/* XXX get pointers to nat_rule and anchor */
347130613Smlaier
348145836Smlaier	/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
349145836Smlaier	r->states++;
350145836Smlaier
351130613Smlaier	/* fill in the rest of the state entry */
352130613Smlaier	pf_state_host_ntoh(&sp->lan, &st->lan);
353130613Smlaier	pf_state_host_ntoh(&sp->gwy, &st->gwy);
354130613Smlaier	pf_state_host_ntoh(&sp->ext, &st->ext);
355130613Smlaier
356130613Smlaier	pf_state_peer_ntoh(&sp->src, &st->src);
357130613Smlaier	pf_state_peer_ntoh(&sp->dst, &st->dst);
358130613Smlaier
359130613Smlaier	bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
360145836Smlaier	st->creation = time_second - ntohl(sp->creation);
361130613Smlaier	st->expire = ntohl(sp->expire) + time_second;
362130613Smlaier
363130613Smlaier	st->af = sp->af;
364130613Smlaier	st->proto = sp->proto;
365130613Smlaier	st->direction = sp->direction;
366130613Smlaier	st->log = sp->log;
367130613Smlaier	st->timeout = sp->timeout;
368130613Smlaier	st->allow_opts = sp->allow_opts;
369130613Smlaier
370130613Smlaier	bcopy(sp->id, &st->id, sizeof(st->id));
371130613Smlaier	st->creatorid = sp->creatorid;
372145836Smlaier	st->sync_flags = PFSTATE_FROMSYNC;
373130613Smlaier
374130613Smlaier
375130613Smlaier	if (pf_insert_state(kif, st)) {
376130613Smlaier		pfi_maybe_destroy(kif);
377145836Smlaier		/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
378145836Smlaier		r->states--;
379130613Smlaier		pool_put(&pf_state_pl, st);
380130613Smlaier		return (EINVAL);
381130613Smlaier	}
382130613Smlaier
383130613Smlaier	return (0);
384130613Smlaier}
385130613Smlaier
386130613Smlaiervoid
387130613Smlaier#ifdef __FreeBSD__
388130613Smlaierpfsync_input(struct mbuf *m, __unused int off)
389130613Smlaier#else
390130613Smlaierpfsync_input(struct mbuf *m, ...)
391130613Smlaier#endif
392130613Smlaier{
393130613Smlaier	struct ip *ip = mtod(m, struct ip *);
394130613Smlaier	struct pfsync_header *ph;
395130613Smlaier#ifdef __FreeBSD__
396130613Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
397130613Smlaier#else
398130613Smlaier	struct pfsync_softc *sc = &pfsyncif;
399130613Smlaier#endif
400130613Smlaier	struct pf_state *st, key;
401130613Smlaier	struct pfsync_state *sp;
402130613Smlaier	struct pfsync_state_upd *up;
403130613Smlaier	struct pfsync_state_del *dp;
404130613Smlaier	struct pfsync_state_clr *cp;
405130613Smlaier	struct pfsync_state_upd_req *rup;
406130613Smlaier	struct pfsync_state_bus *bus;
407130613Smlaier	struct in_addr src;
408130613Smlaier	struct mbuf *mp;
409145836Smlaier	int iplen, action, error, i, s, count, offp, sfail, stale = 0;
410130613Smlaier
411130613Smlaier	pfsyncstats.pfsyncs_ipackets++;
412130613Smlaier
413130613Smlaier	/* verify that we have a sync interface configured */
414130613Smlaier	if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
415130613Smlaier		goto done;
416130613Smlaier
417130613Smlaier	/* verify that the packet came in on the right interface */
418130613Smlaier	if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
419130613Smlaier		pfsyncstats.pfsyncs_badif++;
420130613Smlaier		goto done;
421130613Smlaier	}
422130613Smlaier
423130613Smlaier	/* verify that the IP TTL is 255.  */
424130613Smlaier	if (ip->ip_ttl != PFSYNC_DFLTTL) {
425130613Smlaier		pfsyncstats.pfsyncs_badttl++;
426130613Smlaier		goto done;
427130613Smlaier	}
428130613Smlaier
429130613Smlaier	iplen = ip->ip_hl << 2;
430130613Smlaier
431130613Smlaier	if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
432130613Smlaier		pfsyncstats.pfsyncs_hdrops++;
433130613Smlaier		goto done;
434130613Smlaier	}
435130613Smlaier
436130613Smlaier	if (iplen + sizeof(*ph) > m->m_len) {
437130613Smlaier		if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
438130613Smlaier			pfsyncstats.pfsyncs_hdrops++;
439130613Smlaier			goto done;
440130613Smlaier		}
441130613Smlaier		ip = mtod(m, struct ip *);
442130613Smlaier	}
443130613Smlaier	ph = (struct pfsync_header *)((char *)ip + iplen);
444130613Smlaier
445130613Smlaier	/* verify the version */
446130613Smlaier	if (ph->version != PFSYNC_VERSION) {
447130613Smlaier		pfsyncstats.pfsyncs_badver++;
448130613Smlaier		goto done;
449130613Smlaier	}
450130613Smlaier
451130613Smlaier	action = ph->action;
452130613Smlaier	count = ph->count;
453130613Smlaier
454130613Smlaier	/* make sure it's a valid action code */
455130613Smlaier	if (action >= PFSYNC_ACT_MAX) {
456130613Smlaier		pfsyncstats.pfsyncs_badact++;
457130613Smlaier		goto done;
458130613Smlaier	}
459130613Smlaier
460130613Smlaier	/* Cheaper to grab this now than having to mess with mbufs later */
461130613Smlaier	src = ip->ip_src;
462130613Smlaier
463130613Smlaier	switch (action) {
464130613Smlaier	case PFSYNC_ACT_CLR: {
465145836Smlaier		struct pf_state *nexts;
466130613Smlaier		struct pfi_kif	*kif;
467130613Smlaier		u_int32_t creatorid;
468130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
469130613Smlaier		    sizeof(*cp), &offp)) == NULL) {
470130613Smlaier			pfsyncstats.pfsyncs_badlen++;
471130613Smlaier			return;
472130613Smlaier		}
473130613Smlaier		cp = (struct pfsync_state_clr *)(mp->m_data + offp);
474130613Smlaier		creatorid = cp->creatorid;
475130613Smlaier
476130613Smlaier		s = splsoftnet();
477130613Smlaier#ifdef __FreeBSD__
478130613Smlaier		PF_LOCK();
479130613Smlaier#endif
480130613Smlaier		if (cp->ifname[0] == '\0') {
481145836Smlaier			for (st = RB_MIN(pf_state_tree_id, &tree_id);
482145836Smlaier			    st; st = nexts) {
483145836Smlaier                		nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
484145836Smlaier				if (st->creatorid == creatorid) {
485130613Smlaier					st->timeout = PFTM_PURGE;
486145836Smlaier					pf_purge_expired_state(st);
487145836Smlaier				}
488130613Smlaier			}
489130613Smlaier		} else {
490130613Smlaier			kif = pfi_lookup_if(cp->ifname);
491130613Smlaier			if (kif == NULL) {
492130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
493130613Smlaier					printf("pfsync_input: PFSYNC_ACT_CLR "
494130613Smlaier					    "bad interface: %s\n", cp->ifname);
495130613Smlaier				splx(s);
496130613Smlaier#ifdef __FreeBSD__
497130613Smlaier				PF_UNLOCK();
498130613Smlaier#endif
499130613Smlaier				goto done;
500130613Smlaier			}
501145836Smlaier			for (st = RB_MIN(pf_state_tree_lan_ext,
502145836Smlaier			    &kif->pfik_lan_ext); st; st = nexts) {
503145836Smlaier				nexts = RB_NEXT(pf_state_tree_lan_ext,
504145836Smlaier				    &kif->pfik_lan_ext, st);
505145836Smlaier				if (st->creatorid == creatorid) {
506130613Smlaier					st->timeout = PFTM_PURGE;
507145836Smlaier					pf_purge_expired_state(st);
508145836Smlaier				}
509130613Smlaier			}
510130613Smlaier		}
511130613Smlaier#ifdef __FreeBSD__
512130613Smlaier		PF_UNLOCK();
513130613Smlaier#endif
514130613Smlaier		splx(s);
515130613Smlaier
516130613Smlaier		break;
517130613Smlaier	}
518130613Smlaier	case PFSYNC_ACT_INS:
519130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
520130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
521130613Smlaier			pfsyncstats.pfsyncs_badlen++;
522130613Smlaier			return;
523130613Smlaier		}
524130613Smlaier
525130613Smlaier		s = splsoftnet();
526130613Smlaier#ifdef __FreeBSD__
527130613Smlaier		PF_LOCK();
528130613Smlaier#endif
529130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
530130613Smlaier		    i < count; i++, sp++) {
531130613Smlaier			/* check for invalid values */
532130613Smlaier			if (sp->timeout >= PFTM_MAX ||
533130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
534130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST ||
535130613Smlaier			    sp->direction > PF_OUT ||
536130613Smlaier			    (sp->af != AF_INET && sp->af != AF_INET6)) {
537130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
538130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_INS: "
539130613Smlaier					    "invalid value\n");
540130613Smlaier				pfsyncstats.pfsyncs_badstate++;
541130613Smlaier				continue;
542130613Smlaier			}
543130613Smlaier
544130613Smlaier			if ((error = pfsync_insert_net_state(sp))) {
545130613Smlaier				if (error == ENOMEM) {
546130613Smlaier					splx(s);
547130613Smlaier#ifdef __FreeBSD__
548130613Smlaier					PF_UNLOCK();
549130613Smlaier#endif
550130613Smlaier					goto done;
551130613Smlaier				}
552130613Smlaier				continue;
553130613Smlaier			}
554130613Smlaier		}
555130613Smlaier#ifdef __FreeBSD__
556130613Smlaier		PF_UNLOCK();
557130613Smlaier#endif
558130613Smlaier		splx(s);
559130613Smlaier		break;
560130613Smlaier	case PFSYNC_ACT_UPD:
561130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
562130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
563130613Smlaier			pfsyncstats.pfsyncs_badlen++;
564130613Smlaier			return;
565130613Smlaier		}
566130613Smlaier
567130613Smlaier		s = splsoftnet();
568130613Smlaier#ifdef __FreeBSD__
569130613Smlaier		PF_LOCK();
570130613Smlaier#endif
571130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
572130613Smlaier		    i < count; i++, sp++) {
573145836Smlaier			int flags = PFSYNC_FLAG_STALE;
574145836Smlaier
575130613Smlaier			/* check for invalid values */
576130613Smlaier			if (sp->timeout >= PFTM_MAX ||
577130613Smlaier			    sp->src.state > PF_TCPS_PROXY_DST ||
578130613Smlaier			    sp->dst.state > PF_TCPS_PROXY_DST) {
579130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
580130613Smlaier					printf("pfsync_insert: PFSYNC_ACT_UPD: "
581130613Smlaier					    "invalid value\n");
582130613Smlaier				pfsyncstats.pfsyncs_badstate++;
583130613Smlaier				continue;
584130613Smlaier			}
585130613Smlaier
586130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
587130613Smlaier			key.creatorid = sp->creatorid;
588130613Smlaier
589130613Smlaier			st = pf_find_state_byid(&key);
590130613Smlaier			if (st == NULL) {
591130613Smlaier				/* insert the update */
592130613Smlaier				if (pfsync_insert_net_state(sp))
593130613Smlaier					pfsyncstats.pfsyncs_badstate++;
594130613Smlaier				continue;
595130613Smlaier			}
596145836Smlaier			sfail = 0;
597145836Smlaier			if (st->proto == IPPROTO_TCP) {
598145836Smlaier				/*
599145836Smlaier				 * The state should never go backwards except
600145836Smlaier				 * for syn-proxy states.  Neither should the
601145836Smlaier				 * sequence window slide backwards.
602145836Smlaier				 */
603145836Smlaier				if (st->src.state > sp->src.state &&
604145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
605145836Smlaier				    sp->src.state >= PF_TCPS_PROXY_SRC))
606145836Smlaier					sfail = 1;
607145836Smlaier				else if (SEQ_GT(st->src.seqlo,
608145836Smlaier				    ntohl(sp->src.seqlo)))
609145836Smlaier					sfail = 3;
610145836Smlaier				else if (st->dst.state > sp->dst.state) {
611145836Smlaier					/* There might still be useful
612145836Smlaier					 * information about the src state here,
613145836Smlaier					 * so import that part of the update,
614145836Smlaier					 * then "fail" so we send the updated
615145836Smlaier					 * state back to the peer who is missing
616145836Smlaier					 * our what we know. */
617145836Smlaier					pf_state_peer_ntoh(&sp->src, &st->src);
618145836Smlaier					/* XXX do anything with timeouts? */
619145836Smlaier					sfail = 7;
620145836Smlaier					flags = 0;
621145836Smlaier				} else if (st->dst.state >= TCPS_SYN_SENT &&
622145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo)))
623145836Smlaier					sfail = 4;
624145836Smlaier			} else {
625145836Smlaier				/*
626145836Smlaier				 * Non-TCP protocol state machine always go
627145836Smlaier				 * forwards
628145836Smlaier				 */
629145836Smlaier				if (st->src.state > sp->src.state)
630145836Smlaier					sfail = 5;
631145836Smlaier				else if ( st->dst.state > sp->dst.state)
632145836Smlaier					sfail = 6;
633145836Smlaier			}
634145836Smlaier			if (sfail) {
635145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
636145836Smlaier					printf("pfsync: %s stale update "
637145836Smlaier					    "(%d) id: %016llx "
638145836Smlaier					    "creatorid: %08x\n",
639145836Smlaier					    (sfail < 7 ?  "ignoring"
640145836Smlaier					     : "partial"), sfail,
641145836Smlaier#ifdef __FreeBSD__
642145836Smlaier					    (unsigned long long)be64toh(st->id),
643145836Smlaier#else
644145836Smlaier					    betoh64(st->id),
645145836Smlaier#endif
646145836Smlaier					    ntohl(st->creatorid));
647145836Smlaier				pfsyncstats.pfsyncs_badstate++;
648145836Smlaier
649145836Smlaier				if (!(sp->sync_flags & PFSTATE_STALE)) {
650145836Smlaier					/* we have a better state, send it */
651145836Smlaier					if (sc->sc_mbuf != NULL && !stale)
652145836Smlaier						pfsync_sendout(sc);
653145836Smlaier					stale++;
654145836Smlaier					if (!st->sync_flags)
655145836Smlaier						pfsync_pack_state(
656145836Smlaier						    PFSYNC_ACT_UPD, st, flags);
657145836Smlaier				}
658145836Smlaier				continue;
659145836Smlaier			}
660130613Smlaier			pf_state_peer_ntoh(&sp->src, &st->src);
661130613Smlaier			pf_state_peer_ntoh(&sp->dst, &st->dst);
662130613Smlaier			st->expire = ntohl(sp->expire) + time_second;
663130613Smlaier			st->timeout = sp->timeout;
664130613Smlaier		}
665145836Smlaier		if (stale && sc->sc_mbuf != NULL)
666145836Smlaier			pfsync_sendout(sc);
667130613Smlaier#ifdef __FreeBSD__
668130613Smlaier		PF_UNLOCK();
669130613Smlaier#endif
670130613Smlaier		splx(s);
671130613Smlaier		break;
672130613Smlaier	/*
673130613Smlaier	 * It's not strictly necessary for us to support the "uncompressed"
674130613Smlaier	 * delete action, but it's relatively simple and maintains consistency.
675130613Smlaier	 */
676130613Smlaier	case PFSYNC_ACT_DEL:
677130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
678130613Smlaier		    count * sizeof(*sp), &offp)) == NULL) {
679130613Smlaier			pfsyncstats.pfsyncs_badlen++;
680130613Smlaier			return;
681130613Smlaier		}
682130613Smlaier
683130613Smlaier		s = splsoftnet();
684130613Smlaier#ifdef __FreeBSD__
685130613Smlaier		PF_LOCK();
686130613Smlaier#endif
687130613Smlaier		for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp);
688130613Smlaier		    i < count; i++, sp++) {
689130613Smlaier			bcopy(sp->id, &key.id, sizeof(key.id));
690130613Smlaier			key.creatorid = sp->creatorid;
691130613Smlaier
692130613Smlaier			st = pf_find_state_byid(&key);
693130613Smlaier			if (st == NULL) {
694130613Smlaier				pfsyncstats.pfsyncs_badstate++;
695130613Smlaier				continue;
696130613Smlaier			}
697130613Smlaier			st->timeout = PFTM_PURGE;
698130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
699145836Smlaier			pf_purge_expired_state(st);
700130613Smlaier		}
701130613Smlaier#ifdef __FreeBSD__
702130613Smlaier		PF_UNLOCK();
703130613Smlaier#endif
704130613Smlaier		splx(s);
705130613Smlaier		break;
706130613Smlaier	case PFSYNC_ACT_UPD_C: {
707130613Smlaier		int update_requested = 0;
708130613Smlaier
709130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
710130613Smlaier		    count * sizeof(*up), &offp)) == NULL) {
711130613Smlaier			pfsyncstats.pfsyncs_badlen++;
712130613Smlaier			return;
713130613Smlaier		}
714130613Smlaier
715130613Smlaier		s = splsoftnet();
716130613Smlaier#ifdef __FreeBSD__
717130613Smlaier		PF_LOCK();
718130613Smlaier#endif
719130613Smlaier		for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp);
720130613Smlaier		    i < count; i++, up++) {
721130613Smlaier			/* check for invalid values */
722130613Smlaier			if (up->timeout >= PFTM_MAX ||
723130613Smlaier			    up->src.state > PF_TCPS_PROXY_DST ||
724130613Smlaier			    up->dst.state > PF_TCPS_PROXY_DST) {
725130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
726130613Smlaier					printf("pfsync_insert: "
727130613Smlaier					    "PFSYNC_ACT_UPD_C: "
728130613Smlaier					    "invalid value\n");
729130613Smlaier				pfsyncstats.pfsyncs_badstate++;
730130613Smlaier				continue;
731130613Smlaier			}
732130613Smlaier
733130613Smlaier			bcopy(up->id, &key.id, sizeof(key.id));
734130613Smlaier			key.creatorid = up->creatorid;
735130613Smlaier
736130613Smlaier			st = pf_find_state_byid(&key);
737130613Smlaier			if (st == NULL) {
738130613Smlaier				/* We don't have this state. Ask for it. */
739145836Smlaier				error = pfsync_request_update(up, &src);
740145836Smlaier				if (error == ENOMEM) {
741145836Smlaier					splx(s);
742145836Smlaier					goto done;
743145836Smlaier				}
744130613Smlaier				update_requested = 1;
745130613Smlaier				pfsyncstats.pfsyncs_badstate++;
746130613Smlaier				continue;
747130613Smlaier			}
748145836Smlaier			sfail = 0;
749145836Smlaier			if (st->proto == IPPROTO_TCP) {
750145836Smlaier				/*
751145836Smlaier				 * The state should never go backwards except
752145836Smlaier				 * for syn-proxy states.  Neither should the
753145836Smlaier				 * sequence window slide backwards.
754145836Smlaier				 */
755145836Smlaier				if (st->src.state > up->src.state &&
756145836Smlaier				    (st->src.state < PF_TCPS_PROXY_SRC ||
757145836Smlaier				    up->src.state >= PF_TCPS_PROXY_SRC))
758145836Smlaier					sfail = 1;
759145836Smlaier				else if (st->dst.state > up->dst.state)
760145836Smlaier					sfail = 2;
761145836Smlaier				else if (SEQ_GT(st->src.seqlo,
762145836Smlaier				    ntohl(up->src.seqlo)))
763145836Smlaier					sfail = 3;
764145836Smlaier				else if (st->dst.state >= TCPS_SYN_SENT &&
765145836Smlaier				    SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo)))
766145836Smlaier					sfail = 4;
767145836Smlaier			} else {
768145836Smlaier				/*
769145836Smlaier				 * Non-TCP protocol state machine always go
770145836Smlaier				 * forwards
771145836Smlaier				 */
772145836Smlaier				if (st->src.state > up->src.state)
773145836Smlaier					sfail = 5;
774145836Smlaier				else if (st->dst.state > up->dst.state)
775145836Smlaier					sfail = 6;
776145836Smlaier			}
777145836Smlaier			if (sfail) {
778145836Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
779145836Smlaier					printf("pfsync: ignoring stale update "
780145836Smlaier					    "(%d) id: %016llx "
781145836Smlaier					    "creatorid: %08x\n", sfail,
782145836Smlaier#ifdef __FreeBSD__
783145836Smlaier					    (unsigned long long)be64toh(st->id),
784145836Smlaier#else
785145836Smlaier					    betoh64(st->id),
786145836Smlaier#endif
787145836Smlaier					    ntohl(st->creatorid));
788145836Smlaier				pfsyncstats.pfsyncs_badstate++;
789145836Smlaier
790145836Smlaier				/* we have a better state, send it out */
791145836Smlaier				if ((!stale || update_requested) &&
792145836Smlaier				    sc->sc_mbuf != NULL) {
793145836Smlaier					pfsync_sendout(sc);
794145836Smlaier					update_requested = 0;
795145836Smlaier				}
796145836Smlaier				stale++;
797145836Smlaier				if (!st->sync_flags)
798145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD, st,
799145836Smlaier					    PFSYNC_FLAG_STALE);
800145836Smlaier				continue;
801145836Smlaier			}
802130613Smlaier			pf_state_peer_ntoh(&up->src, &st->src);
803130613Smlaier			pf_state_peer_ntoh(&up->dst, &st->dst);
804130613Smlaier			st->expire = ntohl(up->expire) + time_second;
805130613Smlaier			st->timeout = up->timeout;
806130613Smlaier		}
807145836Smlaier		if ((update_requested || stale) && sc->sc_mbuf)
808130613Smlaier			pfsync_sendout(sc);
809130613Smlaier#ifdef __FreeBSD__
810130613Smlaier		PF_UNLOCK();
811130613Smlaier#endif
812130613Smlaier		splx(s);
813130613Smlaier		break;
814130613Smlaier	}
815130613Smlaier	case PFSYNC_ACT_DEL_C:
816130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
817130613Smlaier		    count * sizeof(*dp), &offp)) == NULL) {
818130613Smlaier			pfsyncstats.pfsyncs_badlen++;
819130613Smlaier			return;
820130613Smlaier		}
821130613Smlaier
822130613Smlaier		s = splsoftnet();
823130613Smlaier#ifdef __FreeBSD__
824130613Smlaier		PF_LOCK();
825130613Smlaier#endif
826130613Smlaier		for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp);
827130613Smlaier		    i < count; i++, dp++) {
828130613Smlaier			bcopy(dp->id, &key.id, sizeof(key.id));
829130613Smlaier			key.creatorid = dp->creatorid;
830130613Smlaier
831130613Smlaier			st = pf_find_state_byid(&key);
832130613Smlaier			if (st == NULL) {
833130613Smlaier				pfsyncstats.pfsyncs_badstate++;
834130613Smlaier				continue;
835130613Smlaier			}
836130613Smlaier			st->timeout = PFTM_PURGE;
837130613Smlaier			st->sync_flags |= PFSTATE_FROMSYNC;
838145836Smlaier			pf_purge_expired_state(st);
839130613Smlaier		}
840130613Smlaier#ifdef __FreeBSD__
841130613Smlaier		PF_UNLOCK();
842130613Smlaier#endif
843130613Smlaier		splx(s);
844130613Smlaier		break;
845130613Smlaier	case PFSYNC_ACT_INS_F:
846130613Smlaier	case PFSYNC_ACT_DEL_F:
847130613Smlaier		/* not implemented */
848130613Smlaier		break;
849130613Smlaier	case PFSYNC_ACT_UREQ:
850130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
851130613Smlaier		    count * sizeof(*rup), &offp)) == NULL) {
852130613Smlaier			pfsyncstats.pfsyncs_badlen++;
853130613Smlaier			return;
854130613Smlaier		}
855130613Smlaier
856130613Smlaier		s = splsoftnet();
857130613Smlaier#ifdef __FreeBSD__
858130613Smlaier		PF_LOCK();
859130613Smlaier#endif
860130613Smlaier		if (sc->sc_mbuf != NULL)
861130613Smlaier			pfsync_sendout(sc);
862130613Smlaier		for (i = 0,
863130613Smlaier		    rup = (struct pfsync_state_upd_req *)(mp->m_data + offp);
864130613Smlaier		    i < count; i++, rup++) {
865130613Smlaier			bcopy(rup->id, &key.id, sizeof(key.id));
866130613Smlaier			key.creatorid = rup->creatorid;
867130613Smlaier
868130613Smlaier			if (key.id == 0 && key.creatorid == 0) {
869130613Smlaier				sc->sc_ureq_received = time_uptime;
870130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
871130613Smlaier					printf("pfsync: received "
872130613Smlaier					    "bulk update request\n");
873130613Smlaier				pfsync_send_bus(sc, PFSYNC_BUS_START);
874130613Smlaier#ifdef __FreeBSD__
875130613Smlaier				callout_reset(&sc->sc_bulk_tmo, 1 * hz,
876130613Smlaier				    pfsync_bulk_update,
877130613Smlaier				    LIST_FIRST(&pfsync_list));
878130613Smlaier#else
879130613Smlaier				timeout_add(&sc->sc_bulk_tmo, 1 * hz);
880130613Smlaier#endif
881130613Smlaier			} else {
882130613Smlaier				st = pf_find_state_byid(&key);
883130613Smlaier				if (st == NULL) {
884130613Smlaier					pfsyncstats.pfsyncs_badstate++;
885130613Smlaier					continue;
886130613Smlaier				}
887145836Smlaier				if (!st->sync_flags)
888145836Smlaier					pfsync_pack_state(PFSYNC_ACT_UPD,
889145836Smlaier					    st, 0);
890130613Smlaier			}
891130613Smlaier		}
892130613Smlaier		if (sc->sc_mbuf != NULL)
893130613Smlaier			pfsync_sendout(sc);
894130613Smlaier#ifdef __FreeBSD__
895130613Smlaier		PF_UNLOCK();
896130613Smlaier#endif
897130613Smlaier		splx(s);
898130613Smlaier		break;
899130613Smlaier	case PFSYNC_ACT_BUS:
900130613Smlaier		/* If we're not waiting for a bulk update, who cares. */
901130613Smlaier		if (sc->sc_ureq_sent == 0)
902130613Smlaier			break;
903130613Smlaier
904130613Smlaier		if ((mp = m_pulldown(m, iplen + sizeof(*ph),
905130613Smlaier		    sizeof(*bus), &offp)) == NULL) {
906130613Smlaier			pfsyncstats.pfsyncs_badlen++;
907130613Smlaier			return;
908130613Smlaier		}
909130613Smlaier		bus = (struct pfsync_state_bus *)(mp->m_data + offp);
910130613Smlaier		switch (bus->status) {
911130613Smlaier		case PFSYNC_BUS_START:
912130613Smlaier#ifdef __FreeBSD__
913130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo,
914130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
915130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount),
916130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
917130613Smlaier#else
918130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo,
919130613Smlaier			    pf_pool_limits[PF_LIMIT_STATES].limit /
920130613Smlaier			    (PFSYNC_BULKPACKETS * sc->sc_maxcount));
921130613Smlaier#endif
922130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
923130613Smlaier				printf("pfsync: received bulk "
924130613Smlaier				    "update start\n");
925130613Smlaier			break;
926130613Smlaier		case PFSYNC_BUS_END:
927130613Smlaier			if (time_uptime - ntohl(bus->endtime) >=
928130613Smlaier			    sc->sc_ureq_sent) {
929130613Smlaier				/* that's it, we're happy */
930130613Smlaier				sc->sc_ureq_sent = 0;
931130613Smlaier				sc->sc_bulk_tries = 0;
932130613Smlaier#ifdef __FreeBSD__
933130613Smlaier				callout_stop(&sc->sc_bulkfail_tmo);
934130613Smlaier#else
935130613Smlaier				timeout_del(&sc->sc_bulkfail_tmo);
936130613Smlaier#endif
937145836Smlaier#if NCARP > 0	/* XXX_IMPORT */
938145836Smlaier				if (!pfsync_sync_ok)
939145836Smlaier					carp_suppress_preempt--;
940145836Smlaier#endif
941130613Smlaier				pfsync_sync_ok = 1;
942130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
943130613Smlaier					printf("pfsync: received valid "
944130613Smlaier					    "bulk update end\n");
945130613Smlaier			} else {
946130613Smlaier				if (pf_status.debug >= PF_DEBUG_MISC)
947130613Smlaier					printf("pfsync: received invalid "
948130613Smlaier					    "bulk update end: bad timestamp\n");
949130613Smlaier			}
950130613Smlaier			break;
951130613Smlaier		}
952130613Smlaier		break;
953130613Smlaier	}
954130613Smlaier
955130613Smlaierdone:
956130613Smlaier	if (m)
957130613Smlaier		m_freem(m);
958130613Smlaier}
959130613Smlaier
960130613Smlaierint
961126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
962126258Smlaier	struct rtentry *rt)
963126258Smlaier{
964126258Smlaier	m_freem(m);
965126258Smlaier	return (0);
966126258Smlaier}
967126258Smlaier
968126258Smlaier/* ARGSUSED */
969126258Smlaierint
970126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
971126258Smlaier{
972130613Smlaier#ifndef __FreeBSD__
973130613Smlaier	struct proc *p = curproc;
974130613Smlaier#endif
975126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
976126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
977130613Smlaier	struct ip_moptions *imo = &sc->sc_imo;
978130613Smlaier	struct pfsyncreq pfsyncr;
979130613Smlaier	struct ifnet    *sifp;
980130613Smlaier	int s, error;
981126258Smlaier
982126258Smlaier	switch (cmd) {
983126258Smlaier	case SIOCSIFADDR:
984126258Smlaier	case SIOCAIFADDR:
985126258Smlaier	case SIOCSIFDSTADDR:
986126258Smlaier	case SIOCSIFFLAGS:
987126258Smlaier		if (ifp->if_flags & IFF_UP)
988126258Smlaier			ifp->if_flags |= IFF_RUNNING;
989126258Smlaier		else
990126258Smlaier			ifp->if_flags &= ~IFF_RUNNING;
991126258Smlaier		break;
992126258Smlaier	case SIOCSIFMTU:
993126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
994126258Smlaier			return (EINVAL);
995126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
996126258Smlaier			ifr->ifr_mtu = MCLBYTES;
997126258Smlaier		s = splnet();
998130613Smlaier#ifdef __FreeBSD__
999130613Smlaier		PF_LOCK();
1000130613Smlaier#endif
1001130613Smlaier		if (ifr->ifr_mtu < ifp->if_mtu) {
1002126258Smlaier			pfsync_sendout(sc);
1003130613Smlaier		}
1004126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
1005130613Smlaier#ifdef __FreeBSD__
1006130613Smlaier		PF_UNLOCK();
1007130613Smlaier#endif
1008126258Smlaier		splx(s);
1009126258Smlaier		break;
1010130613Smlaier	case SIOCGETPFSYNC:
1011130613Smlaier#ifdef __FreeBSD__
1012130613Smlaier		/* XXX: read unlocked */
1013130613Smlaier#endif
1014130613Smlaier		bzero(&pfsyncr, sizeof(pfsyncr));
1015130613Smlaier		if (sc->sc_sync_ifp)
1016145836Smlaier			strlcpy(pfsyncr.pfsyncr_syncdev,
1017130613Smlaier			    sc->sc_sync_ifp->if_xname, IFNAMSIZ);
1018145836Smlaier		pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
1019130613Smlaier		pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
1020130613Smlaier		if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
1021130613Smlaier			return (error);
1022130613Smlaier		break;
1023130613Smlaier	case SIOCSETPFSYNC:
1024130613Smlaier#ifdef __FreeBSD__
1025130613Smlaier		if ((error = suser(curthread)) != 0)
1026130613Smlaier#else
1027130613Smlaier		if ((error = suser(p, p->p_acflag)) != 0)
1028130613Smlaier#endif
1029130613Smlaier			return (error);
1030130613Smlaier		if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
1031130613Smlaier			return (error);
1032130613Smlaier
1033145836Smlaier		if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
1034145836Smlaier			sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
1035145836Smlaier		else
1036145836Smlaier			sc->sc_sync_peer.s_addr =
1037145836Smlaier			    pfsyncr.pfsyncr_syncpeer.s_addr;
1038145836Smlaier
1039130613Smlaier		if (pfsyncr.pfsyncr_maxupdates > 255)
1040130613Smlaier			return (EINVAL);
1041130613Smlaier#ifdef __FreeBSD__
1042147261Smlaier		callout_drain(&sc->sc_send_tmo);
1043130613Smlaier		PF_LOCK();
1044130613Smlaier#endif
1045130613Smlaier		sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
1046130613Smlaier
1047145836Smlaier		if (pfsyncr.pfsyncr_syncdev[0] == 0) {
1048130613Smlaier			sc->sc_sync_ifp = NULL;
1049130613Smlaier			if (sc->sc_mbuf_net != NULL) {
1050130613Smlaier				/* Don't keep stale pfsync packets around. */
1051130613Smlaier				s = splnet();
1052130613Smlaier				m_freem(sc->sc_mbuf_net);
1053130613Smlaier				sc->sc_mbuf_net = NULL;
1054130613Smlaier				sc->sc_statep_net.s = NULL;
1055130613Smlaier				splx(s);
1056130613Smlaier			}
1057145836Smlaier			if (imo->imo_num_memberships > 0) {
1058145836Smlaier				in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1059145836Smlaier				imo->imo_multicast_ifp = NULL;
1060145836Smlaier			}
1061130613Smlaier#ifdef __FreeBSD__
1062130613Smlaier			PF_UNLOCK();
1063130613Smlaier#endif
1064130613Smlaier			break;
1065130613Smlaier		}
1066145836Smlaier
1067145836Smlaier		if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
1068130613Smlaier#ifdef __FreeBSD__
1069130613Smlaier			PF_UNLOCK();
1070130613Smlaier#endif
1071130613Smlaier			return (EINVAL);
1072130613Smlaier		}
1073130613Smlaier
1074130613Smlaier		s = splnet();
1075141584Smlaier#ifdef __FreeBSD__
1076141584Smlaier		if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
1077141584Smlaier#else
1078130613Smlaier		if (sifp->if_mtu < sc->sc_if.if_mtu ||
1079141584Smlaier#endif
1080130613Smlaier		    (sc->sc_sync_ifp != NULL &&
1081130613Smlaier		    sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
1082130613Smlaier		    sifp->if_mtu < MCLBYTES - sizeof(struct ip))
1083130613Smlaier			pfsync_sendout(sc);
1084130613Smlaier		sc->sc_sync_ifp = sifp;
1085130613Smlaier
1086141584Smlaier#ifdef __FreeBSD__
1087141584Smlaier		pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
1088141584Smlaier#else
1089130613Smlaier		pfsync_setmtu(sc, sc->sc_if.if_mtu);
1090141584Smlaier#endif
1091130613Smlaier
1092130613Smlaier		if (imo->imo_num_memberships > 0) {
1093130613Smlaier			in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1094130613Smlaier			imo->imo_multicast_ifp = NULL;
1095130613Smlaier		}
1096130613Smlaier
1097145836Smlaier		if (sc->sc_sync_ifp &&
1098145836Smlaier		    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1099130613Smlaier			struct in_addr addr;
1100130613Smlaier
1101145836Smlaier			if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) {
1102145836Smlaier				sc->sc_sync_ifp = NULL;
1103130613Smlaier#ifdef __FreeBSD__
1104145836Smlaier				PF_UNLOCK();
1105145836Smlaier#endif
1106145836Smlaier				splx(s);
1107145836Smlaier				return (EADDRNOTAVAIL);
1108145836Smlaier			}
1109145836Smlaier#ifdef __FreeBSD__
1110130613Smlaier			PF_UNLOCK();		/* addmulti mallocs w/ WAITOK */
1111130613Smlaier			addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
1112130613Smlaier#else
1113130613Smlaier			addr.s_addr = INADDR_PFSYNC_GROUP;
1114130613Smlaier#endif
1115145836Smlaier
1116130613Smlaier			if ((imo->imo_membership[0] =
1117130613Smlaier			    in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
1118145836Smlaier				sc->sc_sync_ifp = NULL;
1119130613Smlaier				splx(s);
1120130613Smlaier				return (ENOBUFS);
1121130613Smlaier			}
1122130613Smlaier			imo->imo_num_memberships++;
1123130613Smlaier			imo->imo_multicast_ifp = sc->sc_sync_ifp;
1124130613Smlaier			imo->imo_multicast_ttl = PFSYNC_DFLTTL;
1125130613Smlaier			imo->imo_multicast_loop = 0;
1126145836Smlaier		}
1127130613Smlaier
1128145836Smlaier		if (sc->sc_sync_ifp ||
1129145836Smlaier		    sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) {
1130130613Smlaier			/* Request a full state table update. */
1131130613Smlaier#ifdef __FreeBSD__
1132130613Smlaier			PF_LOCK();
1133145836Smlaier#endif
1134130613Smlaier			sc->sc_ureq_sent = time_uptime;
1135145836Smlaier#if NCARP > 0
1136145836Smlaier			if (pfsync_sync_ok)
1137145836Smlaier				carp_suppress_preempt++;
1138130613Smlaier#endif
1139130613Smlaier			pfsync_sync_ok = 0;
1140130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1141130613Smlaier				printf("pfsync: requesting bulk update\n");
1142130613Smlaier#ifdef __FreeBSD__
1143130613Smlaier			callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
1144130613Smlaier			    pfsync_bulkfail, LIST_FIRST(&pfsync_list));
1145130613Smlaier#else
1146130613Smlaier			timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1147130613Smlaier#endif
1148145836Smlaier			error = pfsync_request_update(NULL, NULL);
1149145836Smlaier			if (error == ENOMEM) {
1150145836Smlaier#ifdef __FreeBSD__
1151145836Smlaier				PF_UNLOCK();
1152145836Smlaier#endif
1153145836Smlaier				splx(s);
1154145836Smlaier				return (ENOMEM);
1155145836Smlaier			}
1156130613Smlaier			pfsync_sendout(sc);
1157130613Smlaier		}
1158130613Smlaier#ifdef __FreeBSD__
1159130613Smlaier		PF_UNLOCK();
1160130613Smlaier#endif
1161130613Smlaier		splx(s);
1162130613Smlaier
1163130613Smlaier		break;
1164130613Smlaier
1165126258Smlaier	default:
1166126258Smlaier		return (ENOTTY);
1167126258Smlaier	}
1168126258Smlaier
1169126258Smlaier	return (0);
1170126258Smlaier}
1171126258Smlaier
1172126258Smlaiervoid
1173130613Smlaierpfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
1174130613Smlaier{
1175126258Smlaier	int mtu;
1176130613Smlaier
1177130613Smlaier	if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
1178130613Smlaier		mtu = sc->sc_sync_ifp->if_mtu;
1179130613Smlaier	else
1180130613Smlaier		mtu = mtu_req;
1181130613Smlaier
1182130613Smlaier	sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
1183130613Smlaier	    sizeof(struct pfsync_state);
1184130613Smlaier	if (sc->sc_maxcount > 254)
1185130613Smlaier	    sc->sc_maxcount = 254;
1186141584Smlaier#ifdef __FreeBSD__
1187141584Smlaier	SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
1188141584Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1189141584Smlaier#else
1190126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
1191130613Smlaier	    sc->sc_maxcount * sizeof(struct pfsync_state);
1192141584Smlaier#endif
1193126258Smlaier}
1194126258Smlaier
1195126258Smlaierstruct mbuf *
1196130613Smlaierpfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
1197126258Smlaier{
1198126258Smlaier	struct pfsync_header *h;
1199126258Smlaier	struct mbuf *m;
1200126258Smlaier	int len;
1201126258Smlaier
1202130613Smlaier#ifdef __FreeBSD__
1203130613Smlaier	PF_ASSERT(MA_OWNED);
1204130613Smlaier#endif
1205126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
1206126258Smlaier	if (m == NULL) {
1207141584Smlaier#ifdef __FreeBSD__
1208141584Smlaier		SCP2IFP(sc)->if_oerrors++;
1209141584Smlaier#else
1210126258Smlaier		sc->sc_if.if_oerrors++;
1211141584Smlaier#endif
1212126258Smlaier		return (NULL);
1213126258Smlaier	}
1214126258Smlaier
1215130613Smlaier	switch (action) {
1216130613Smlaier	case PFSYNC_ACT_CLR:
1217130613Smlaier		len = sizeof(struct pfsync_header) +
1218130613Smlaier		    sizeof(struct pfsync_state_clr);
1219130613Smlaier		break;
1220130613Smlaier	case PFSYNC_ACT_UPD_C:
1221130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) +
1222130613Smlaier		    sizeof(struct pfsync_header);
1223130613Smlaier		break;
1224130613Smlaier	case PFSYNC_ACT_DEL_C:
1225130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) +
1226130613Smlaier		    sizeof(struct pfsync_header);
1227130613Smlaier		break;
1228130613Smlaier	case PFSYNC_ACT_UREQ:
1229130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) +
1230130613Smlaier		    sizeof(struct pfsync_header);
1231130613Smlaier		break;
1232130613Smlaier	case PFSYNC_ACT_BUS:
1233130613Smlaier		len = sizeof(struct pfsync_header) +
1234130613Smlaier		    sizeof(struct pfsync_state_bus);
1235130613Smlaier		break;
1236130613Smlaier	default:
1237130613Smlaier		len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
1238130613Smlaier		    sizeof(struct pfsync_header);
1239130613Smlaier		break;
1240130613Smlaier	}
1241130613Smlaier
1242126258Smlaier	if (len > MHLEN) {
1243126258Smlaier		MCLGET(m, M_DONTWAIT);
1244126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
1245126258Smlaier			m_free(m);
1246141584Smlaier#ifdef __FreeBSD__
1247141584Smlaier			SCP2IFP(sc)->if_oerrors++;
1248141584Smlaier#else
1249126258Smlaier			sc->sc_if.if_oerrors++;
1250141584Smlaier#endif
1251126258Smlaier			return (NULL);
1252126258Smlaier		}
1253130613Smlaier		m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
1254130613Smlaier	} else
1255130613Smlaier		MH_ALIGN(m, len);
1256130613Smlaier
1257126258Smlaier	m->m_pkthdr.rcvif = NULL;
1258130613Smlaier	m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
1259126258Smlaier	h = mtod(m, struct pfsync_header *);
1260126258Smlaier	h->version = PFSYNC_VERSION;
1261126258Smlaier	h->af = 0;
1262126258Smlaier	h->count = 0;
1263126258Smlaier	h->action = action;
1264126258Smlaier
1265130613Smlaier	*sp = (void *)((char *)h + PFSYNC_HDRLEN);
1266127145Smlaier#ifdef __FreeBSD__
1267126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
1268126261Smlaier	    LIST_FIRST(&pfsync_list));
1269126261Smlaier#else
1270126258Smlaier	timeout_add(&sc->sc_tmo, hz);
1271126261Smlaier#endif
1272126258Smlaier	return (m);
1273126258Smlaier}
1274126258Smlaier
1275126258Smlaierint
1276145836Smlaierpfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
1277126258Smlaier{
1278127145Smlaier#ifdef __FreeBSD__
1279141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1280126261Smlaier#else
1281126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1282130613Smlaier#endif
1283126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1284130613Smlaier	struct pfsync_header *h, *h_net;
1285130613Smlaier	struct pfsync_state *sp = NULL;
1286130613Smlaier	struct pfsync_state_upd *up = NULL;
1287130613Smlaier	struct pfsync_state_del *dp = NULL;
1288130613Smlaier	struct pf_rule *r;
1289126258Smlaier	u_long secs;
1290130613Smlaier	int s, ret = 0;
1291130613Smlaier	u_int8_t i = 255, newaction = 0;
1292126258Smlaier
1293130613Smlaier#ifdef __FreeBSD__
1294130613Smlaier	PF_ASSERT(MA_OWNED);
1295130613Smlaier#endif
1296130613Smlaier	/*
1297130613Smlaier	 * If a packet falls in the forest and there's nobody around to
1298130613Smlaier	 * hear, does it make a sound?
1299130613Smlaier	 */
1300145836Smlaier	if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
1301145836Smlaier	    sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
1302130613Smlaier		/* Don't leave any stale pfsync packets hanging around. */
1303130613Smlaier		if (sc->sc_mbuf != NULL) {
1304130613Smlaier			m_freem(sc->sc_mbuf);
1305130613Smlaier			sc->sc_mbuf = NULL;
1306130613Smlaier			sc->sc_statep.s = NULL;
1307130613Smlaier		}
1308130613Smlaier		return (0);
1309130613Smlaier	}
1310130613Smlaier
1311126258Smlaier	if (action >= PFSYNC_ACT_MAX)
1312126258Smlaier		return (EINVAL);
1313126258Smlaier
1314126258Smlaier	s = splnet();
1315130613Smlaier	if (sc->sc_mbuf == NULL) {
1316130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1317130613Smlaier		    (void *)&sc->sc_statep.s)) == NULL) {
1318126258Smlaier			splx(s);
1319126258Smlaier			return (ENOMEM);
1320126258Smlaier		}
1321130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1322126258Smlaier	} else {
1323130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1324126258Smlaier		if (h->action != action) {
1325126258Smlaier			pfsync_sendout(sc);
1326130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
1327130613Smlaier			    (void *)&sc->sc_statep.s)) == NULL) {
1328126258Smlaier				splx(s);
1329126258Smlaier				return (ENOMEM);
1330126258Smlaier			}
1331130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1332130613Smlaier		} else {
1333130613Smlaier			/*
1334130613Smlaier			 * If it's an update, look in the packet to see if
1335130613Smlaier			 * we already have an update for the state.
1336130613Smlaier			 */
1337130613Smlaier			if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
1338130613Smlaier				struct pfsync_state *usp =
1339130613Smlaier				    (void *)((char *)h + PFSYNC_HDRLEN);
1340130613Smlaier
1341130613Smlaier				for (i = 0; i < h->count; i++) {
1342130613Smlaier					if (!memcmp(usp->id, &st->id,
1343130613Smlaier					    PFSYNC_ID_LEN) &&
1344130613Smlaier					    usp->creatorid == st->creatorid) {
1345130613Smlaier						sp = usp;
1346130613Smlaier						sp->updates++;
1347130613Smlaier						break;
1348130613Smlaier					}
1349130613Smlaier					usp++;
1350130613Smlaier				}
1351130613Smlaier			}
1352126258Smlaier		}
1353126258Smlaier	}
1354126258Smlaier
1355130613Smlaier	secs = time_second;
1356126258Smlaier
1357130613Smlaier	st->pfsync_time = time_uptime;
1358130613Smlaier	TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
1359130613Smlaier	TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
1360130613Smlaier
1361130613Smlaier	if (sp == NULL) {
1362130613Smlaier		/* not a "duplicate" update */
1363130613Smlaier		i = 255;
1364130613Smlaier		sp = sc->sc_statep.s++;
1365130613Smlaier		sc->sc_mbuf->m_pkthdr.len =
1366130613Smlaier		    sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
1367130613Smlaier		h->count++;
1368130613Smlaier		bzero(sp, sizeof(*sp));
1369130613Smlaier
1370130613Smlaier		bcopy(&st->id, sp->id, sizeof(sp->id));
1371130613Smlaier		sp->creatorid = st->creatorid;
1372130613Smlaier
1373130613Smlaier		strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname));
1374130613Smlaier		pf_state_host_hton(&st->lan, &sp->lan);
1375130613Smlaier		pf_state_host_hton(&st->gwy, &sp->gwy);
1376130613Smlaier		pf_state_host_hton(&st->ext, &sp->ext);
1377130613Smlaier
1378130613Smlaier		bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
1379130613Smlaier
1380130613Smlaier		sp->creation = htonl(secs - st->creation);
1381130613Smlaier		sp->packets[0] = htonl(st->packets[0]);
1382130613Smlaier		sp->packets[1] = htonl(st->packets[1]);
1383130613Smlaier		sp->bytes[0] = htonl(st->bytes[0]);
1384130613Smlaier		sp->bytes[1] = htonl(st->bytes[1]);
1385130613Smlaier		if ((r = st->rule.ptr) == NULL)
1386130613Smlaier			sp->rule = htonl(-1);
1387130613Smlaier		else
1388130613Smlaier			sp->rule = htonl(r->nr);
1389130613Smlaier		if ((r = st->anchor.ptr) == NULL)
1390130613Smlaier			sp->anchor = htonl(-1);
1391130613Smlaier		else
1392130613Smlaier			sp->anchor = htonl(r->nr);
1393130613Smlaier		sp->af = st->af;
1394130613Smlaier		sp->proto = st->proto;
1395130613Smlaier		sp->direction = st->direction;
1396130613Smlaier		sp->log = st->log;
1397130613Smlaier		sp->allow_opts = st->allow_opts;
1398130613Smlaier		sp->timeout = st->timeout;
1399130613Smlaier
1400145836Smlaier		if (flags & PFSYNC_FLAG_STALE)
1401145836Smlaier			sp->sync_flags |= PFSTATE_STALE;
1402130613Smlaier	}
1403130613Smlaier
1404126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
1405126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
1406126258Smlaier
1407126258Smlaier	if (st->expire <= secs)
1408126258Smlaier		sp->expire = htonl(0);
1409126258Smlaier	else
1410126258Smlaier		sp->expire = htonl(st->expire - secs);
1411126258Smlaier
1412130613Smlaier	/* do we need to build "compressed" actions for network transfer? */
1413145836Smlaier	if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) {
1414130613Smlaier		switch (action) {
1415130613Smlaier		case PFSYNC_ACT_UPD:
1416130613Smlaier			newaction = PFSYNC_ACT_UPD_C;
1417130613Smlaier			break;
1418130613Smlaier		case PFSYNC_ACT_DEL:
1419130613Smlaier			newaction = PFSYNC_ACT_DEL_C;
1420130613Smlaier			break;
1421130613Smlaier		default:
1422130613Smlaier			/* by default we just send the uncompressed states */
1423130613Smlaier			break;
1424130613Smlaier		}
1425130613Smlaier	}
1426130613Smlaier
1427130613Smlaier	if (newaction) {
1428130613Smlaier		if (sc->sc_mbuf_net == NULL) {
1429130613Smlaier			if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
1430130613Smlaier			    (void *)&sc->sc_statep_net.s)) == NULL) {
1431130613Smlaier				splx(s);
1432130613Smlaier				return (ENOMEM);
1433130613Smlaier			}
1434130613Smlaier		}
1435130613Smlaier		h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
1436130613Smlaier
1437130613Smlaier		switch (newaction) {
1438130613Smlaier		case PFSYNC_ACT_UPD_C:
1439130613Smlaier			if (i != 255) {
1440130613Smlaier				up = (void *)((char *)h_net +
1441130613Smlaier				    PFSYNC_HDRLEN + (i * sizeof(*up)));
1442130613Smlaier				up->updates++;
1443130613Smlaier			} else {
1444130613Smlaier				h_net->count++;
1445130613Smlaier				sc->sc_mbuf_net->m_pkthdr.len =
1446130613Smlaier				    sc->sc_mbuf_net->m_len += sizeof(*up);
1447130613Smlaier				up = sc->sc_statep_net.u++;
1448130613Smlaier
1449130613Smlaier				bzero(up, sizeof(*up));
1450130613Smlaier				bcopy(&st->id, up->id, sizeof(up->id));
1451130613Smlaier				up->creatorid = st->creatorid;
1452130613Smlaier			}
1453130613Smlaier			up->timeout = st->timeout;
1454130613Smlaier			up->expire = sp->expire;
1455130613Smlaier			up->src = sp->src;
1456130613Smlaier			up->dst = sp->dst;
1457130613Smlaier			break;
1458130613Smlaier		case PFSYNC_ACT_DEL_C:
1459130613Smlaier			sc->sc_mbuf_net->m_pkthdr.len =
1460130613Smlaier			    sc->sc_mbuf_net->m_len += sizeof(*dp);
1461130613Smlaier			dp = sc->sc_statep_net.d++;
1462130613Smlaier			h_net->count++;
1463130613Smlaier
1464130613Smlaier			bzero(dp, sizeof(*dp));
1465130613Smlaier			bcopy(&st->id, dp->id, sizeof(dp->id));
1466130613Smlaier			dp->creatorid = st->creatorid;
1467130613Smlaier			break;
1468130613Smlaier		}
1469130613Smlaier	}
1470130613Smlaier
1471130613Smlaier	if (h->count == sc->sc_maxcount ||
1472130613Smlaier	    (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
1473126258Smlaier		ret = pfsync_sendout(sc);
1474126258Smlaier
1475126258Smlaier	splx(s);
1476130613Smlaier	return (ret);
1477126258Smlaier}
1478126258Smlaier
1479130613Smlaier/* This must be called in splnet() */
1480126258Smlaierint
1481130613Smlaierpfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
1482126258Smlaier{
1483127145Smlaier#ifdef __FreeBSD__
1484141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1485126261Smlaier#else
1486126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1487130613Smlaier#endif
1488130613Smlaier	struct pfsync_header *h;
1489126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1490130613Smlaier	struct pfsync_state_upd_req *rup;
1491145836Smlaier	int ret = 0;
1492130613Smlaier
1493130613Smlaier#ifdef __FreeBSD__
1494130613Smlaier	PF_ASSERT(MA_OWNED);
1495126261Smlaier#endif
1496130613Smlaier	if (sc->sc_mbuf == NULL) {
1497130613Smlaier		if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1498145836Smlaier		    (void *)&sc->sc_statep.s)) == NULL)
1499130613Smlaier			return (ENOMEM);
1500130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1501130613Smlaier	} else {
1502130613Smlaier		h = mtod(sc->sc_mbuf, struct pfsync_header *);
1503130613Smlaier		if (h->action != PFSYNC_ACT_UREQ) {
1504130613Smlaier			pfsync_sendout(sc);
1505130613Smlaier			if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
1506145836Smlaier			    (void *)&sc->sc_statep.s)) == NULL)
1507130613Smlaier				return (ENOMEM);
1508130613Smlaier			h = mtod(sc->sc_mbuf, struct pfsync_header *);
1509130613Smlaier		}
1510130613Smlaier	}
1511130613Smlaier
1512130613Smlaier	if (src != NULL)
1513130613Smlaier		sc->sc_sendaddr = *src;
1514130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
1515130613Smlaier	h->count++;
1516130613Smlaier	rup = sc->sc_statep.r++;
1517130613Smlaier	bzero(rup, sizeof(*rup));
1518130613Smlaier	if (up != NULL) {
1519130613Smlaier		bcopy(up->id, rup->id, sizeof(rup->id));
1520130613Smlaier		rup->creatorid = up->creatorid;
1521130613Smlaier	}
1522130613Smlaier
1523130613Smlaier	if (h->count == sc->sc_maxcount)
1524130613Smlaier		ret = pfsync_sendout(sc);
1525130613Smlaier
1526130613Smlaier	return (ret);
1527130613Smlaier}
1528130613Smlaier
1529130613Smlaierint
1530130613Smlaierpfsync_clear_states(u_int32_t creatorid, char *ifname)
1531130613Smlaier{
1532130613Smlaier#ifdef __FreeBSD__
1533141584Smlaier	struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
1534130613Smlaier#else
1535130613Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
1536130613Smlaier#endif
1537130613Smlaier	struct pfsync_softc *sc = ifp->if_softc;
1538130613Smlaier	struct pfsync_state_clr *cp;
1539126258Smlaier	int s, ret;
1540126258Smlaier
1541126258Smlaier	s = splnet();
1542130613Smlaier#ifdef __FreeBSD__
1543130613Smlaier	PF_ASSERT(MA_OWNED);
1544130613Smlaier#endif
1545130613Smlaier	if (sc->sc_mbuf != NULL)
1546130613Smlaier		pfsync_sendout(sc);
1547130613Smlaier	if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
1548130613Smlaier	    (void *)&sc->sc_statep.c)) == NULL) {
1549126258Smlaier		splx(s);
1550126258Smlaier		return (ENOMEM);
1551126258Smlaier	}
1552130613Smlaier	sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
1553130613Smlaier	cp = sc->sc_statep.c;
1554130613Smlaier	cp->creatorid = creatorid;
1555130613Smlaier	if (ifname != NULL)
1556130613Smlaier		strlcpy(cp->ifname, ifname, IFNAMSIZ);
1557126258Smlaier
1558126258Smlaier	ret = (pfsync_sendout(sc));
1559126258Smlaier	splx(s);
1560126258Smlaier	return (ret);
1561126258Smlaier}
1562126258Smlaier
1563126258Smlaiervoid
1564126258Smlaierpfsync_timeout(void *v)
1565126258Smlaier{
1566126258Smlaier	struct pfsync_softc *sc = v;
1567126258Smlaier	int s;
1568126258Smlaier
1569126258Smlaier	s = splnet();
1570130613Smlaier#ifdef __FreeBSD__
1571130613Smlaier	PF_LOCK();
1572130613Smlaier#endif
1573126258Smlaier	pfsync_sendout(sc);
1574130613Smlaier#ifdef __FreeBSD__
1575130613Smlaier	PF_UNLOCK();
1576130613Smlaier#endif
1577126258Smlaier	splx(s);
1578126258Smlaier}
1579126258Smlaier
1580145836Smlaier/* This must be called in splnet() */
1581130613Smlaiervoid
1582130613Smlaierpfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
1583130613Smlaier{
1584130613Smlaier	struct pfsync_state_bus *bus;
1585130613Smlaier
1586130613Smlaier#ifdef __FreeBSD__
1587130613Smlaier	PF_ASSERT(MA_OWNED);
1588130613Smlaier#endif
1589130613Smlaier	if (sc->sc_mbuf != NULL)
1590130613Smlaier		pfsync_sendout(sc);
1591130613Smlaier
1592130613Smlaier	if (pfsync_sync_ok &&
1593130613Smlaier	    (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS,
1594130613Smlaier	    (void *)&sc->sc_statep.b)) != NULL) {
1595130613Smlaier		sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus);
1596130613Smlaier		bus = sc->sc_statep.b;
1597130613Smlaier		bus->creatorid = pf_status.hostid;
1598130613Smlaier		bus->status = status;
1599130613Smlaier		bus->endtime = htonl(time_uptime - sc->sc_ureq_received);
1600130613Smlaier		pfsync_sendout(sc);
1601130613Smlaier	}
1602130613Smlaier}
1603130613Smlaier
1604130613Smlaiervoid
1605130613Smlaierpfsync_bulk_update(void *v)
1606130613Smlaier{
1607130613Smlaier	struct pfsync_softc *sc = v;
1608130613Smlaier	int s, i = 0;
1609130613Smlaier	struct pf_state *state;
1610130613Smlaier
1611130613Smlaier#ifdef __FreeBSD__
1612130613Smlaier	PF_LOCK();
1613130613Smlaier#endif
1614130613Smlaier	s = splnet();
1615130613Smlaier	if (sc->sc_mbuf != NULL)
1616130613Smlaier		pfsync_sendout(sc);
1617130613Smlaier
1618130613Smlaier	/*
1619130613Smlaier	 * Grab at most PFSYNC_BULKPACKETS worth of states which have not
1620130613Smlaier	 * been sent since the latest request was made.
1621130613Smlaier	 */
1622130613Smlaier	while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
1623130613Smlaier	    ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
1624130613Smlaier		if (state->pfsync_time > sc->sc_ureq_received) {
1625130613Smlaier			/* we're done */
1626130613Smlaier			pfsync_send_bus(sc, PFSYNC_BUS_END);
1627130613Smlaier			sc->sc_ureq_received = 0;
1628130613Smlaier#ifdef __FreeBSD__
1629130613Smlaier			callout_stop(&sc->sc_bulk_tmo);
1630130613Smlaier#else
1631130613Smlaier			timeout_del(&sc->sc_bulk_tmo);
1632130613Smlaier#endif
1633130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1634130613Smlaier				printf("pfsync: bulk update complete\n");
1635130613Smlaier			break;
1636130613Smlaier		} else {
1637130613Smlaier			/* send an update and move to end of list */
1638130613Smlaier			if (!state->sync_flags)
1639130613Smlaier				pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
1640130613Smlaier			state->pfsync_time = time_uptime;
1641130613Smlaier			TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
1642130613Smlaier			TAILQ_INSERT_TAIL(&state_updates, state,
1643130613Smlaier			    u.s.entry_updates);
1644130613Smlaier
1645130613Smlaier			/* look again for more in a bit */
1646130613Smlaier#ifdef __FreeBSD__
1647130613Smlaier			callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
1648130613Smlaier			    LIST_FIRST(&pfsync_list));
1649130613Smlaier#else
1650130613Smlaier			timeout_add(&sc->sc_bulk_tmo, 1);
1651130613Smlaier#endif
1652130613Smlaier		}
1653130613Smlaier	}
1654130613Smlaier	if (sc->sc_mbuf != NULL)
1655130613Smlaier		pfsync_sendout(sc);
1656130613Smlaier	splx(s);
1657130613Smlaier#ifdef __FreeBSD__
1658130613Smlaier	PF_UNLOCK();
1659130613Smlaier#endif
1660130613Smlaier}
1661130613Smlaier
1662130613Smlaiervoid
1663130613Smlaierpfsync_bulkfail(void *v)
1664130613Smlaier{
1665130613Smlaier	struct pfsync_softc *sc = v;
1666145836Smlaier	int s, error;
1667130613Smlaier
1668130613Smlaier#ifdef __FreeBSD__
1669130613Smlaier	PF_LOCK();
1670130613Smlaier#endif
1671130613Smlaier	if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) {
1672130613Smlaier		/* Try again in a bit */
1673130613Smlaier#ifdef __FreeBSD__
1674130613Smlaier		callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
1675130613Smlaier		    LIST_FIRST(&pfsync_list));
1676130613Smlaier#else
1677130613Smlaier		timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
1678130613Smlaier#endif
1679145836Smlaier		s = splnet();
1680145836Smlaier		error = pfsync_request_update(NULL, NULL);
1681145836Smlaier		if (error == ENOMEM) {
1682145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
1683145836Smlaier				printf("pfsync: cannot allocate mbufs for "
1684145836Smlaier				    "bulk update\n");
1685145836Smlaier		} else
1686145836Smlaier			pfsync_sendout(sc);
1687145836Smlaier		splx(s);
1688130613Smlaier	} else {
1689130613Smlaier		/* Pretend like the transfer was ok */
1690130613Smlaier		sc->sc_ureq_sent = 0;
1691130613Smlaier		sc->sc_bulk_tries = 0;
1692145836Smlaier#if NCARP > 0
1693145836Smlaier		if (!pfsync_sync_ok)
1694145836Smlaier			carp_suppress_preempt--;
1695145836Smlaier#endif
1696130613Smlaier		pfsync_sync_ok = 1;
1697130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
1698130613Smlaier			printf("pfsync: failed to receive "
1699130613Smlaier			    "bulk update status\n");
1700130613Smlaier#ifdef __FreeBSD__
1701130613Smlaier		callout_stop(&sc->sc_bulkfail_tmo);
1702130613Smlaier#else
1703130613Smlaier		timeout_del(&sc->sc_bulkfail_tmo);
1704130613Smlaier#endif
1705130613Smlaier	}
1706130613Smlaier#ifdef __FreeBSD__
1707130613Smlaier	PF_UNLOCK();
1708130613Smlaier#endif
1709130613Smlaier}
1710130613Smlaier
1711145836Smlaier/* This must be called in splnet() */
1712126258Smlaierint
1713126258Smlaierpfsync_sendout(sc)
1714126258Smlaier	struct pfsync_softc *sc;
1715126258Smlaier{
1716138666Smlaier#if NBPFILTER > 0
1717141584Smlaier# ifdef __FreeBSD__
1718141584Smlaier	struct ifnet *ifp = SCP2IFP(sc);
1719141584Smlaier# else
1720141584Smlaier	struct ifnet *ifp = &sc->if_sc;
1721141584Smlaier# endif
1722138666Smlaier#endif
1723130613Smlaier	struct mbuf *m;
1724126258Smlaier
1725127145Smlaier#ifdef __FreeBSD__
1726130613Smlaier	PF_ASSERT(MA_OWNED);
1727126261Smlaier	callout_stop(&sc->sc_tmo);
1728126261Smlaier#else
1729126258Smlaier	timeout_del(&sc->sc_tmo);
1730126261Smlaier#endif
1731130613Smlaier
1732130613Smlaier	if (sc->sc_mbuf == NULL)
1733130613Smlaier		return (0);
1734130613Smlaier	m = sc->sc_mbuf;
1735126258Smlaier	sc->sc_mbuf = NULL;
1736130613Smlaier	sc->sc_statep.s = NULL;
1737126258Smlaier
1738127145Smlaier#ifdef __FreeBSD__
1739126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
1740126261Smlaier#endif
1741126258Smlaier#if NBPFILTER > 0
1742126258Smlaier	if (ifp->if_bpf)
1743126258Smlaier		bpf_mtap(ifp->if_bpf, m);
1744126258Smlaier#endif
1745126258Smlaier
1746130613Smlaier	if (sc->sc_mbuf_net) {
1747130613Smlaier		m_freem(m);
1748130613Smlaier		m = sc->sc_mbuf_net;
1749130613Smlaier		sc->sc_mbuf_net = NULL;
1750130613Smlaier		sc->sc_statep_net.s = NULL;
1751130613Smlaier	}
1752126258Smlaier
1753145836Smlaier	if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
1754130613Smlaier		struct ip *ip;
1755130613Smlaier		struct sockaddr sa;
1756130613Smlaier
1757130613Smlaier		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
1758130613Smlaier		if (m == NULL) {
1759130613Smlaier			pfsyncstats.pfsyncs_onomem++;
1760130613Smlaier			return (0);
1761130613Smlaier		}
1762130613Smlaier		ip = mtod(m, struct ip *);
1763130613Smlaier		ip->ip_v = IPVERSION;
1764130613Smlaier		ip->ip_hl = sizeof(*ip) >> 2;
1765130613Smlaier		ip->ip_tos = IPTOS_LOWDELAY;
1766130613Smlaier#ifdef __FreeBSD__
1767130613Smlaier		ip->ip_len = m->m_pkthdr.len;
1768130613Smlaier#else
1769130613Smlaier		ip->ip_len = htons(m->m_pkthdr.len);
1770130613Smlaier#endif
1771130613Smlaier		ip->ip_id = htons(ip_randomid());
1772130613Smlaier#ifdef __FreeBSD__
1773130613Smlaier		ip->ip_off = IP_DF;
1774130613Smlaier#else
1775130613Smlaier		ip->ip_off = htons(IP_DF);
1776130613Smlaier#endif
1777130613Smlaier		ip->ip_ttl = PFSYNC_DFLTTL;
1778130613Smlaier		ip->ip_p = IPPROTO_PFSYNC;
1779130613Smlaier		ip->ip_sum = 0;
1780130613Smlaier
1781130613Smlaier		bzero(&sa, sizeof(sa));
1782145836Smlaier		ip->ip_src.s_addr = INADDR_ANY;
1783130613Smlaier
1784130613Smlaier#ifdef __FreeBSD__
1785130613Smlaier		if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP))
1786130613Smlaier#else
1787130613Smlaier		if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
1788130613Smlaier#endif
1789130613Smlaier			m->m_flags |= M_MCAST;
1790130613Smlaier		ip->ip_dst = sc->sc_sendaddr;
1791130613Smlaier#ifdef __FreeBSD__
1792145836Smlaier		/* XXX_IMPORT */
1793145836Smlaier		sc->sc_sendaddr.s_addr = htonl(sc->sc_sync_peer.s_addr);
1794130613Smlaier#else
1795145836Smlaier		sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
1796130613Smlaier#endif
1797130613Smlaier
1798130613Smlaier		pfsyncstats.pfsyncs_opackets++;
1799130613Smlaier#ifdef __FreeBSD__
1800147261Smlaier		if (IF_HANDOFF(&sc->sc_ifq, m, NULL))
1801147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1802147261Smlaier		callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
1803147261Smlaier#else
1804130613Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1805130613Smlaier			pfsyncstats.pfsyncs_oerrors++;
1806130613Smlaier#endif
1807130613Smlaier	} else
1808130613Smlaier		m_freem(m);
1809130613Smlaier
1810126258Smlaier	return (0);
1811126258Smlaier}
1812126261Smlaier
1813147261Smlaier#ifdef __FreeBSD__
1814147261Smlaierstatic void
1815147261Smlaierpfsync_senddef(void *arg)
1816147261Smlaier{
1817147261Smlaier	struct pfsync_softc *sc = (struct pfsync_softc *)arg;
1818147261Smlaier	struct mbuf *m;
1819126261Smlaier
1820147261Smlaier	for(;;) {
1821147261Smlaier		IF_DEQUEUE(&sc->sc_ifq, m);
1822147261Smlaier		if (m == NULL)
1823147261Smlaier			break;
1824147261Smlaier		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
1825147261Smlaier			pfsyncstats.pfsyncs_oerrors++;
1826147261Smlaier	}
1827147261Smlaier}
1828147261Smlaier
1829126261Smlaierstatic int
1830126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
1831126261Smlaier{
1832126261Smlaier	int error = 0;
1833126261Smlaier
1834126261Smlaier	switch (type) {
1835126261Smlaier	case MOD_LOAD:
1836126261Smlaier		LIST_INIT(&pfsync_list);
1837126261Smlaier		if_clone_attach(&pfsync_cloner);
1838126261Smlaier		break;
1839126261Smlaier
1840126261Smlaier	case MOD_UNLOAD:
1841126261Smlaier		if_clone_detach(&pfsync_cloner);
1842126261Smlaier		while (!LIST_EMPTY(&pfsync_list))
1843126261Smlaier			pfsync_clone_destroy(
1844141584Smlaier			    SCP2IFP(LIST_FIRST(&pfsync_list)));
1845126261Smlaier		break;
1846126261Smlaier
1847126261Smlaier	default:
1848126261Smlaier		error = EINVAL;
1849126261Smlaier		break;
1850126261Smlaier	}
1851126261Smlaier
1852126261Smlaier	return error;
1853126261Smlaier}
1854126261Smlaier
1855126261Smlaierstatic moduledata_t pfsync_mod = {
1856126261Smlaier	"pfsync",
1857126261Smlaier	pfsync_modevent,
1858126261Smlaier	0
1859126261Smlaier};
1860126261Smlaier
1861126261Smlaier#define PFSYNC_MODVER 1
1862126261Smlaier
1863135196SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1864126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
1865126261Smlaier#endif /* __FreeBSD__ */
1866