pf_if.c revision 133573
1130613Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf_if.c 133573 2004-08-12 13:54:50Z mlaier $ */
2130610Smlaier/*	$OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */
3133573Smlaier/* add	$OpenBSD: pf_if.c,v 1.19 2004/08/11 12:06:44 henning Exp $ */
4130610Smlaier
5130610Smlaier/*
6130610Smlaier * Copyright (c) 2001 Daniel Hartmeier
7130610Smlaier * Copyright (c) 2003 Cedric Berger
8130610Smlaier * All rights reserved.
9130610Smlaier *
10130610Smlaier * Redistribution and use in source and binary forms, with or without
11130610Smlaier * modification, are permitted provided that the following conditions
12130610Smlaier * are met:
13130610Smlaier *
14130610Smlaier *    - Redistributions of source code must retain the above copyright
15130610Smlaier *      notice, this list of conditions and the following disclaimer.
16130610Smlaier *    - Redistributions in binary form must reproduce the above
17130610Smlaier *      copyright notice, this list of conditions and the following
18130610Smlaier *      disclaimer in the documentation and/or other materials provided
19130610Smlaier *      with the distribution.
20130610Smlaier *
21130610Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22130610Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23130610Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24130610Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25130610Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26130610Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27130610Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28130610Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29130610Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30130610Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31130610Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32130610Smlaier * POSSIBILITY OF SUCH DAMAGE.
33130610Smlaier */
34130610Smlaier
35130613Smlaier#if defined(__FreeBSD__)
36130613Smlaier#include "opt_inet.h"
37130613Smlaier#include "opt_inet6.h"
38130613Smlaier#endif
39130613Smlaier
40130610Smlaier#include <sys/param.h>
41130610Smlaier#include <sys/systm.h>
42130613Smlaier#ifdef __FreeBSD__
43130613Smlaier#include <sys/malloc.h>
44130613Smlaier#endif
45130610Smlaier#include <sys/mbuf.h>
46130610Smlaier#include <sys/filio.h>
47130610Smlaier#include <sys/socket.h>
48130610Smlaier#include <sys/socketvar.h>
49130610Smlaier#include <sys/kernel.h>
50130613Smlaier#ifndef __FreeBSD__
51130610Smlaier#include <sys/device.h>
52130613Smlaier#endif
53130610Smlaier#include <sys/time.h>
54130610Smlaier
55130610Smlaier#include <net/if.h>
56130610Smlaier#include <net/if_types.h>
57133573Smlaier#include <net/route.h>
58130610Smlaier
59130610Smlaier#include <netinet/in.h>
60130610Smlaier#include <netinet/in_var.h>
61130610Smlaier#include <netinet/in_systm.h>
62130610Smlaier#include <netinet/ip.h>
63130610Smlaier#include <netinet/ip_var.h>
64130610Smlaier
65130610Smlaier#include <net/pfvar.h>
66130610Smlaier
67130610Smlaier#ifdef INET6
68130610Smlaier#include <netinet/ip6.h>
69130610Smlaier#endif /* INET6 */
70130610Smlaier
71130610Smlaier#define ACCEPT_FLAGS(oklist)			\
72130610Smlaier	do {					\
73130610Smlaier		if ((flags & ~(oklist)) &	\
74130610Smlaier		    PFI_FLAG_ALLMASK)		\
75130610Smlaier			return (EINVAL);	\
76130610Smlaier	} while (0)
77130610Smlaier
78130610Smlaier#define senderr(e)      do { rv = (e); goto _bad; } while (0)
79130610Smlaier
80130610Smlaierstruct pfi_kif		**pfi_index2kif;
81130613Smlaierstruct pfi_kif		 *pfi_self, *pfi_dummy;
82130610Smlaierint			  pfi_indexlim;
83130610Smlaierstruct pfi_ifhead	  pfi_ifs;
84130610Smlaierstruct pfi_statehead	  pfi_statehead;
85130610Smlaierint			  pfi_ifcnt;
86130613Smlaier#ifdef __FreeBSD__
87130613Smlaieruma_zone_t		  pfi_addr_pl;
88130613Smlaier#else
89130610Smlaierstruct pool		  pfi_addr_pl;
90130613Smlaier#endif
91130610Smlaierlong			  pfi_update = 1;
92130610Smlaierstruct pfr_addr		 *pfi_buffer;
93130610Smlaierint			  pfi_buffer_cnt;
94130610Smlaierint			  pfi_buffer_max;
95130610Smlaierchar			  pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] =
96130610Smlaier				PF_RESERVED_ANCHOR;
97130610Smlaierchar			  pfi_interface_ruleset[PF_RULESET_NAME_SIZE] =
98130610Smlaier				PF_INTERFACE_RULESET;
99130613Smlaier#ifdef __FreeBSD__
100130613Smlaiereventhandler_tag	 pfi_clone_cookie = NULL;
101130613Smlaiereventhandler_tag	 pfi_attach_cookie = NULL;
102130613Smlaiereventhandler_tag	 pfi_detach_cookie = NULL;
103130613Smlaier#endif
104130610Smlaier
105130610Smlaiervoid		 pfi_dynaddr_update(void *);
106130610Smlaiervoid		 pfi_kifaddr_update(void *);
107130610Smlaiervoid		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
108130610Smlaier		    int, int);
109130610Smlaiervoid		 pfi_instance_add(struct ifnet *, int, int);
110130610Smlaiervoid		 pfi_address_add(struct sockaddr *, int, int);
111130610Smlaierint		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
112130610Smlaierstruct pfi_kif	*pfi_if_create(const char *, struct pfi_kif *, int);
113130610Smlaiervoid		 pfi_copy_group(char *, const char *, int);
114130610Smlaiervoid		 pfi_dynamic_drivers(void);
115130610Smlaiervoid		 pfi_newgroup(const char *, int);
116130610Smlaierint		 pfi_skip_if(const char *, struct pfi_kif *, int);
117130610Smlaierint		 pfi_unmask(void *);
118130610Smlaiervoid		 pfi_dohooks(struct pfi_kif *);
119130613Smlaier#ifdef __FreeBSD__
120130613Smlaiervoid		 pfi_kifaddr_update_event(void *, struct ifnet *);
121130613Smlaiervoid		 pfi_attach_clone_event(void * __unused, struct if_clone *);
122130613Smlaiervoid		 pfi_attach_ifnet_event(void * __unused, struct ifnet *);
123130613Smlaiervoid		 pfi_detach_ifnet_event(void * __unused, struct ifnet *);
124130613Smlaier#endif
125130610Smlaier
126130610SmlaierRB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
127130610SmlaierRB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
128130610Smlaier
129130610Smlaier#define PFI_DYNAMIC_BUSES	{ "pcmcia", "cardbus", "uhub" }
130130610Smlaier#define PFI_BUFFER_MAX		0x10000
131130613Smlaier#ifdef __FreeBSD__
132130613SmlaierMALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
133130613Smlaier#else
134130610Smlaier#define PFI_MTYPE		M_IFADDR
135130613Smlaier#endif
136130610Smlaier
137130610Smlaiervoid
138130610Smlaierpfi_initialize(void)
139130610Smlaier{
140130613Smlaier#ifdef __FreeBSD__
141130613Smlaier	struct ifnet	*ifp;
142130613Smlaier#endif
143130613Smlaier
144130610Smlaier	if (pfi_self != NULL)	/* already initialized */
145130610Smlaier		return;
146130610Smlaier
147130610Smlaier	TAILQ_INIT(&pfi_statehead);
148130613Smlaier#ifndef __FreeBSD__
149130610Smlaier	pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
150130610Smlaier	    "pfiaddrpl", &pool_allocator_nointr);
151130613Smlaier#endif
152130610Smlaier	pfi_buffer_max = 64;
153130610Smlaier	pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
154130610Smlaier	    PFI_MTYPE, M_WAITOK);
155130610Smlaier	pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
156130610Smlaier	pfi_dynamic_drivers();
157130613Smlaier#ifdef __FreeBSD__
158130613Smlaier	PF_LOCK();
159130613Smlaier	IFNET_RLOCK();
160130613Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link)
161130613Smlaier		if (ifp->if_dunit != IF_DUNIT_NONE) {
162130613Smlaier			IFNET_RUNLOCK();
163130613Smlaier			pfi_attach_ifnet(ifp);
164130613Smlaier			IFNET_RLOCK();
165130613Smlaier		}
166130613Smlaier	IFNET_RUNLOCK();
167130613Smlaier	PF_UNLOCK();
168130613Smlaier	pfi_dummy = pfi_if_create("notyet", pfi_self,
169130613Smlaier	    PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
170130613Smlaier	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
171130613Smlaier	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
172130613Smlaier	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
173130613Smlaier	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
174130613Smlaier	pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
175130613Smlaier	    pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY);
176130613Smlaier#endif
177130610Smlaier}
178130610Smlaier
179130613Smlaier#ifdef __FreeBSD__
180130610Smlaiervoid
181130613Smlaierpfi_cleanup(void)
182130613Smlaier{
183130613Smlaier	struct pfi_kif *p, key;
184130613Smlaier	struct ifnet *ifp;
185130613Smlaier
186130613Smlaier	PF_ASSERT(MA_OWNED);
187132567Smlaier
188130613Smlaier	PF_UNLOCK();
189130613Smlaier	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
190130613Smlaier	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
191130613Smlaier	EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
192132567Smlaier	PF_LOCK();
193130613Smlaier
194130613Smlaier	IFNET_RLOCK();
195130613Smlaier	/* release PFI_IFLAG_INSTANCE */
196130613Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link) {
197130613Smlaier		strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
198130613Smlaier		p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
199130613Smlaier		if (p != NULL) {
200132567Smlaier			IFNET_RUNLOCK();
201130613Smlaier			pfi_detach_ifnet(ifp);
202132567Smlaier			IFNET_RLOCK();
203130613Smlaier		}
204130613Smlaier	}
205130613Smlaier	IFNET_RUNLOCK();
206130613Smlaier
207130613Smlaier	/* XXX clear all other interface group */
208130613Smlaier	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
209130613Smlaier		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
210130613Smlaier
211130613Smlaier		free(p->pfik_ah_head, PFI_MTYPE);
212130613Smlaier		free(p, PFI_MTYPE);
213130613Smlaier	}
214130613Smlaier	free(pfi_index2kif, PFI_MTYPE);
215130613Smlaier	free(pfi_buffer, PFI_MTYPE);
216130613Smlaier	pfi_index2kif = NULL;
217130613Smlaier	pfi_buffer = NULL;
218130613Smlaier	pfi_self = NULL;
219130613Smlaier}
220130613Smlaier
221130613Smlaier/*
222130613Smlaier * Wrapper functions for FreeBSD eventhandler
223130613Smlaier */
224130613Smlaiervoid
225130613Smlaierpfi_kifaddr_update_event(void *arg, struct ifnet *ifp)
226130613Smlaier{
227130613Smlaier	struct pfi_kif *p = arg;
228130613Smlaier
229130613Smlaier	PF_LOCK();
230130613Smlaier	/*
231130613Smlaier	 * Check to see if it is 'our' interface as we do not have per
232130613Smlaier	 * interface hooks and thus get an update for every interface.
233130613Smlaier	 */
234130613Smlaier	if (p && p->pfik_ifp == ifp)
235130613Smlaier		pfi_kifaddr_update(p);
236130613Smlaier	PF_UNLOCK();
237130613Smlaier}
238130613Smlaier
239130613Smlaiervoid
240130613Smlaierpfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
241130613Smlaier{
242130613Smlaier	PF_LOCK();
243130613Smlaier	pfi_attach_clone(ifc);
244130613Smlaier	PF_UNLOCK();
245130613Smlaier}
246130613Smlaier
247130613Smlaiervoid
248130613Smlaierpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
249130613Smlaier{
250130613Smlaier	PF_LOCK();
251130613Smlaier	if (ifp->if_dunit != IF_DUNIT_NONE)
252130613Smlaier		pfi_attach_ifnet(ifp);
253130613Smlaier	PF_UNLOCK();
254130613Smlaier}
255130613Smlaier
256130613Smlaiervoid
257130613Smlaierpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
258130613Smlaier{
259130613Smlaier	PF_LOCK();
260130613Smlaier	pfi_detach_ifnet(ifp);
261130613Smlaier	PF_UNLOCK();
262130613Smlaier}
263130613Smlaier#endif /* __FreeBSD__ */
264130613Smlaier
265130613Smlaiervoid
266130610Smlaierpfi_attach_clone(struct if_clone *ifc)
267130610Smlaier{
268130610Smlaier	pfi_initialize();
269130610Smlaier	pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
270130610Smlaier}
271130610Smlaier
272130610Smlaiervoid
273130610Smlaierpfi_attach_ifnet(struct ifnet *ifp)
274130610Smlaier{
275130610Smlaier	struct pfi_kif	*p, *q, key;
276130610Smlaier	int		 s;
277130613Smlaier#ifdef __FreeBSD__
278130613Smlaier	int		 realname;
279130613Smlaier#endif
280130610Smlaier
281130610Smlaier	pfi_initialize();
282130610Smlaier	s = splsoftnet();
283130610Smlaier	pfi_update++;
284130610Smlaier	if (ifp->if_index >= pfi_indexlim) {
285130610Smlaier		/*
286130610Smlaier		 * grow pfi_index2kif,  similar to ifindex2ifnet code in if.c
287130610Smlaier		 */
288130610Smlaier		size_t m, n, oldlim;
289130610Smlaier		struct pfi_kif **mp, **np;
290130610Smlaier
291130610Smlaier		oldlim = pfi_indexlim;
292130610Smlaier		if (pfi_indexlim == 0)
293130610Smlaier			pfi_indexlim = 64;
294130610Smlaier		while (ifp->if_index >= pfi_indexlim)
295130610Smlaier			pfi_indexlim <<= 1;
296130610Smlaier
297130610Smlaier		m = oldlim * sizeof(struct pfi_kif *);
298130610Smlaier		mp = pfi_index2kif;
299130610Smlaier		n = pfi_indexlim * sizeof(struct pfi_kif *);
300130613Smlaier#ifdef __FreeBSD__
301130613Smlaier		np = malloc(n, PFI_MTYPE, M_NOWAIT);
302130613Smlaier#else
303130610Smlaier		np = malloc(n, PFI_MTYPE, M_DONTWAIT);
304130613Smlaier#endif
305130610Smlaier		if (np == NULL)
306130610Smlaier			panic("pfi_attach_ifnet: "
307130610Smlaier			    "cannot allocate translation table");
308130610Smlaier		bzero(np, n);
309130610Smlaier		if (mp != NULL)
310130610Smlaier			bcopy(mp, np, m);
311130610Smlaier		pfi_index2kif = np;
312130610Smlaier		if (mp != NULL)
313130610Smlaier			free(mp, PFI_MTYPE);
314130610Smlaier	}
315130610Smlaier
316130610Smlaier	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
317130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
318130613Smlaier#ifdef __FreeBSD__
319130613Smlaier	/* some additional trickery for placeholders */
320130613Smlaier	if ((p == NULL) || (p->pfik_parent == pfi_dummy)) {
321130613Smlaier		/* are we looking at a renamed instance or not? */
322130613Smlaier		pfi_copy_group(key.pfik_name, ifp->if_xname,
323130613Smlaier		    sizeof(key.pfik_name));
324130613Smlaier		realname = (strncmp(key.pfik_name, ifp->if_dname,
325130613Smlaier		    sizeof(key.pfik_name)) == 0);
326130613Smlaier		/* add group */
327130613Smlaier		/* we can change if_xname, hence use if_dname as group id */
328130613Smlaier		pfi_copy_group(key.pfik_name, ifp->if_dname,
329130613Smlaier		    sizeof(key.pfik_name));
330130613Smlaier		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
331130613Smlaier		if (q == NULL)
332130613Smlaier		    q = pfi_if_create(key.pfik_name, pfi_self,
333130613Smlaier		        PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC);
334130613Smlaier		else if (q->pfik_parent == pfi_dummy) {
335130613Smlaier			q->pfik_parent = pfi_self;
336130613Smlaier			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
337130613Smlaier		}
338130613Smlaier		if (q == NULL)
339130613Smlaier			panic("pfi_attach_ifnet: "
340130613Smlaier			    "cannot allocate '%s' group", key.pfik_name);
341130613Smlaier
342130613Smlaier		/* add/modify interface */
343130613Smlaier		if (p == NULL)
344130613Smlaier			p = pfi_if_create(ifp->if_xname, q,
345130613Smlaier			    realname?PFI_IFLAG_INSTANCE:PFI_IFLAG_PLACEHOLDER);
346130613Smlaier		else {
347130613Smlaier			/* remove from the dummy group */
348130613Smlaier			/* XXX: copy stats? We should not have any!!! */
349130613Smlaier			pfi_dummy->pfik_delcnt++;
350130613Smlaier			TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p,
351130613Smlaier			    pfik_instances);
352130613Smlaier			/* move to the right group */
353130613Smlaier			p->pfik_parent = q;
354130613Smlaier			q->pfik_addcnt++;
355130613Smlaier			TAILQ_INSERT_TAIL(&q->pfik_grouphead, p,
356130613Smlaier			    pfik_instances);
357130613Smlaier			if (realname) {
358130613Smlaier				p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER;
359130613Smlaier				p->pfik_flags |= PFI_IFLAG_INSTANCE;
360130613Smlaier			}
361130613Smlaier		}
362130613Smlaier		if (p == NULL)
363130613Smlaier			panic("pfi_attach_ifnet: "
364130613Smlaier			    "cannot allocate '%s' interface", ifp->if_xname);
365130613Smlaier#else
366130610Smlaier	if (p == NULL) {
367130610Smlaier		/* add group */
368130610Smlaier		pfi_copy_group(key.pfik_name, ifp->if_xname,
369130610Smlaier		    sizeof(key.pfik_name));
370130610Smlaier		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
371130610Smlaier		if (q == NULL)
372130610Smlaier		    q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
373130613Smlaier		else if (q->pfik_parent == pfi_dummy) {
374130613Smlaier			q->pfik_parent = pfi_self;
375130613Smlaier			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
376130613Smlaier		}
377130610Smlaier		if (q == NULL)
378130610Smlaier			panic("pfi_attach_ifnet: "
379130610Smlaier			    "cannot allocate '%s' group", key.pfik_name);
380130610Smlaier
381130610Smlaier		/* add interface */
382130610Smlaier		p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
383130610Smlaier		if (p == NULL)
384130610Smlaier			panic("pfi_attach_ifnet: "
385130610Smlaier			    "cannot allocate '%s' interface", ifp->if_xname);
386130613Smlaier#endif
387130610Smlaier	} else
388130610Smlaier		q = p->pfik_parent;
389130610Smlaier	p->pfik_ifp = ifp;
390130610Smlaier	p->pfik_flags |= PFI_IFLAG_ATTACHED;
391130613Smlaier#ifdef __FreeBSD__
392130613Smlaier	PF_UNLOCK();
393130613Smlaier	p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
394130613Smlaier	    pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY);
395130613Smlaier	PF_LOCK();
396130613Smlaier#else
397130610Smlaier	p->pfik_ah_cookie =
398130610Smlaier	    hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
399130613Smlaier#endif
400130610Smlaier	pfi_index2kif[ifp->if_index] = p;
401130610Smlaier	pfi_dohooks(p);
402130610Smlaier	splx(s);
403130610Smlaier}
404130610Smlaier
405130610Smlaiervoid
406130610Smlaierpfi_detach_ifnet(struct ifnet *ifp)
407130610Smlaier{
408130610Smlaier	struct pfi_kif	*p, *q, key;
409130610Smlaier	int		 s;
410130610Smlaier
411130610Smlaier	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
412130610Smlaier
413130610Smlaier	s = splsoftnet();
414130610Smlaier	pfi_update++;
415130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
416130610Smlaier	if (p == NULL) {
417130610Smlaier		printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
418130610Smlaier		splx(s);
419130610Smlaier		return;
420130610Smlaier	}
421130613Smlaier#ifdef __FreeBSD__
422130613Smlaier	PF_UNLOCK();
423130613Smlaier	EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie);
424130613Smlaier	PF_LOCK();
425130613Smlaier#else
426130610Smlaier	hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
427130613Smlaier#endif
428130610Smlaier	q = p->pfik_parent;
429130610Smlaier	p->pfik_ifp = NULL;
430130610Smlaier	p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
431130610Smlaier	pfi_index2kif[ifp->if_index] = NULL;
432130610Smlaier	pfi_dohooks(p);
433130610Smlaier	pfi_maybe_destroy(p);
434130610Smlaier	splx(s);
435130610Smlaier}
436130610Smlaier
437130610Smlaierstruct pfi_kif *
438130610Smlaierpfi_lookup_create(const char *name)
439130610Smlaier{
440130610Smlaier	struct pfi_kif	*p, *q, key;
441130610Smlaier	int		 s;
442130610Smlaier
443130610Smlaier	s = splsoftnet();
444130610Smlaier	p = pfi_lookup_if(name);
445130610Smlaier	if (p == NULL) {
446130610Smlaier		pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
447130610Smlaier		q = pfi_lookup_if(key.pfik_name);
448130613Smlaier#ifdef __FreeBSD__
449130613Smlaier		if ((q != NULL) && (q->pfik_parent != pfi_dummy))
450130613Smlaier			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
451130613Smlaier		else {
452130613Smlaier			if (pfi_dummy == NULL)
453130613Smlaier				panic("no 'notyet' dummy group");
454130613Smlaier			p = pfi_if_create(name, pfi_dummy,
455130613Smlaier			    PFI_IFLAG_PLACEHOLDER);
456130613Smlaier		}
457130613Smlaier#else
458130610Smlaier		if (q != NULL)
459130610Smlaier			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
460130613Smlaier#endif
461130610Smlaier	}
462130610Smlaier	splx(s);
463130610Smlaier	return (p);
464130610Smlaier}
465130610Smlaier
466130610Smlaierstruct pfi_kif *
467130610Smlaierpfi_attach_rule(const char *name)
468130610Smlaier{
469130610Smlaier	struct pfi_kif	*p;
470130610Smlaier
471130610Smlaier	p = pfi_lookup_create(name);
472130610Smlaier	if (p != NULL)
473130610Smlaier		p->pfik_rules++;
474130610Smlaier	return (p);
475130610Smlaier}
476130610Smlaier
477130610Smlaiervoid
478130610Smlaierpfi_detach_rule(struct pfi_kif *p)
479130610Smlaier{
480130610Smlaier	if (p == NULL)
481130610Smlaier		return;
482130610Smlaier	if (p->pfik_rules > 0)
483130610Smlaier		p->pfik_rules--;
484130610Smlaier	else
485130610Smlaier		printf("pfi_detach_rule: reference count at 0\n");
486130610Smlaier	pfi_maybe_destroy(p);
487130610Smlaier}
488130610Smlaier
489130610Smlaiervoid
490130610Smlaierpfi_attach_state(struct pfi_kif *p)
491130610Smlaier{
492130610Smlaier	if (!p->pfik_states++)
493130610Smlaier		TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
494130610Smlaier}
495130610Smlaier
496130610Smlaiervoid
497130610Smlaierpfi_detach_state(struct pfi_kif *p)
498130610Smlaier{
499130610Smlaier	if (p == NULL)
500130610Smlaier		return;
501130610Smlaier	if (p->pfik_states <= 0) {
502130610Smlaier		printf("pfi_detach_state: reference count <= 0\n");
503130610Smlaier		return;
504130610Smlaier	}
505130610Smlaier	if (!--p->pfik_states)
506130610Smlaier		TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
507130610Smlaier	pfi_maybe_destroy(p);
508130610Smlaier}
509130610Smlaier
510130610Smlaierint
511130610Smlaierpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
512130610Smlaier{
513130610Smlaier	struct pfi_dynaddr	*dyn;
514130610Smlaier	char			 tblname[PF_TABLE_NAME_SIZE];
515130610Smlaier	struct pf_ruleset	*ruleset = NULL;
516130610Smlaier	int			 s, rv = 0;
517130610Smlaier
518130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL)
519130610Smlaier		return (0);
520130610Smlaier	dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
521130610Smlaier	if (dyn == NULL)
522130610Smlaier		return (1);
523130610Smlaier	bzero(dyn, sizeof(*dyn));
524130610Smlaier
525130610Smlaier	s = splsoftnet();
526130610Smlaier	dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
527130610Smlaier	if (dyn->pfid_kif == NULL)
528130610Smlaier		senderr(1);
529130610Smlaier
530130610Smlaier	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
531130610Smlaier	if (af == AF_INET && dyn->pfid_net == 32)
532130610Smlaier		dyn->pfid_net = 128;
533130610Smlaier	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
534130610Smlaier	if (aw->iflags & PFI_AFLAG_NETWORK)
535130610Smlaier		strlcat(tblname, ":network", sizeof(tblname));
536130610Smlaier	if (aw->iflags & PFI_AFLAG_BROADCAST)
537130610Smlaier		strlcat(tblname, ":broadcast", sizeof(tblname));
538130610Smlaier	if (aw->iflags & PFI_AFLAG_PEER)
539130610Smlaier		strlcat(tblname, ":peer", sizeof(tblname));
540130610Smlaier	if (aw->iflags & PFI_AFLAG_NOALIAS)
541130610Smlaier		strlcat(tblname, ":0", sizeof(tblname));
542130610Smlaier	if (dyn->pfid_net != 128)
543130610Smlaier		snprintf(tblname + strlen(tblname),
544130610Smlaier		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
545130610Smlaier	ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor,
546130610Smlaier	    pfi_interface_ruleset);
547130610Smlaier	if (ruleset == NULL)
548130610Smlaier		senderr(1);
549130610Smlaier
550130610Smlaier	dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
551130610Smlaier	if (dyn->pfid_kt == NULL)
552130610Smlaier		senderr(1);
553130610Smlaier
554130610Smlaier	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
555130610Smlaier	dyn->pfid_iflags = aw->iflags;
556130610Smlaier	dyn->pfid_af = af;
557130610Smlaier	dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
558130610Smlaier	    pfi_dynaddr_update, dyn);
559130610Smlaier	if (dyn->pfid_hook_cookie == NULL)
560130610Smlaier		senderr(1);
561130610Smlaier
562130610Smlaier	aw->p.dyn = dyn;
563130610Smlaier	pfi_dynaddr_update(aw->p.dyn);
564130610Smlaier	splx(s);
565130610Smlaier	return (0);
566130610Smlaier
567130610Smlaier_bad:
568130610Smlaier	if (dyn->pfid_kt != NULL)
569130610Smlaier		pfr_detach_table(dyn->pfid_kt);
570130610Smlaier	if (ruleset != NULL)
571130610Smlaier		pf_remove_if_empty_ruleset(ruleset);
572130610Smlaier	if (dyn->pfid_kif != NULL)
573130610Smlaier		pfi_detach_rule(dyn->pfid_kif);
574130610Smlaier	pool_put(&pfi_addr_pl, dyn);
575130610Smlaier	splx(s);
576130610Smlaier	return (rv);
577130610Smlaier}
578130610Smlaier
579130610Smlaiervoid
580130610Smlaierpfi_dynaddr_update(void *p)
581130610Smlaier{
582130610Smlaier	struct pfi_dynaddr	*dyn = (struct pfi_dynaddr *)p;
583130610Smlaier	struct pfi_kif		*kif = dyn->pfid_kif;
584130610Smlaier	struct pfr_ktable	*kt = dyn->pfid_kt;
585130610Smlaier
586130610Smlaier	if (dyn == NULL || kif == NULL || kt == NULL)
587130610Smlaier		panic("pfi_dynaddr_update");
588130610Smlaier	if (kt->pfrkt_larg != pfi_update) {
589130610Smlaier		/* this table needs to be brought up-to-date */
590130610Smlaier		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
591130610Smlaier		kt->pfrkt_larg = pfi_update;
592130610Smlaier	}
593130610Smlaier	pfr_dynaddr_update(kt, dyn);
594130610Smlaier}
595130610Smlaier
596130610Smlaiervoid
597130610Smlaierpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
598130610Smlaier{
599130610Smlaier	int			 e, size2 = 0;
600130610Smlaier	struct pfi_kif		*p;
601130610Smlaier	struct pfr_table	 t;
602130610Smlaier
603130610Smlaier	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
604130610Smlaier		pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
605130610Smlaier		return;
606130610Smlaier	}
607130610Smlaier	pfi_buffer_cnt = 0;
608130610Smlaier	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
609130610Smlaier		pfi_instance_add(kif->pfik_ifp, net, flags);
610130610Smlaier	else if (strcmp(kif->pfik_name, "self")) {
611130610Smlaier		TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
612130610Smlaier			pfi_instance_add(p->pfik_ifp, net, flags);
613130610Smlaier	} else {
614130610Smlaier		RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
615130610Smlaier			if (p->pfik_flags & PFI_IFLAG_INSTANCE)
616130610Smlaier				pfi_instance_add(p->pfik_ifp, net, flags);
617130610Smlaier	}
618130610Smlaier	t = kt->pfrkt_t;
619130610Smlaier	t.pfrt_flags = 0;
620130610Smlaier	if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
621130610Smlaier	    NULL, NULL, NULL, 0)))
622130610Smlaier		printf("pfi_table_update: cannot set %d new addresses "
623130610Smlaier		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
624130610Smlaier}
625130610Smlaier
626130610Smlaiervoid
627130610Smlaierpfi_instance_add(struct ifnet *ifp, int net, int flags)
628130610Smlaier{
629130610Smlaier	struct ifaddr	*ia;
630130610Smlaier	int		 got4 = 0, got6 = 0;
631130610Smlaier	int		 net2, af;
632130610Smlaier
633130610Smlaier	if (ifp == NULL)
634130610Smlaier		return;
635130610Smlaier	TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
636130610Smlaier		if (ia->ifa_addr == NULL)
637130610Smlaier			continue;
638130610Smlaier		af = ia->ifa_addr->sa_family;
639130610Smlaier		if (af != AF_INET && af != AF_INET6)
640130610Smlaier			continue;
641133573Smlaier		if (!(ia->ifa_flags & IFA_ROUTE))
642133573Smlaier			continue;
643130610Smlaier		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
644130610Smlaier			continue;
645130610Smlaier		if ((flags & PFI_AFLAG_BROADCAST) &&
646130610Smlaier		    !(ifp->if_flags & IFF_BROADCAST))
647130610Smlaier			continue;
648130610Smlaier		if ((flags & PFI_AFLAG_PEER) &&
649130610Smlaier		    !(ifp->if_flags & IFF_POINTOPOINT))
650130610Smlaier			continue;
651130610Smlaier		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
652130610Smlaier		    IN6_IS_ADDR_LINKLOCAL(
653130610Smlaier		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
654130610Smlaier			continue;
655130610Smlaier		if (flags & PFI_AFLAG_NOALIAS) {
656130610Smlaier			if (af == AF_INET && got4)
657130610Smlaier				continue;
658130610Smlaier			if (af == AF_INET6 && got6)
659130610Smlaier				continue;
660130610Smlaier		}
661130610Smlaier		if (af == AF_INET)
662130610Smlaier			got4 = 1;
663130610Smlaier		else
664130610Smlaier			got6 = 1;
665130610Smlaier		net2 = net;
666130610Smlaier		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
667130610Smlaier			if (af == AF_INET) {
668130610Smlaier				net2 = pfi_unmask(&((struct sockaddr_in *)
669130610Smlaier				    ia->ifa_netmask)->sin_addr);
670130610Smlaier			} else {
671130610Smlaier				net2 = pfi_unmask(&((struct sockaddr_in6 *)
672130610Smlaier				    ia->ifa_netmask)->sin6_addr);
673130610Smlaier			}
674130610Smlaier		}
675130610Smlaier		if (af == AF_INET && net2 > 32)
676130610Smlaier			net2 = 32;
677130610Smlaier		if (flags & PFI_AFLAG_BROADCAST)
678130610Smlaier			pfi_address_add(ia->ifa_broadaddr, af, net2);
679130610Smlaier		else if (flags & PFI_AFLAG_PEER)
680130610Smlaier			pfi_address_add(ia->ifa_dstaddr, af, net2);
681130610Smlaier		else
682130610Smlaier			pfi_address_add(ia->ifa_addr, af, net2);
683130610Smlaier	}
684130610Smlaier}
685130610Smlaier
686130610Smlaiervoid
687130610Smlaierpfi_address_add(struct sockaddr *sa, int af, int net)
688130610Smlaier{
689130610Smlaier	struct pfr_addr	*p;
690130610Smlaier	int		 i;
691130610Smlaier
692130610Smlaier	if (pfi_buffer_cnt >= pfi_buffer_max) {
693130610Smlaier		int		 new_max = pfi_buffer_max * 2;
694130610Smlaier
695130610Smlaier		if (new_max > PFI_BUFFER_MAX) {
696130610Smlaier			printf("pfi_address_add: address buffer full (%d/%d)\n",
697130610Smlaier			    pfi_buffer_cnt, PFI_BUFFER_MAX);
698130610Smlaier			return;
699130610Smlaier		}
700130613Smlaier#ifdef __FreeBSD__
701130610Smlaier		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
702130613Smlaier		    M_NOWAIT);
703130613Smlaier#else
704130613Smlaier		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
705130610Smlaier		    M_DONTWAIT);
706130613Smlaier#endif
707130610Smlaier		if (p == NULL) {
708130610Smlaier			printf("pfi_address_add: no memory to grow buffer "
709130610Smlaier			    "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
710130610Smlaier			return;
711130610Smlaier		}
712130610Smlaier		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
713130610Smlaier		/* no need to zero buffer */
714130610Smlaier		free(pfi_buffer, PFI_MTYPE);
715130610Smlaier		pfi_buffer = p;
716130610Smlaier		pfi_buffer_max = new_max;
717130610Smlaier	}
718130610Smlaier	if (af == AF_INET && net > 32)
719130610Smlaier		net = 128;
720130610Smlaier	p = pfi_buffer + pfi_buffer_cnt++;
721130610Smlaier	bzero(p, sizeof(*p));
722130610Smlaier	p->pfra_af = af;
723130610Smlaier	p->pfra_net = net;
724130610Smlaier	if (af == AF_INET)
725130610Smlaier		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
726130610Smlaier	if (af == AF_INET6) {
727130610Smlaier		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
728130610Smlaier		if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
729130610Smlaier			p->pfra_ip6addr.s6_addr16[1] = 0;
730130610Smlaier	}
731130610Smlaier	/* mask network address bits */
732130610Smlaier	if (net < 128)
733130610Smlaier		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
734130610Smlaier	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
735130610Smlaier		((caddr_t)p)[i] = 0;
736130610Smlaier}
737130610Smlaier
738130610Smlaiervoid
739130610Smlaierpfi_dynaddr_remove(struct pf_addr_wrap *aw)
740130610Smlaier{
741130610Smlaier	int	s;
742130610Smlaier
743130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
744130610Smlaier	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
745130610Smlaier		return;
746130610Smlaier
747130610Smlaier	s = splsoftnet();
748130610Smlaier	hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
749130610Smlaier	    aw->p.dyn->pfid_hook_cookie);
750130610Smlaier	pfi_detach_rule(aw->p.dyn->pfid_kif);
751130610Smlaier	aw->p.dyn->pfid_kif = NULL;
752130610Smlaier	pfr_detach_table(aw->p.dyn->pfid_kt);
753130610Smlaier	aw->p.dyn->pfid_kt = NULL;
754130610Smlaier	pool_put(&pfi_addr_pl, aw->p.dyn);
755130610Smlaier	aw->p.dyn = NULL;
756130610Smlaier	splx(s);
757130610Smlaier}
758130610Smlaier
759130610Smlaiervoid
760130610Smlaierpfi_dynaddr_copyout(struct pf_addr_wrap *aw)
761130610Smlaier{
762130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
763130610Smlaier	    aw->p.dyn->pfid_kif == NULL)
764130610Smlaier		return;
765130610Smlaier	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
766130610Smlaier}
767130610Smlaier
768130610Smlaiervoid
769130610Smlaierpfi_kifaddr_update(void *v)
770130610Smlaier{
771130610Smlaier	int		 s;
772130610Smlaier
773130610Smlaier	s = splsoftnet();
774130610Smlaier	pfi_update++;
775130610Smlaier	pfi_dohooks(v);
776130610Smlaier	splx(s);
777130610Smlaier}
778130610Smlaier
779130610Smlaierint
780130610Smlaierpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
781130610Smlaier{
782130610Smlaier	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
783130610Smlaier}
784130610Smlaier
785130610Smlaierstruct pfi_kif *
786130610Smlaierpfi_if_create(const char *name, struct pfi_kif *q, int flags)
787130610Smlaier{
788130610Smlaier	struct pfi_kif *p;
789130610Smlaier
790130613Smlaier#ifdef __FreeBSD__
791130613Smlaier	p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT);
792130613Smlaier#else
793130610Smlaier	p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
794130613Smlaier#endif
795130610Smlaier	if (p == NULL)
796130610Smlaier		return (NULL);
797130610Smlaier	bzero(p, sizeof(*p));
798130613Smlaier#ifdef __FreeBSD__
799130610Smlaier	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
800130613Smlaier	    M_NOWAIT);
801130613Smlaier#else
802130613Smlaier	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
803130610Smlaier	    M_DONTWAIT);
804130613Smlaier#endif
805130610Smlaier	if (p->pfik_ah_head == NULL) {
806130610Smlaier		free(p, PFI_MTYPE);
807130610Smlaier		return (NULL);
808130610Smlaier	}
809130610Smlaier	bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
810130610Smlaier	TAILQ_INIT(p->pfik_ah_head);
811130610Smlaier	TAILQ_INIT(&p->pfik_grouphead);
812130610Smlaier	strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
813130610Smlaier	RB_INIT(&p->pfik_lan_ext);
814130610Smlaier	RB_INIT(&p->pfik_ext_gwy);
815130610Smlaier	p->pfik_flags = flags;
816130610Smlaier	p->pfik_parent = q;
817130613Smlaier#ifdef __FreeBSD__
818130613Smlaier	p->pfik_tzero = time_second;
819130613Smlaier#else
820130610Smlaier	p->pfik_tzero = time.tv_sec;
821130613Smlaier#endif
822130610Smlaier
823130610Smlaier	RB_INSERT(pfi_ifhead, &pfi_ifs, p);
824130610Smlaier	if (q != NULL) {
825130610Smlaier		q->pfik_addcnt++;
826130610Smlaier		TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
827130610Smlaier	}
828130610Smlaier	pfi_ifcnt++;
829130610Smlaier	return (p);
830130610Smlaier}
831130610Smlaier
832130610Smlaierint
833130610Smlaierpfi_maybe_destroy(struct pfi_kif *p)
834130610Smlaier{
835130610Smlaier	int		 i, j, k, s;
836130610Smlaier	struct pfi_kif	*q = p->pfik_parent;
837130610Smlaier
838130610Smlaier	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
839130610Smlaier	    p->pfik_rules > 0 || p->pfik_states > 0)
840130613Smlaier#ifdef __FreeBSD__
841130613Smlaier		if (!(p->pfik_flags & PFI_IFLAG_PLACEHOLDER))
842130613Smlaier#endif
843130610Smlaier		return (0);
844130610Smlaier
845130610Smlaier	s = splsoftnet();
846130610Smlaier	if (q != NULL) {
847130610Smlaier		for (i = 0; i < 2; i++)
848130610Smlaier			for (j = 0; j < 2; j++)
849130610Smlaier				for (k = 0; k < 2; k++) {
850130610Smlaier					q->pfik_bytes[i][j][k] +=
851130610Smlaier					    p->pfik_bytes[i][j][k];
852130610Smlaier					q->pfik_packets[i][j][k] +=
853130610Smlaier					    p->pfik_packets[i][j][k];
854130613Smlaier#ifdef __FreeBSD__
855130613Smlaier			/* clear stats in case we return to the dummy group */
856130613Smlaier					p->pfik_bytes[i][j][k] = 0;
857130613Smlaier					p->pfik_packets[i][j][k] = 0;
858130613Smlaier#endif
859130610Smlaier				}
860130610Smlaier		q->pfik_delcnt++;
861130610Smlaier		TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
862130610Smlaier	}
863130613Smlaier#ifdef __FreeBSD__
864130613Smlaier	if (p->pfik_rules > 0 || p->pfik_states > 0) {
865130613Smlaier		/* move back to the dummy group */
866130613Smlaier		p->pfik_parent = pfi_dummy;
867130613Smlaier		pfi_dummy->pfik_addcnt++;
868130613Smlaier		TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p,
869130613Smlaier		    pfik_instances);
870130613Smlaier		return (0);
871130613Smlaier	}
872130613Smlaier#endif
873130610Smlaier	pfi_ifcnt--;
874130610Smlaier	RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
875130610Smlaier	splx(s);
876130610Smlaier
877130610Smlaier	free(p->pfik_ah_head, PFI_MTYPE);
878130610Smlaier	free(p, PFI_MTYPE);
879130610Smlaier	return (1);
880130610Smlaier}
881130610Smlaier
882130610Smlaiervoid
883130610Smlaierpfi_copy_group(char *p, const char *q, int m)
884130610Smlaier{
885130610Smlaier	while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
886130610Smlaier		*p++ = *q++;
887130610Smlaier		m--;
888130610Smlaier	}
889130610Smlaier	if (m > 0)
890130610Smlaier		*p++ = '\0';
891130610Smlaier}
892130610Smlaier
893130610Smlaiervoid
894130610Smlaierpfi_dynamic_drivers(void)
895130610Smlaier{
896130613Smlaier#ifdef __FreeBSD__
897130613Smlaier	struct ifnet	*ifp;
898130613Smlaier
899130613Smlaier/*
900130613Smlaier * For FreeBSD basically every interface is "dynamic" as we can unload
901130613Smlaier * modules e.g.
902130613Smlaier */
903130613Smlaier
904130613Smlaier	IFNET_RLOCK();
905130613Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link) {
906130613Smlaier		if (ifp->if_dunit == IF_DUNIT_NONE)
907130613Smlaier			continue;
908130613Smlaier		pfi_newgroup(ifp->if_dname, PFI_IFLAG_DYNAMIC);
909130613Smlaier	}
910130613Smlaier	IFNET_RUNLOCK();
911130613Smlaier#else
912130610Smlaier	char		*buses[] = PFI_DYNAMIC_BUSES;
913130610Smlaier	int		 nbuses = sizeof(buses)/sizeof(buses[0]);
914130610Smlaier	int		 enabled[sizeof(buses)/sizeof(buses[0])];
915130610Smlaier	struct device	*dev;
916130610Smlaier	struct cfdata	*cf;
917130610Smlaier	struct cfdriver	*drv;
918130610Smlaier	short		*p;
919130610Smlaier	int		 i;
920130610Smlaier
921130610Smlaier	bzero(enabled, sizeof(enabled));
922130610Smlaier	TAILQ_FOREACH(dev, &alldevs, dv_list) {
923130610Smlaier		if (!(dev->dv_flags & DVF_ACTIVE))
924130610Smlaier			continue;
925130610Smlaier		for (i = 0; i < nbuses; i++)
926130610Smlaier			if (!enabled[i] && !strcmp(buses[i],
927130610Smlaier			    dev->dv_cfdata->cf_driver->cd_name))
928130610Smlaier				enabled[i] = 1;
929130610Smlaier	}
930130610Smlaier	for (cf = cfdata; cf->cf_driver; cf++) {
931130610Smlaier		if (cf->cf_driver->cd_class != DV_IFNET)
932130610Smlaier			continue;
933130610Smlaier		for (p = cf->cf_parents; p && *p >= 0; p++) {
934130610Smlaier			if ((drv = cfdata[*p].cf_driver) == NULL)
935130610Smlaier				continue;
936130610Smlaier			for (i = 0; i < nbuses; i++)
937130610Smlaier				if (enabled[i] &&
938130610Smlaier				    !strcmp(drv->cd_name, buses[i]))
939130610Smlaier					break;
940130610Smlaier			if (i < nbuses) {
941130610Smlaier				pfi_newgroup(cf->cf_driver->cd_name,
942130610Smlaier				    PFI_IFLAG_DYNAMIC);
943130610Smlaier				break;
944130610Smlaier			}
945130610Smlaier		}
946130610Smlaier	}
947130613Smlaier#endif
948130610Smlaier}
949130610Smlaier
950130610Smlaiervoid
951130610Smlaierpfi_newgroup(const char *name, int flags)
952130610Smlaier{
953130610Smlaier	struct pfi_kif	*p;
954130610Smlaier
955130610Smlaier	p = pfi_lookup_if(name);
956130610Smlaier	if (p == NULL)
957130610Smlaier		p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
958130610Smlaier	if (p == NULL) {
959130610Smlaier		printf("pfi_newgroup: cannot allocate '%s' group", name);
960130610Smlaier		return;
961130610Smlaier	}
962130610Smlaier	p->pfik_flags |= flags;
963130610Smlaier}
964130610Smlaier
965130610Smlaiervoid
966130610Smlaierpfi_fill_oldstatus(struct pf_status *pfs)
967130610Smlaier{
968130610Smlaier	struct pfi_kif	*p, key;
969130610Smlaier	int		 i, j, k, s;
970130610Smlaier
971130610Smlaier	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
972130610Smlaier	s = splsoftnet();
973130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
974130610Smlaier	if (p == NULL) {
975130610Smlaier		splx(s);
976130610Smlaier		return;
977130610Smlaier	}
978130610Smlaier	bzero(pfs->pcounters, sizeof(pfs->pcounters));
979130610Smlaier	bzero(pfs->bcounters, sizeof(pfs->bcounters));
980130610Smlaier	for (i = 0; i < 2; i++)
981130610Smlaier		for (j = 0; j < 2; j++)
982130610Smlaier			for (k = 0; k < 2; k++) {
983130610Smlaier				pfs->pcounters[i][j][k] =
984130610Smlaier					p->pfik_packets[i][j][k];
985130610Smlaier				pfs->bcounters[i][j] +=
986130610Smlaier					p->pfik_bytes[i][j][k];
987130610Smlaier			}
988130610Smlaier	splx(s);
989130610Smlaier}
990130610Smlaier
991130610Smlaierint
992130610Smlaierpfi_clr_istats(const char *name, int *nzero, int flags)
993130610Smlaier{
994130610Smlaier	struct pfi_kif	*p;
995130610Smlaier	int		 n = 0, s;
996130613Smlaier#ifdef __FreeBSD__
997130613Smlaier	long		 tzero = time_second;
998130613Smlaier#else
999130610Smlaier	long		 tzero = time.tv_sec;
1000130613Smlaier#endif
1001130610Smlaier
1002130610Smlaier	s = splsoftnet();
1003130610Smlaier	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1004130610Smlaier	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1005130610Smlaier		if (pfi_skip_if(name, p, flags))
1006130610Smlaier			continue;
1007130610Smlaier		bzero(p->pfik_packets, sizeof(p->pfik_packets));
1008130610Smlaier		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
1009130610Smlaier		p->pfik_tzero = tzero;
1010130610Smlaier		n++;
1011130610Smlaier	}
1012130610Smlaier	splx(s);
1013130610Smlaier	if (nzero != NULL)
1014130610Smlaier		*nzero = n;
1015130610Smlaier	return (0);
1016130610Smlaier}
1017130610Smlaier
1018130610Smlaierint
1019130610Smlaierpfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
1020130610Smlaier{
1021130610Smlaier	struct pfi_kif	*p;
1022130610Smlaier	int		 s, n = 0;
1023130613Smlaier#ifdef __FreeBSD__
1024130613Smlaier	int		 ec;
1025130613Smlaier#endif
1026130610Smlaier
1027130610Smlaier	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1028130610Smlaier	s = splsoftnet();
1029130610Smlaier	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1030130610Smlaier		if (pfi_skip_if(name, p, flags))
1031130610Smlaier			continue;
1032130610Smlaier		if (*size > n++) {
1033130610Smlaier			if (!p->pfik_tzero)
1034130610Smlaier				p->pfik_tzero = boottime.tv_sec;
1035130613Smlaier#ifdef __FreeBSD__
1036130613Smlaier			PF_COPYOUT(p, buf++, sizeof(*buf), ec);
1037130613Smlaier			if (ec) {
1038130613Smlaier#else
1039130610Smlaier			if (copyout(p, buf++, sizeof(*buf))) {
1040130613Smlaier#endif
1041130610Smlaier				splx(s);
1042130610Smlaier				return (EFAULT);
1043130610Smlaier			}
1044130610Smlaier		}
1045130610Smlaier	}
1046130610Smlaier	splx(s);
1047130610Smlaier	*size = n;
1048130610Smlaier	return (0);
1049130610Smlaier}
1050130610Smlaier
1051130610Smlaierstruct pfi_kif *
1052130610Smlaierpfi_lookup_if(const char *name)
1053130610Smlaier{
1054130610Smlaier	struct pfi_kif	*p, key;
1055130610Smlaier
1056130610Smlaier	strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
1057130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
1058130610Smlaier	return (p);
1059130610Smlaier}
1060130610Smlaier
1061130610Smlaierint
1062130610Smlaierpfi_skip_if(const char *filter, struct pfi_kif *p, int f)
1063130610Smlaier{
1064130610Smlaier	int	n;
1065130610Smlaier
1066130610Smlaier	if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
1067130610Smlaier		return (1);
1068130610Smlaier	if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
1069130610Smlaier		return (1);
1070130610Smlaier	if (filter == NULL || !*filter)
1071130610Smlaier		return (0);
1072130610Smlaier	if (!strcmp(p->pfik_name, filter))
1073130610Smlaier		return (0);	/* exact match */
1074130610Smlaier	n = strlen(filter);
1075130610Smlaier	if (n < 1 || n >= IFNAMSIZ)
1076130610Smlaier		return (1);	/* sanity check */
1077130610Smlaier	if (filter[n-1] >= '0' && filter[n-1] <= '9')
1078130610Smlaier		return (1);	/* only do exact match in that case */
1079130610Smlaier	if (strncmp(p->pfik_name, filter, n))
1080130610Smlaier		return (1);	/* prefix doesn't match */
1081130610Smlaier	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
1082130610Smlaier}
1083130610Smlaier
1084130610Smlaier/* from pf_print_state.c */
1085130610Smlaierint
1086130610Smlaierpfi_unmask(void *addr)
1087130610Smlaier{
1088130610Smlaier	struct pf_addr *m = addr;
1089130610Smlaier	int i = 31, j = 0, b = 0;
1090130610Smlaier	u_int32_t tmp;
1091130610Smlaier
1092130610Smlaier	while (j < 4 && m->addr32[j] == 0xffffffff) {
1093130610Smlaier		b += 32;
1094130610Smlaier		j++;
1095130610Smlaier	}
1096130610Smlaier	if (j < 4) {
1097130610Smlaier		tmp = ntohl(m->addr32[j]);
1098130610Smlaier		for (i = 31; tmp & (1 << i); --i)
1099130610Smlaier			b++;
1100130610Smlaier	}
1101130610Smlaier	return (b);
1102130610Smlaier}
1103130610Smlaier
1104130610Smlaiervoid
1105130610Smlaierpfi_dohooks(struct pfi_kif *p)
1106130610Smlaier{
1107130610Smlaier	for (; p != NULL; p = p->pfik_parent)
1108130610Smlaier		dohooks(p->pfik_ah_head, 0);
1109130610Smlaier}
1110130610Smlaier
1111130610Smlaierint
1112130610Smlaierpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
1113130610Smlaier{
1114130610Smlaier	if (af == AF_INET) {
1115130610Smlaier		switch (dyn->pfid_acnt4) {
1116130610Smlaier		case 0:
1117130610Smlaier			return (0);
1118130610Smlaier		case 1:
1119130610Smlaier			return (PF_MATCHA(0, &dyn->pfid_addr4,
1120130610Smlaier			    &dyn->pfid_mask4, a, AF_INET));
1121130610Smlaier		default:
1122130610Smlaier			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
1123130610Smlaier		}
1124130610Smlaier	} else {
1125130610Smlaier		switch (dyn->pfid_acnt6) {
1126130610Smlaier		case 0:
1127130610Smlaier			return (0);
1128130610Smlaier		case 1:
1129130610Smlaier			return (PF_MATCHA(0, &dyn->pfid_addr6,
1130130610Smlaier			    &dyn->pfid_mask6, a, AF_INET6));
1131130610Smlaier		default:
1132130610Smlaier			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
1133130610Smlaier		}
1134130610Smlaier	}
1135130610Smlaier}
1136