if_pfsync.c revision 127145
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/if_pfsync.c 127145 2004-03-17 21:11:02Z 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
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>
46126258Smlaier#include <sys/systm.h>
47126258Smlaier#include <sys/time.h>
48126258Smlaier#include <sys/mbuf.h>
49126258Smlaier#include <sys/socket.h>
50127145Smlaier#ifdef __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
79127145Smlaier#ifdef __FreeBSD__
80127145Smlaier#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
93127145Smlaier#ifndef __FreeBSD__
94126258Smlaierstruct pfsync_softc pfsyncif;
95126261Smlaier#endif
96126258Smlaier
97127145Smlaier#ifdef __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
113127145Smlaier#ifndef __FreeBSD__
114126258Smlaierextern int ifqmaxlen;
115126261Smlaier#endif
116126258Smlaier
117127145Smlaier#ifdef __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
144126261Smlaierint
145126261Smlaierpfsync_clone_create(struct if_clone *ifc, int unit)
146126261Smlaier{
147126261Smlaier	struct pfsync_softc *sc;
148126261Smlaier
149126261Smlaier	MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
150126261Smlaier		M_WAITOK|M_ZERO);
151126261Smlaier
152126261Smlaier	sc->sc_count = 8;
153126261Smlaier#if (__FreeBSD_version < 501113)
154126261Smlaier	sc->sc_if.if_name = PFSYNCNAME;
155126261Smlaier	sc->sc_if.if_unit = unit;
156126261Smlaier#else
157126261Smlaier	if_initname(&sc->sc_if, ifc->ifc_name, unit);
158126261Smlaier#endif
159126261Smlaier	sc->sc_if.if_ioctl = pfsyncioctl;
160126261Smlaier	sc->sc_if.if_output = pfsyncoutput;
161126261Smlaier	sc->sc_if.if_start = pfsyncstart;
162126261Smlaier	sc->sc_if.if_type = IFT_PFSYNC;
163126261Smlaier	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
164126261Smlaier	sc->sc_if.if_hdrlen = PFSYNC_HDRLEN;
165126261Smlaier	sc->sc_if.if_baudrate = IF_Mbps(100);
166126261Smlaier        sc->sc_if.if_softc = sc;
167126261Smlaier	pfsync_setmtu(sc, MCLBYTES);
168126261Smlaier	/*
169126261Smlaier	 * XXX
170126261Smlaier	 *  The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
171126261Smlaier	 * if Gaint lock is removed from the network stack.
172126261Smlaier	 */
173126261Smlaier	callout_init(&sc->sc_tmo, 0);
174126261Smlaier	if_attach(&sc->sc_if);
175126261Smlaier
176126261Smlaier	LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
177126261Smlaier#if NBPFILTER > 0
178126261Smlaier	bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
179126261Smlaier#endif
180126261Smlaier
181126261Smlaier	return (0);
182126261Smlaier}
183126261Smlaier#else /* !__FreeBSD__ */
184126261Smlaiervoid
185126258Smlaierpfsyncattach(int npfsync)
186126258Smlaier{
187126258Smlaier	struct ifnet *ifp;
188126258Smlaier
189126258Smlaier	pfsyncif.sc_mbuf = NULL;
190126258Smlaier	pfsyncif.sc_ptr = NULL;
191126258Smlaier	pfsyncif.sc_count = 8;
192126258Smlaier	ifp = &pfsyncif.sc_if;
193126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
194126258Smlaier	ifp->if_softc = &pfsyncif;
195126258Smlaier	ifp->if_ioctl = pfsyncioctl;
196126258Smlaier	ifp->if_output = pfsyncoutput;
197126258Smlaier	ifp->if_start = pfsyncstart;
198126258Smlaier	ifp->if_type = IFT_PFSYNC;
199126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
200126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
201126258Smlaier	ifp->if_baudrate = IF_Mbps(100);
202126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
203126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
204126258Smlaier	if_attach(ifp);
205126258Smlaier	if_alloc_sadl(ifp);
206126258Smlaier
207126258Smlaier#if NBPFILTER > 0
208126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
209126258Smlaier#endif
210126258Smlaier}
211126261Smlaier#endif
212126258Smlaier
213126258Smlaier/*
214126258Smlaier * Start output on the pfsync interface.
215126258Smlaier */
216126258Smlaiervoid
217126258Smlaierpfsyncstart(struct ifnet *ifp)
218126258Smlaier{
219126258Smlaier	struct mbuf *m;
220126261Smlaier#if defined(__FreeBSD__) && defined(ALTQ)
221126261Smlaier	struct ifaltq *ifq;
222126261Smlaier#else
223126261Smlaier	struct ifqueue *ifq;
224126261Smlaier#endif
225126258Smlaier	int s;
226126258Smlaier
227127145Smlaier#ifdef __FreeBSD__
228126261Smlaier	ifq = &ifp->if_snd;
229126261Smlaier#endif
230126258Smlaier	for (;;) {
231126258Smlaier		s = splimp();
232127145Smlaier#ifdef __FreeBSD__
233126261Smlaier		IF_LOCK(ifq);
234126261Smlaier		_IF_DROP(ifq);
235126261Smlaier		_IF_DEQUEUE(ifq, m);
236126261Smlaier		IF_UNLOCK(ifq);
237126261Smlaier#else
238126258Smlaier		IF_DROP(&ifp->if_snd);
239126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
240126261Smlaier#endif
241126258Smlaier		splx(s);
242126258Smlaier
243126258Smlaier		if (m == NULL)
244126258Smlaier			return;
245126258Smlaier		else
246126258Smlaier			m_freem(m);
247126258Smlaier	}
248126258Smlaier}
249126258Smlaier
250126258Smlaierint
251126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
252126258Smlaier	struct rtentry *rt)
253126258Smlaier{
254126258Smlaier	m_freem(m);
255126258Smlaier	return (0);
256126258Smlaier}
257126258Smlaier
258126258Smlaier/* ARGSUSED */
259126258Smlaierint
260126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
261126258Smlaier{
262126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
263126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
264126258Smlaier	int s;
265126258Smlaier
266126258Smlaier	switch (cmd) {
267126258Smlaier	case SIOCSIFADDR:
268126258Smlaier	case SIOCAIFADDR:
269126258Smlaier	case SIOCSIFDSTADDR:
270126258Smlaier	case SIOCSIFFLAGS:
271126258Smlaier		if (ifp->if_flags & IFF_UP)
272126258Smlaier			ifp->if_flags |= IFF_RUNNING;
273126258Smlaier		else
274126258Smlaier			ifp->if_flags &= ~IFF_RUNNING;
275126258Smlaier		break;
276126258Smlaier	case SIOCSIFMTU:
277126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
278126258Smlaier			return (EINVAL);
279126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
280126258Smlaier			ifr->ifr_mtu = MCLBYTES;
281126258Smlaier		s = splnet();
282126258Smlaier		if (ifr->ifr_mtu < ifp->if_mtu)
283126258Smlaier			pfsync_sendout(sc);
284126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
285126258Smlaier		splx(s);
286126258Smlaier		break;
287126258Smlaier	default:
288126258Smlaier		return (ENOTTY);
289126258Smlaier	}
290126258Smlaier
291126258Smlaier	return (0);
292126258Smlaier}
293126258Smlaier
294126258Smlaiervoid
295126258Smlaierpfsync_setmtu(sc, mtu)
296126258Smlaier	struct pfsync_softc *sc;
297126258Smlaier	int mtu;
298126258Smlaier{
299126258Smlaier	sc->sc_count = (mtu - sizeof(struct pfsync_header)) /
300126258Smlaier	    sizeof(struct pf_state);
301126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
302126258Smlaier	    sc->sc_count * sizeof(struct pf_state);
303126258Smlaier}
304126258Smlaier
305126258Smlaierstruct mbuf *
306126258Smlaierpfsync_get_mbuf(sc, action)
307126258Smlaier	struct pfsync_softc *sc;
308126258Smlaier	u_int8_t action;
309126258Smlaier{
310127145Smlaier#ifndef __FreeBSD__
311126258Smlaier	extern int hz;
312126261Smlaier#endif
313126258Smlaier	struct pfsync_header *h;
314126258Smlaier	struct mbuf *m;
315126258Smlaier	int len;
316126258Smlaier
317126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
318126258Smlaier	if (m == NULL) {
319126258Smlaier		sc->sc_if.if_oerrors++;
320126258Smlaier		return (NULL);
321126258Smlaier	}
322126258Smlaier
323126258Smlaier	len = sc->sc_if.if_mtu;
324126258Smlaier	if (len > MHLEN) {
325126258Smlaier		MCLGET(m, M_DONTWAIT);
326126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
327126258Smlaier			m_free(m);
328126258Smlaier			sc->sc_if.if_oerrors++;
329126258Smlaier			return (NULL);
330126258Smlaier		}
331126258Smlaier	}
332126258Smlaier	m->m_pkthdr.rcvif = NULL;
333126258Smlaier	m->m_pkthdr.len = m->m_len = len;
334126258Smlaier
335126258Smlaier	h = mtod(m, struct pfsync_header *);
336126258Smlaier	h->version = PFSYNC_VERSION;
337126258Smlaier	h->af = 0;
338126258Smlaier	h->count = 0;
339126258Smlaier	h->action = action;
340126258Smlaier
341126258Smlaier	sc->sc_mbuf = m;
342126258Smlaier	sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
343127145Smlaier#ifdef __FreeBSD__
344126261Smlaier	callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
345126261Smlaier	    LIST_FIRST(&pfsync_list));
346126261Smlaier#else
347126258Smlaier	timeout_add(&sc->sc_tmo, hz);
348126261Smlaier#endif
349126258Smlaier
350126258Smlaier	return (m);
351126258Smlaier}
352126258Smlaier
353126261Smlaier/*
354126261Smlaier * XXX: This function should be called with PF_LOCK held as it references
355126261Smlaier * pf_state.
356126261Smlaier */
357126258Smlaierint
358126258Smlaierpfsync_pack_state(action, st)
359126258Smlaier	u_int8_t action;
360126258Smlaier	struct pf_state *st;
361126258Smlaier{
362127145Smlaier#ifdef __FreeBSD__
363126261Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
364126261Smlaier#else
365126258Smlaier	extern struct timeval time;
366126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
367126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
368126261Smlaier#endif
369126258Smlaier	struct pfsync_header *h;
370126258Smlaier	struct pf_state *sp;
371126258Smlaier	struct pf_rule *r = st->rule.ptr;
372126258Smlaier	struct mbuf *m;
373126258Smlaier	u_long secs;
374126258Smlaier	int s, ret;
375126258Smlaier
376126258Smlaier	if (action >= PFSYNC_ACT_MAX)
377126258Smlaier		return (EINVAL);
378126258Smlaier
379127145Smlaier#ifdef __FreeBSD__
380126261Smlaier	/*
381126261Smlaier	 * XXX
382126261Smlaier	 *  If we need to check mutex owned, PF_LOCK should be
383127145Smlaier	 * declared in pflog.ko.
384126261Smlaier	 *
385126261Smlaier	 * PF_LOCK_ASSERT();
386126261Smlaier	 */
387126261Smlaier	KASSERT((!LIST_EMPTY(&pfsync_list)), ("pfsync: no interface"));
388126261Smlaier#endif
389126258Smlaier	s = splnet();
390126258Smlaier	m = sc->sc_mbuf;
391126258Smlaier	if (m == NULL) {
392126258Smlaier		if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
393126258Smlaier			splx(s);
394126258Smlaier			return (ENOMEM);
395126258Smlaier		}
396126258Smlaier		h = mtod(m, struct pfsync_header *);
397126258Smlaier	} else {
398126258Smlaier		h = mtod(m, struct pfsync_header *);
399126258Smlaier		if (h->action != action) {
400126258Smlaier			pfsync_sendout(sc);
401126258Smlaier			if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
402126258Smlaier				splx(s);
403126258Smlaier				return (ENOMEM);
404126258Smlaier			}
405126258Smlaier			h = mtod(m, struct pfsync_header *);
406126258Smlaier		}
407126258Smlaier	}
408126258Smlaier
409126258Smlaier	sp = sc->sc_ptr++;
410126258Smlaier	h->count++;
411126258Smlaier	bzero(sp, sizeof(*sp));
412126258Smlaier
413126258Smlaier	bcopy(&st->lan, &sp->lan, sizeof(sp->lan));
414126258Smlaier	bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy));
415126258Smlaier	bcopy(&st->ext, &sp->ext, sizeof(sp->ext));
416126258Smlaier
417126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
418126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
419126258Smlaier
420126258Smlaier	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
421127145Smlaier#ifdef __FreeBSD__
422126261Smlaier	secs = time_second;
423126261Smlaier#else
424126258Smlaier	secs = time.tv_sec;
425126261Smlaier#endif
426126258Smlaier	sp->creation = htonl(secs - st->creation);
427126258Smlaier	if (st->expire <= secs)
428126258Smlaier		sp->expire = htonl(0);
429126258Smlaier	else
430126258Smlaier		sp->expire = htonl(st->expire - secs);
431126258Smlaier	sp->packets[0] = htonl(st->packets[0]);
432126258Smlaier	sp->packets[1] = htonl(st->packets[1]);
433126258Smlaier	sp->bytes[0] = htonl(st->bytes[0]);
434126258Smlaier	sp->bytes[1] = htonl(st->bytes[1]);
435126258Smlaier	if (r == NULL)
436126258Smlaier		sp->rule.nr = htonl(-1);
437126258Smlaier	else
438126258Smlaier		sp->rule.nr = htonl(r->nr);
439126258Smlaier	sp->af = st->af;
440126258Smlaier	sp->proto = st->proto;
441126258Smlaier	sp->direction = st->direction;
442126258Smlaier	sp->log = st->log;
443126258Smlaier	sp->allow_opts = st->allow_opts;
444126258Smlaier
445126258Smlaier	ret = 0;
446126258Smlaier	if (h->count == sc->sc_count)
447126258Smlaier		ret = pfsync_sendout(sc);
448126258Smlaier
449126258Smlaier	splx(s);
450126258Smlaier	return (0);
451126258Smlaier}
452126258Smlaier
453126258Smlaierint
454126258Smlaierpfsync_clear_state(st)
455126258Smlaier	struct pf_state *st;
456126258Smlaier{
457127145Smlaier#ifdef __FreeBSD__
458126261Smlaier	struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
459126261Smlaier#else
460126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
461126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
462126261Smlaier#endif
463126258Smlaier	struct mbuf *m = sc->sc_mbuf;
464126258Smlaier	int s, ret;
465126258Smlaier
466126258Smlaier	s = splnet();
467126258Smlaier	if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) {
468126258Smlaier		splx(s);
469126258Smlaier		return (ENOMEM);
470126258Smlaier	}
471126258Smlaier
472126258Smlaier	ret = (pfsync_sendout(sc));
473126258Smlaier	splx(s);
474126258Smlaier	return (ret);
475126258Smlaier}
476126258Smlaier
477126258Smlaiervoid
478126258Smlaierpfsync_timeout(void *v)
479126258Smlaier{
480126258Smlaier	struct pfsync_softc *sc = v;
481126258Smlaier	int s;
482126258Smlaier
483126261Smlaier	/* We don't need PF_LOCK/PF_UNLOCK here! */
484126258Smlaier	s = splnet();
485126258Smlaier	pfsync_sendout(sc);
486126258Smlaier	splx(s);
487126258Smlaier}
488126258Smlaier
489126258Smlaierint
490126258Smlaierpfsync_sendout(sc)
491126258Smlaier	struct pfsync_softc *sc;
492126258Smlaier{
493126258Smlaier	struct ifnet *ifp = &sc->sc_if;
494126258Smlaier	struct mbuf *m = sc->sc_mbuf;
495126258Smlaier
496127145Smlaier#ifdef __FreeBSD__
497126261Smlaier	callout_stop(&sc->sc_tmo);
498126261Smlaier#else
499126258Smlaier	timeout_del(&sc->sc_tmo);
500126261Smlaier#endif
501126258Smlaier	sc->sc_mbuf = NULL;
502126258Smlaier	sc->sc_ptr = NULL;
503126258Smlaier
504127145Smlaier#ifdef __FreeBSD__
505126261Smlaier	KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
506126261Smlaier#endif
507126258Smlaier#if NBPFILTER > 0
508126258Smlaier	if (ifp->if_bpf)
509126258Smlaier		bpf_mtap(ifp->if_bpf, m);
510126258Smlaier#endif
511126258Smlaier
512126258Smlaier	m_freem(m);
513126258Smlaier
514126258Smlaier	return (0);
515126258Smlaier}
516126261Smlaier
517126261Smlaier
518127145Smlaier#ifdef __FreeBSD__
519126261Smlaierstatic int
520126261Smlaierpfsync_modevent(module_t mod, int type, void *data)
521126261Smlaier{
522126261Smlaier	int error = 0;
523126261Smlaier
524126261Smlaier	switch (type) {
525126261Smlaier	case MOD_LOAD:
526126261Smlaier		LIST_INIT(&pfsync_list);
527126261Smlaier		if_clone_attach(&pfsync_cloner);
528126261Smlaier		break;
529126261Smlaier
530126261Smlaier	case MOD_UNLOAD:
531126261Smlaier		if_clone_detach(&pfsync_cloner);
532126261Smlaier		while (!LIST_EMPTY(&pfsync_list))
533126261Smlaier			pfsync_clone_destroy(
534126261Smlaier				&LIST_FIRST(&pfsync_list)->sc_if);
535126261Smlaier		break;
536126261Smlaier
537126261Smlaier	default:
538126261Smlaier		error = EINVAL;
539126261Smlaier		break;
540126261Smlaier	}
541126261Smlaier
542126261Smlaier	return error;
543126261Smlaier}
544126261Smlaier
545126261Smlaierstatic moduledata_t pfsync_mod = {
546126261Smlaier	"pfsync",
547126261Smlaier	pfsync_modevent,
548126261Smlaier	0
549126261Smlaier};
550126261Smlaier
551126261Smlaier#define PFSYNC_MODVER 1
552126261Smlaier
553126261SmlaierDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
554126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER);
555126261Smlaier#endif /* __FreeBSD__ */
556