if_pfsync.c revision 126261
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 126261 2004-02-26 02:34:12Z mlaier $	*/
2126258Smlaier/*	$OpenBSD: if_pfsync.c,v 1.6 2003/06/21 09:07:01 djm 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
30126261Smlaier#if defined(__FreeBSD__) && __FreeBSD__ >= 5
31126261Smlaier#include "opt_inet.h"
32126261Smlaier#include "opt_inet6.h"
33126261Smlaier#endif
34126261Smlaier
35126261Smlaier#if !defined(__FreeBSD__)
36126258Smlaier#include "bpfilter.h"
37126258Smlaier#include "pfsync.h"
38126261Smlaier#elif __FreeBSD__ >= 5
39126261Smlaier#include "opt_bpf.h"
40126261Smlaier#define NBPFILTER DEV_BPF
41126261Smlaier#include "opt_pf.h"
42126261Smlaier#define NPFSYNC DEV_PFSYNC
43126261Smlaier#endif
44126258Smlaier
45126258Smlaier#include <sys/param.h>
46126258Smlaier#include <sys/systm.h>
47126258Smlaier#include <sys/time.h>
48126258Smlaier#include <sys/mbuf.h>
49126258Smlaier#include <sys/socket.h>
50126261Smlaier#if defined(__FreeBSD__)
51126261Smlaier#include <sys/kernel.h>
52126261Smlaier#include <sys/malloc.h>
53126261Smlaier#include <sys/sockio.h>
54126261Smlaier#else
55126258Smlaier#include <sys/ioctl.h>
56126258Smlaier#include <sys/timeout.h>
57126261Smlaier#endif
58126258Smlaier
59126258Smlaier#include <net/if.h>
60126258Smlaier#include <net/if_types.h>
61126258Smlaier#include <net/route.h>
62126258Smlaier#include <net/bpf.h>
63126258Smlaier
64126258Smlaier#ifdef	INET
65126258Smlaier#include <netinet/in.h>
66126258Smlaier#include <netinet/in_var.h>
67126258Smlaier#endif
68126258Smlaier
69126258Smlaier#ifdef INET6
70126258Smlaier#ifndef INET
71126258Smlaier#include <netinet/in.h>
72126258Smlaier#endif
73126258Smlaier#include <netinet6/nd6.h>
74126258Smlaier#endif /* INET6 */
75126258Smlaier
76126258Smlaier#include <net/pfvar.h>
77126258Smlaier#include <net/if_pfsync.h>
78126258Smlaier
79126261Smlaier#if defined(__FreeBSD__)
80126261Smlaier#define PFSYNCNAME	"pfsync"
81126261Smlaier#endif
82126261Smlaier
83126258Smlaier#define PFSYNC_MINMTU	\
84126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
85126258Smlaier
86126258Smlaier#ifdef PFSYNCDEBUG
87126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
88126258Smlaierint pfsyncdebug;
89126258Smlaier#else
90126258Smlaier#define DPRINTF(x)
91126258Smlaier#endif
92126258Smlaier
93126261Smlaier#if !defined(__FreeBSD__)
94126258Smlaierstruct pfsync_softc pfsyncif;
95126261Smlaier#endif
96126258Smlaier
97126261Smlaier#if defined(__FreeBSD__)
98126261Smlaiervoid	pfsync_clone_destroy(struct ifnet *);
99126261Smlaierint	pfsync_clone_create(struct if_clone *, int);
100126261Smlaier#else
101126258Smlaiervoid	pfsyncattach(int);
102126261Smlaier#endif
103126258Smlaiervoid	pfsync_setmtu(struct pfsync_softc *sc, int);
104126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
105126258Smlaier	       struct rtentry *);
106126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
107126258Smlaiervoid	pfsyncstart(struct ifnet *);
108126258Smlaier
109126258Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action);
110126258Smlaierint	pfsync_sendout(struct pfsync_softc *sc);
111126258Smlaiervoid	pfsync_timeout(void *v);
112126258Smlaier
113126261Smlaier#if !defined(__FreeBSD__)
114126258Smlaierextern int ifqmaxlen;
115126261Smlaier#endif
116126258Smlaier
117126261Smlaier#if defined(__FreeBSD__)
118126261Smlaierstatic MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
119126261Smlaierstatic LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
120126261Smlaierstruct if_clone pfsync_cloner = IF_CLONE_INITIALIZER(PFSYNCNAME,
121126261Smlaier	pfsync_clone_create, pfsync_clone_destroy, 1, IF_MAXUNIT);
122126261Smlaier
123126258Smlaiervoid
124126261Smlaierpfsync_clone_destroy(struct ifnet *ifp)
125126261Smlaier{
126126261Smlaier        struct pfsync_softc *sc;
127126261Smlaier
128126261Smlaier        sc = ifp->if_softc;
129126261Smlaier	callout_stop(&sc->sc_tmo);
130126261Smlaier
131126261Smlaier	/*
132126261Smlaier	 * Does we really need this?
133126261Smlaier	 */
134126261Smlaier	IF_DRAIN(&ifp->if_snd);
135126261Smlaier
136126261Smlaier#if NBPFILTER > 0
137126261Smlaier        bpfdetach(ifp);
138126261Smlaier#endif
139126261Smlaier        if_detach(ifp);
140126261Smlaier        LIST_REMOVE(sc, sc_next);
141126261Smlaier        free(sc, M_PFSYNC);
142126261Smlaier}
143126261Smlaier#endif /* __FreeBSD__ */
144126261Smlaier
145126261Smlaier#if defined(__FreeBSD__)
146126261Smlaierint
147126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
148126261Smlaier{
149126261Smlaier	struct pfsync_softc *sc;
150126261Smlaier
151126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
152126261Smlaier		M_WAITOK|M_ZERO);
153126261Smlaier
154126261Smlaier	sc->sc_count = 8;
155126261Smlaier#if (__FreeBSD_version < 501113)
156126261Smlaier	sc->sc_if.if_name = PFSYNCNAME;
157126261Smlaier	sc->sc_if.if_unit = unit;
158126261Smlaier#else
159126261Smlaier	if_initname(&sc->sc_if, ifc->ifc_name, unit);
160126261Smlaier#endif
161126261Smlaier	sc->sc_if.if_ioctl = pfsyncioctl;
162126261Smlaier	sc->sc_if.if_output = pfsyncoutput;
163126261Smlaier	sc->sc_if.if_start = pfsyncstart;
164126261Smlaier	sc->sc_if.if_type = IFT_PFSYNC;
165126261Smlaier	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
166126261Smlaier	sc->sc_if.if_hdrlen = PFSYNC_HDRLEN;
167126261Smlaier	sc->sc_if.if_baudrate = IF_Mbps(100);
168126261Smlaier        sc->sc_if.if_softc = sc;
169126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
170126261Smlaier	/*
171126261Smlaier	 * XXX
172126261Smlaier	 *  The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
173126261Smlaier	 * if Gaint lock is removed from the network stack.
174126261Smlaier	 */
175126261Smlaier	callout_init(&sc->sc_tmo, 0);
176126261Smlaier	if_attach(&sc->sc_if);
177126261Smlaier
178126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
179126261Smlaier#if NBPFILTER > 0
180126261Smlaier	bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
181126261Smlaier#endif
182126261Smlaier
183126261Smlaier	return (0);
184126261Smlaier}
185126261Smlaier#else /* !__FreeBSD__ */
186126261Smlaiervoid
187126258Smlaierpfsyncattach(int npfsync)
188126258Smlaier{
189126258Smlaier	struct ifnet *ifp;
190126258Smlaier
191126258Smlaier	pfsyncif.sc_mbuf = NULL;
192126258Smlaier	pfsyncif.sc_ptr = NULL;
193126258Smlaier	pfsyncif.sc_count = 8;
194126258Smlaier	ifp = &pfsyncif.sc_if;
195126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
196126258Smlaier	ifp->if_softc = &pfsyncif;
197126258Smlaier	ifp->if_ioctl = pfsyncioctl;
198126258Smlaier	ifp->if_output = pfsyncoutput;
199126258Smlaier	ifp->if_start = pfsyncstart;
200126258Smlaier	ifp->if_type = IFT_PFSYNC;
201126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
202126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
203126258Smlaier	ifp->if_baudrate = IF_Mbps(100);
204126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
205126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
206126258Smlaier	if_attach(ifp);
207126258Smlaier	if_alloc_sadl(ifp);
208126258Smlaier
209126258Smlaier#if NBPFILTER > 0
210126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
211126258Smlaier#endif
212126258Smlaier}
213126261Smlaier#endif
214126258Smlaier
215126258Smlaier/*
216126258Smlaier * Start output on the pfsync interface.
217126258Smlaier */
218126258Smlaiervoid
219126258Smlaierpfsyncstart(struct ifnet *ifp)
220126258Smlaier{
221126258Smlaier	struct mbuf *m;
222126261Smlaier#if defined(__FreeBSD__) && defined(ALTQ)
223126261Smlaier	struct ifaltq *ifq;
224126261Smlaier#else
225126261Smlaier	struct ifqueue *ifq;
226126261Smlaier#endif
227126258Smlaier	int s;
228126258Smlaier
229126261Smlaier#if defined(__FreeBSD__)
230126261Smlaier	ifq = &ifp->if_snd;
231126261Smlaier#endif
232126258Smlaier	for (;;) {
233126258Smlaier		s = splimp();
234126261Smlaier#if defined(__FreeBSD__)
235126261Smlaier		IF_LOCK(ifq);
236126261Smlaier		_IF_DROP(ifq);
237126261Smlaier		_IF_DEQUEUE(ifq, m);
238126261Smlaier		IF_UNLOCK(ifq);
239126261Smlaier#else
240126258Smlaier		IF_DROP(&ifp->if_snd);
241126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
242126261Smlaier#endif
243126258Smlaier		splx(s);
244126258Smlaier
245126258Smlaier		if (m == NULL)
246126258Smlaier			return;
247126258Smlaier		else
248126258Smlaier			m_freem(m);
249126258Smlaier	}
250126258Smlaier}
251126258Smlaier
252126258Smlaierint
253126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
254126258Smlaier	struct rtentry *rt)
255126258Smlaier{
256126258Smlaier	m_freem(m);
257126258Smlaier	return (0);
258126258Smlaier}
259126258Smlaier
260126258Smlaier/* ARGSUSED */
261126258Smlaierint
262126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
263126258Smlaier{
264126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
265126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
266126258Smlaier	int s;
267126258Smlaier
268126258Smlaier	switch (cmd) {
269126258Smlaier	case SIOCSIFADDR:
270126258Smlaier	case SIOCAIFADDR:
271126258Smlaier	case SIOCSIFDSTADDR:
272126258Smlaier	case SIOCSIFFLAGS:
273126258Smlaier		if (ifp->if_flags & IFF_UP)
274126258Smlaier			ifp->if_flags |= IFF_RUNNING;
275126258Smlaier		else
276126258Smlaier			ifp->if_flags &= ~IFF_RUNNING;
277126258Smlaier		break;
278126258Smlaier	case SIOCSIFMTU:
279126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
280126258Smlaier			return (EINVAL);
281126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
282126258Smlaier			ifr->ifr_mtu = MCLBYTES;
283126258Smlaier		s = splnet();
284126258Smlaier		if (ifr->ifr_mtu < ifp->if_mtu)
285126258Smlaier			pfsync_sendout(sc);
286126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
287126258Smlaier		splx(s);
288126258Smlaier		break;
289126258Smlaier	default:
290126258Smlaier		return (ENOTTY);
291126258Smlaier	}
292126258Smlaier
293126258Smlaier	return (0);
294126258Smlaier}
295126258Smlaier
296126258Smlaiervoid
297126258Smlaierpfsync_setmtu(sc, mtu)
298126258Smlaier	struct pfsync_softc *sc;
299126258Smlaier	int mtu;
300126258Smlaier{
301126258Smlaier	sc->sc_count = (mtu - sizeof(struct pfsync_header)) /
302126258Smlaier	    sizeof(struct pf_state);
303126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
304126258Smlaier	    sc->sc_count * sizeof(struct pf_state);
305126258Smlaier}
306126258Smlaier
307126258Smlaierstruct mbuf *
308126258Smlaierpfsync_get_mbuf(sc, action)
309126258Smlaier	struct pfsync_softc *sc;
310126258Smlaier	u_int8_t action;
311126258Smlaier{
312126261Smlaier#if !defined(__FreeBSD__)
313126258Smlaier	extern int hz;
314126261Smlaier#endif
315126258Smlaier	struct pfsync_header *h;
316126258Smlaier	struct mbuf *m;
317126258Smlaier	int len;
318126258Smlaier
319126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
320126258Smlaier	if (m == NULL) {
321126258Smlaier		sc->sc_if.if_oerrors++;
322126258Smlaier		return (NULL);
323126258Smlaier	}
324126258Smlaier
325126258Smlaier	len = sc->sc_if.if_mtu;
326126258Smlaier	if (len > MHLEN) {
327126258Smlaier		MCLGET(m, M_DONTWAIT);
328126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
329126258Smlaier			m_free(m);
330126258Smlaier			sc->sc_if.if_oerrors++;
331126258Smlaier			return (NULL);
332126258Smlaier		}
333126258Smlaier	}
334126258Smlaier	m->m_pkthdr.rcvif = NULL;
335126258Smlaier	m->m_pkthdr.len = m->m_len = len;
336126258Smlaier
337126258Smlaier	h = mtod(m, struct pfsync_header *);
338126258Smlaier	h->version = PFSYNC_VERSION;
339126258Smlaier	h->af = 0;
340126258Smlaier	h->count = 0;
341126258Smlaier	h->action = action;
342126258Smlaier
343126258Smlaier	sc->sc_mbuf = m;
344126258Smlaier	sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
345126261Smlaier#if defined(__FreeBSD__)
346126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
347126261Smlaier	    LIST_FIRST(&pfsync_list));
348126261Smlaier#else
349126258Smlaier	timeout_add(&sc->sc_tmo, hz);
350126261Smlaier#endif
351126258Smlaier
352126258Smlaier	return (m);
353126258Smlaier}
354126258Smlaier
355126261Smlaier/*
356126261Smlaier * XXX: This function should be called with PF_LOCK held as it references
357126261Smlaier * pf_state.
358126261Smlaier */
359126258Smlaierint
360126258Smlaierpfsync_pack_state(action, st)
361126258Smlaier	u_int8_t action;
362126258Smlaier	struct pf_state *st;
363126258Smlaier{
364126261Smlaier#if defined(__FreeBSD__)
365126261Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
366126261Smlaier#else
367126258Smlaier	extern struct timeval time;
368126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
369126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
370126261Smlaier#endif
371126258Smlaier	struct pfsync_header *h;
372126258Smlaier	struct pf_state *sp;
373126258Smlaier	struct pf_rule *r = st->rule.ptr;
374126258Smlaier	struct mbuf *m;
375126258Smlaier	u_long secs;
376126258Smlaier	int s, ret;
377126258Smlaier
378126258Smlaier	if (action >= PFSYNC_ACT_MAX)
379126258Smlaier		return (EINVAL);
380126258Smlaier
381126261Smlaier#if defined(__FreeBSD__)
382126261Smlaier	/*
383126261Smlaier	 * XXX
384126261Smlaier	 *  If we need to check mutex owned, PF_LOCK should be
385126261Smlaier	 * declared in pflog.ko. :-(
386126261Smlaier	 *
387126261Smlaier	 * PF_LOCK_ASSERT();
388126261Smlaier	 */
389126261Smlaier	KASSERT((!LIST_EMPTY(&pfsync_list)), ("pfsync: no interface"));
390126261Smlaier#endif
391126258Smlaier	s = splnet();
392126258Smlaier	m = sc->sc_mbuf;
393126258Smlaier	if (m == NULL) {
394126258Smlaier		if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
395126258Smlaier			splx(s);
396126258Smlaier			return (ENOMEM);
397126258Smlaier		}
398126258Smlaier		h = mtod(m, struct pfsync_header *);
399126258Smlaier	} else {
400126258Smlaier		h = mtod(m, struct pfsync_header *);
401126258Smlaier		if (h->action != action) {
402126258Smlaier			pfsync_sendout(sc);
403126258Smlaier			if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
404126258Smlaier				splx(s);
405126258Smlaier				return (ENOMEM);
406126258Smlaier			}
407126258Smlaier			h = mtod(m, struct pfsync_header *);
408126258Smlaier		}
409126258Smlaier	}
410126258Smlaier
411126258Smlaier	sp = sc->sc_ptr++;
412126258Smlaier	h->count++;
413126258Smlaier	bzero(sp, sizeof(*sp));
414126258Smlaier
415126258Smlaier	bcopy(&st->lan, &sp->lan, sizeof(sp->lan));
416126258Smlaier	bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy));
417126258Smlaier	bcopy(&st->ext, &sp->ext, sizeof(sp->ext));
418126258Smlaier
419126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
420126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
421126258Smlaier
422126258Smlaier	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
423126261Smlaier#if defined(__FreeBSD__)
424126261Smlaier	secs = time_second;
425126261Smlaier#else
426126258Smlaier	secs = time.tv_sec;
427126261Smlaier#endif
428126258Smlaier	sp->creation = htonl(secs - st->creation);
429126258Smlaier	if (st->expire <= secs)
430126258Smlaier		sp->expire = htonl(0);
431126258Smlaier	else
432126258Smlaier		sp->expire = htonl(st->expire - secs);
433126258Smlaier	sp->packets[0] = htonl(st->packets[0]);
434126258Smlaier	sp->packets[1] = htonl(st->packets[1]);
435126258Smlaier	sp->bytes[0] = htonl(st->bytes[0]);
436126258Smlaier	sp->bytes[1] = htonl(st->bytes[1]);
437126258Smlaier	if (r == NULL)
438126258Smlaier		sp->rule.nr = htonl(-1);
439126258Smlaier	else
440126258Smlaier		sp->rule.nr = htonl(r->nr);
441126258Smlaier	sp->af = st->af;
442126258Smlaier	sp->proto = st->proto;
443126258Smlaier	sp->direction = st->direction;
444126258Smlaier	sp->log = st->log;
445126258Smlaier	sp->allow_opts = st->allow_opts;
446126258Smlaier
447126258Smlaier	ret = 0;
448126258Smlaier	if (h->count == sc->sc_count)
449126258Smlaier		ret = pfsync_sendout(sc);
450126258Smlaier
451126258Smlaier	splx(s);
452126258Smlaier	return (0);
453126258Smlaier}
454126258Smlaier
455126258Smlaierint
456126258Smlaierpfsync_clear_state(st)
457126258Smlaier	struct pf_state *st;
458126258Smlaier{
459126261Smlaier#if defined(__FreeBSD__)
460126261Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
461126261Smlaier#else
462126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
463126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
464126261Smlaier#endif
465126258Smlaier	struct mbuf *m = sc->sc_mbuf;
466126258Smlaier	int s, ret;
467126258Smlaier
468126258Smlaier	s = splnet();
469126258Smlaier	if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) {
470126258Smlaier		splx(s);
471126258Smlaier		return (ENOMEM);
472126258Smlaier	}
473126258Smlaier
474126258Smlaier	ret = (pfsync_sendout(sc));
475126258Smlaier	splx(s);
476126258Smlaier	return (ret);
477126258Smlaier}
478126258Smlaier
479126258Smlaiervoid
480126258Smlaierpfsync_timeout(void *v)
481126258Smlaier{
482126258Smlaier	struct pfsync_softc *sc = v;
483126258Smlaier	int s;
484126258Smlaier
485126261Smlaier	/* We don't need PF_LOCK/PF_UNLOCK here! */
486126258Smlaier	s = splnet();
487126258Smlaier	pfsync_sendout(sc);
488126258Smlaier	splx(s);
489126258Smlaier}
490126258Smlaier
491126258Smlaierint
492126258Smlaierpfsync_sendout(sc)
493126258Smlaier	struct pfsync_softc *sc;
494126258Smlaier{
495126258Smlaier	struct ifnet *ifp = &sc->sc_if;
496126258Smlaier	struct mbuf *m = sc->sc_mbuf;
497126258Smlaier
498126261Smlaier#if defined(__FreeBSD__)
499126261Smlaier	callout_stop(&sc->sc_tmo);
500126261Smlaier#else
501126258Smlaier	timeout_del(&sc->sc_tmo);
502126261Smlaier#endif
503126258Smlaier	sc->sc_mbuf = NULL;
504126258Smlaier	sc->sc_ptr = NULL;
505126258Smlaier
506126261Smlaier#if defined(__FreeBSD__)
507126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
508126261Smlaier#endif
509126258Smlaier#if NBPFILTER > 0
510126258Smlaier	if (ifp->if_bpf)
511126258Smlaier		bpf_mtap(ifp->if_bpf, m);
512126258Smlaier#endif
513126258Smlaier
514126258Smlaier	m_freem(m);
515126258Smlaier
516126258Smlaier	return (0);
517126258Smlaier}
518126261Smlaier
519126261Smlaier
520126261Smlaier#if defined(__FreeBSD__)
521126261Smlaierstatic int
522126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
523126261Smlaier{
524126261Smlaier	int error = 0;
525126261Smlaier
526126261Smlaier	switch (type) {
527126261Smlaier	case MOD_LOAD:
528126261Smlaier		LIST_INIT(&pfsync_list);
529126261Smlaier		if_clone_attach(&pfsync_cloner);
530126261Smlaier		printf("pfsync: $Name:  $\n");
531126261Smlaier		break;
532126261Smlaier
533126261Smlaier	case MOD_UNLOAD:
534126261Smlaier		if_clone_detach(&pfsync_cloner);
535126261Smlaier		while (!LIST_EMPTY(&pfsync_list))
536126261Smlaier			pfsync_clone_destroy(
537126261Smlaier				&LIST_FIRST(&pfsync_list)->sc_if);
538126261Smlaier		break;
539126261Smlaier
540126261Smlaier	default:
541126261Smlaier		error = EINVAL;
542126261Smlaier		break;
543126261Smlaier	}
544126261Smlaier
545126261Smlaier	return error;
546126261Smlaier}
547126261Smlaier
548126261Smlaierstatic moduledata_t pfsync_mod = {
549126261Smlaier	"pfsync",
550126261Smlaier	pfsync_modevent,
551126261Smlaier	0
552126261Smlaier};
553126261Smlaier
554126261Smlaier#define PFSYNC_MODVER 1
555126261Smlaier
556126261SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
557126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
558126261Smlaier#endif /* __FreeBSD__ */
559