pf_if.c revision 137159
1130613Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf_if.c 137159 2004-11-03 17:21:12Z 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();
160137159Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link) {
161137159Smlaier		IFNET_RUNLOCK();
162137159Smlaier		pfi_attach_ifnet(ifp);
163137159Smlaier		IFNET_RLOCK();
164137159Smlaier	}
165130613Smlaier	IFNET_RUNLOCK();
166130613Smlaier	PF_UNLOCK();
167130613Smlaier	pfi_dummy = pfi_if_create("notyet", pfi_self,
168130613Smlaier	    PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
169130613Smlaier	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
170130613Smlaier	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
171130613Smlaier	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
172130613Smlaier	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
173130613Smlaier	pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
174130613Smlaier	    pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY);
175130613Smlaier#endif
176130610Smlaier}
177130610Smlaier
178130613Smlaier#ifdef __FreeBSD__
179130610Smlaiervoid
180130613Smlaierpfi_cleanup(void)
181130613Smlaier{
182130613Smlaier	struct pfi_kif *p, key;
183130613Smlaier	struct ifnet *ifp;
184130613Smlaier
185130613Smlaier	PF_ASSERT(MA_OWNED);
186132567Smlaier
187130613Smlaier	PF_UNLOCK();
188130613Smlaier	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
189130613Smlaier	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
190130613Smlaier	EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
191132567Smlaier	PF_LOCK();
192130613Smlaier
193130613Smlaier	IFNET_RLOCK();
194130613Smlaier	/* release PFI_IFLAG_INSTANCE */
195130613Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link) {
196130613Smlaier		strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
197130613Smlaier		p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
198130613Smlaier		if (p != NULL) {
199132567Smlaier			IFNET_RUNLOCK();
200130613Smlaier			pfi_detach_ifnet(ifp);
201132567Smlaier			IFNET_RLOCK();
202130613Smlaier		}
203130613Smlaier	}
204130613Smlaier	IFNET_RUNLOCK();
205130613Smlaier
206130613Smlaier	/* XXX clear all other interface group */
207130613Smlaier	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
208130613Smlaier		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
209130613Smlaier
210130613Smlaier		free(p->pfik_ah_head, PFI_MTYPE);
211130613Smlaier		free(p, PFI_MTYPE);
212130613Smlaier	}
213130613Smlaier	free(pfi_index2kif, PFI_MTYPE);
214130613Smlaier	free(pfi_buffer, PFI_MTYPE);
215130613Smlaier	pfi_index2kif = NULL;
216130613Smlaier	pfi_buffer = NULL;
217130613Smlaier	pfi_self = NULL;
218130613Smlaier}
219130613Smlaier
220130613Smlaier/*
221130613Smlaier * Wrapper functions for FreeBSD eventhandler
222130613Smlaier */
223130613Smlaiervoid
224130613Smlaierpfi_kifaddr_update_event(void *arg, struct ifnet *ifp)
225130613Smlaier{
226130613Smlaier	struct pfi_kif *p = arg;
227130613Smlaier
228130613Smlaier	PF_LOCK();
229130613Smlaier	/*
230130613Smlaier	 * Check to see if it is 'our' interface as we do not have per
231130613Smlaier	 * interface hooks and thus get an update for every interface.
232130613Smlaier	 */
233130613Smlaier	if (p && p->pfik_ifp == ifp)
234130613Smlaier		pfi_kifaddr_update(p);
235130613Smlaier	PF_UNLOCK();
236130613Smlaier}
237130613Smlaier
238130613Smlaiervoid
239130613Smlaierpfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
240130613Smlaier{
241130613Smlaier	PF_LOCK();
242130613Smlaier	pfi_attach_clone(ifc);
243130613Smlaier	PF_UNLOCK();
244130613Smlaier}
245130613Smlaier
246130613Smlaiervoid
247130613Smlaierpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
248130613Smlaier{
249130613Smlaier	PF_LOCK();
250137159Smlaier	pfi_attach_ifnet(ifp);
251130613Smlaier	PF_UNLOCK();
252130613Smlaier}
253130613Smlaier
254130613Smlaiervoid
255130613Smlaierpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
256130613Smlaier{
257130613Smlaier	PF_LOCK();
258130613Smlaier	pfi_detach_ifnet(ifp);
259130613Smlaier	PF_UNLOCK();
260130613Smlaier}
261130613Smlaier#endif /* __FreeBSD__ */
262130613Smlaier
263130613Smlaiervoid
264130610Smlaierpfi_attach_clone(struct if_clone *ifc)
265130610Smlaier{
266130610Smlaier	pfi_initialize();
267130610Smlaier	pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
268130610Smlaier}
269130610Smlaier
270130610Smlaiervoid
271130610Smlaierpfi_attach_ifnet(struct ifnet *ifp)
272130610Smlaier{
273130610Smlaier	struct pfi_kif	*p, *q, key;
274130610Smlaier	int		 s;
275130613Smlaier#ifdef __FreeBSD__
276130613Smlaier	int		 realname;
277130613Smlaier#endif
278130610Smlaier
279130610Smlaier	pfi_initialize();
280130610Smlaier	s = splsoftnet();
281130610Smlaier	pfi_update++;
282130610Smlaier	if (ifp->if_index >= pfi_indexlim) {
283130610Smlaier		/*
284130610Smlaier		 * grow pfi_index2kif,  similar to ifindex2ifnet code in if.c
285130610Smlaier		 */
286130610Smlaier		size_t m, n, oldlim;
287130610Smlaier		struct pfi_kif **mp, **np;
288130610Smlaier
289130610Smlaier		oldlim = pfi_indexlim;
290130610Smlaier		if (pfi_indexlim == 0)
291130610Smlaier			pfi_indexlim = 64;
292130610Smlaier		while (ifp->if_index >= pfi_indexlim)
293130610Smlaier			pfi_indexlim <<= 1;
294130610Smlaier
295130610Smlaier		m = oldlim * sizeof(struct pfi_kif *);
296130610Smlaier		mp = pfi_index2kif;
297130610Smlaier		n = pfi_indexlim * sizeof(struct pfi_kif *);
298130613Smlaier#ifdef __FreeBSD__
299130613Smlaier		np = malloc(n, PFI_MTYPE, M_NOWAIT);
300130613Smlaier#else
301130610Smlaier		np = malloc(n, PFI_MTYPE, M_DONTWAIT);
302130613Smlaier#endif
303130610Smlaier		if (np == NULL)
304130610Smlaier			panic("pfi_attach_ifnet: "
305130610Smlaier			    "cannot allocate translation table");
306130610Smlaier		bzero(np, n);
307130610Smlaier		if (mp != NULL)
308130610Smlaier			bcopy(mp, np, m);
309130610Smlaier		pfi_index2kif = np;
310130610Smlaier		if (mp != NULL)
311130610Smlaier			free(mp, PFI_MTYPE);
312130610Smlaier	}
313130610Smlaier
314130610Smlaier	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
315130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
316130613Smlaier#ifdef __FreeBSD__
317130613Smlaier	/* some additional trickery for placeholders */
318130613Smlaier	if ((p == NULL) || (p->pfik_parent == pfi_dummy)) {
319130613Smlaier		/* are we looking at a renamed instance or not? */
320130613Smlaier		pfi_copy_group(key.pfik_name, ifp->if_xname,
321130613Smlaier		    sizeof(key.pfik_name));
322130613Smlaier		realname = (strncmp(key.pfik_name, ifp->if_dname,
323130613Smlaier		    sizeof(key.pfik_name)) == 0);
324130613Smlaier		/* add group */
325130613Smlaier		/* we can change if_xname, hence use if_dname as group id */
326130613Smlaier		pfi_copy_group(key.pfik_name, ifp->if_dname,
327130613Smlaier		    sizeof(key.pfik_name));
328130613Smlaier		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
329130613Smlaier		if (q == NULL)
330130613Smlaier		    q = pfi_if_create(key.pfik_name, pfi_self,
331130613Smlaier		        PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC);
332130613Smlaier		else if (q->pfik_parent == pfi_dummy) {
333130613Smlaier			q->pfik_parent = pfi_self;
334130613Smlaier			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
335130613Smlaier		}
336130613Smlaier		if (q == NULL)
337130613Smlaier			panic("pfi_attach_ifnet: "
338130613Smlaier			    "cannot allocate '%s' group", key.pfik_name);
339130613Smlaier
340130613Smlaier		/* add/modify interface */
341130613Smlaier		if (p == NULL)
342137159Smlaier			p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE |
343137159Smlaier			    (realname?0:PFI_IFLAG_PLACEHOLDER));
344130613Smlaier		else {
345130613Smlaier			/* remove from the dummy group */
346130613Smlaier			/* XXX: copy stats? We should not have any!!! */
347130613Smlaier			pfi_dummy->pfik_delcnt++;
348130613Smlaier			TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p,
349130613Smlaier			    pfik_instances);
350130613Smlaier			/* move to the right group */
351130613Smlaier			p->pfik_parent = q;
352130613Smlaier			q->pfik_addcnt++;
353130613Smlaier			TAILQ_INSERT_TAIL(&q->pfik_grouphead, p,
354130613Smlaier			    pfik_instances);
355137159Smlaier			if (realname)
356130613Smlaier				p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER;
357137159Smlaier			p->pfik_flags |= PFI_IFLAG_INSTANCE;
358130613Smlaier		}
359130613Smlaier		if (p == NULL)
360130613Smlaier			panic("pfi_attach_ifnet: "
361130613Smlaier			    "cannot allocate '%s' interface", ifp->if_xname);
362130613Smlaier#else
363130610Smlaier	if (p == NULL) {
364130610Smlaier		/* add group */
365130610Smlaier		pfi_copy_group(key.pfik_name, ifp->if_xname,
366130610Smlaier		    sizeof(key.pfik_name));
367130610Smlaier		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
368130610Smlaier		if (q == NULL)
369130610Smlaier		    q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
370130613Smlaier		else if (q->pfik_parent == pfi_dummy) {
371130613Smlaier			q->pfik_parent = pfi_self;
372130613Smlaier			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
373130613Smlaier		}
374130610Smlaier		if (q == NULL)
375130610Smlaier			panic("pfi_attach_ifnet: "
376130610Smlaier			    "cannot allocate '%s' group", key.pfik_name);
377130610Smlaier
378130610Smlaier		/* add interface */
379130610Smlaier		p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
380130610Smlaier		if (p == NULL)
381130610Smlaier			panic("pfi_attach_ifnet: "
382130610Smlaier			    "cannot allocate '%s' interface", ifp->if_xname);
383130613Smlaier#endif
384130610Smlaier	} else
385130610Smlaier		q = p->pfik_parent;
386130610Smlaier	p->pfik_ifp = ifp;
387130610Smlaier	p->pfik_flags |= PFI_IFLAG_ATTACHED;
388130613Smlaier#ifdef __FreeBSD__
389130613Smlaier	PF_UNLOCK();
390130613Smlaier	p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
391130613Smlaier	    pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY);
392130613Smlaier	PF_LOCK();
393130613Smlaier#else
394130610Smlaier	p->pfik_ah_cookie =
395130610Smlaier	    hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
396130613Smlaier#endif
397130610Smlaier	pfi_index2kif[ifp->if_index] = p;
398130610Smlaier	pfi_dohooks(p);
399130610Smlaier	splx(s);
400130610Smlaier}
401130610Smlaier
402130610Smlaiervoid
403130610Smlaierpfi_detach_ifnet(struct ifnet *ifp)
404130610Smlaier{
405130610Smlaier	struct pfi_kif	*p, *q, key;
406130610Smlaier	int		 s;
407130610Smlaier
408130610Smlaier	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
409130610Smlaier
410130610Smlaier	s = splsoftnet();
411130610Smlaier	pfi_update++;
412130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
413130610Smlaier	if (p == NULL) {
414130610Smlaier		printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
415130610Smlaier		splx(s);
416130610Smlaier		return;
417130610Smlaier	}
418130613Smlaier#ifdef __FreeBSD__
419130613Smlaier	PF_UNLOCK();
420130613Smlaier	EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie);
421130613Smlaier	PF_LOCK();
422130613Smlaier#else
423130610Smlaier	hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
424130613Smlaier#endif
425130610Smlaier	q = p->pfik_parent;
426130610Smlaier	p->pfik_ifp = NULL;
427130610Smlaier	p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
428130610Smlaier	pfi_index2kif[ifp->if_index] = NULL;
429130610Smlaier	pfi_dohooks(p);
430130610Smlaier	pfi_maybe_destroy(p);
431130610Smlaier	splx(s);
432130610Smlaier}
433130610Smlaier
434130610Smlaierstruct pfi_kif *
435130610Smlaierpfi_lookup_create(const char *name)
436130610Smlaier{
437130610Smlaier	struct pfi_kif	*p, *q, key;
438130610Smlaier	int		 s;
439130610Smlaier
440130610Smlaier	s = splsoftnet();
441130610Smlaier	p = pfi_lookup_if(name);
442130610Smlaier	if (p == NULL) {
443130610Smlaier		pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
444130610Smlaier		q = pfi_lookup_if(key.pfik_name);
445130613Smlaier#ifdef __FreeBSD__
446130613Smlaier		if ((q != NULL) && (q->pfik_parent != pfi_dummy))
447130613Smlaier			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
448130613Smlaier		else {
449130613Smlaier			if (pfi_dummy == NULL)
450130613Smlaier				panic("no 'notyet' dummy group");
451130613Smlaier			p = pfi_if_create(name, pfi_dummy,
452130613Smlaier			    PFI_IFLAG_PLACEHOLDER);
453130613Smlaier		}
454130613Smlaier#else
455130610Smlaier		if (q != NULL)
456130610Smlaier			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
457130613Smlaier#endif
458130610Smlaier	}
459130610Smlaier	splx(s);
460130610Smlaier	return (p);
461130610Smlaier}
462130610Smlaier
463130610Smlaierstruct pfi_kif *
464130610Smlaierpfi_attach_rule(const char *name)
465130610Smlaier{
466130610Smlaier	struct pfi_kif	*p;
467130610Smlaier
468130610Smlaier	p = pfi_lookup_create(name);
469130610Smlaier	if (p != NULL)
470130610Smlaier		p->pfik_rules++;
471130610Smlaier	return (p);
472130610Smlaier}
473130610Smlaier
474130610Smlaiervoid
475130610Smlaierpfi_detach_rule(struct pfi_kif *p)
476130610Smlaier{
477130610Smlaier	if (p == NULL)
478130610Smlaier		return;
479130610Smlaier	if (p->pfik_rules > 0)
480130610Smlaier		p->pfik_rules--;
481130610Smlaier	else
482130610Smlaier		printf("pfi_detach_rule: reference count at 0\n");
483130610Smlaier	pfi_maybe_destroy(p);
484130610Smlaier}
485130610Smlaier
486130610Smlaiervoid
487130610Smlaierpfi_attach_state(struct pfi_kif *p)
488130610Smlaier{
489130610Smlaier	if (!p->pfik_states++)
490130610Smlaier		TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
491130610Smlaier}
492130610Smlaier
493130610Smlaiervoid
494130610Smlaierpfi_detach_state(struct pfi_kif *p)
495130610Smlaier{
496130610Smlaier	if (p == NULL)
497130610Smlaier		return;
498130610Smlaier	if (p->pfik_states <= 0) {
499130610Smlaier		printf("pfi_detach_state: reference count <= 0\n");
500130610Smlaier		return;
501130610Smlaier	}
502130610Smlaier	if (!--p->pfik_states)
503130610Smlaier		TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
504130610Smlaier	pfi_maybe_destroy(p);
505130610Smlaier}
506130610Smlaier
507130610Smlaierint
508130610Smlaierpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
509130610Smlaier{
510130610Smlaier	struct pfi_dynaddr	*dyn;
511130610Smlaier	char			 tblname[PF_TABLE_NAME_SIZE];
512130610Smlaier	struct pf_ruleset	*ruleset = NULL;
513130610Smlaier	int			 s, rv = 0;
514130610Smlaier
515130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL)
516130610Smlaier		return (0);
517130610Smlaier	dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
518130610Smlaier	if (dyn == NULL)
519130610Smlaier		return (1);
520130610Smlaier	bzero(dyn, sizeof(*dyn));
521130610Smlaier
522130610Smlaier	s = splsoftnet();
523130610Smlaier	dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
524130610Smlaier	if (dyn->pfid_kif == NULL)
525130610Smlaier		senderr(1);
526130610Smlaier
527130610Smlaier	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
528130610Smlaier	if (af == AF_INET && dyn->pfid_net == 32)
529130610Smlaier		dyn->pfid_net = 128;
530130610Smlaier	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
531130610Smlaier	if (aw->iflags & PFI_AFLAG_NETWORK)
532130610Smlaier		strlcat(tblname, ":network", sizeof(tblname));
533130610Smlaier	if (aw->iflags & PFI_AFLAG_BROADCAST)
534130610Smlaier		strlcat(tblname, ":broadcast", sizeof(tblname));
535130610Smlaier	if (aw->iflags & PFI_AFLAG_PEER)
536130610Smlaier		strlcat(tblname, ":peer", sizeof(tblname));
537130610Smlaier	if (aw->iflags & PFI_AFLAG_NOALIAS)
538130610Smlaier		strlcat(tblname, ":0", sizeof(tblname));
539130610Smlaier	if (dyn->pfid_net != 128)
540130610Smlaier		snprintf(tblname + strlen(tblname),
541130610Smlaier		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
542130610Smlaier	ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor,
543130610Smlaier	    pfi_interface_ruleset);
544130610Smlaier	if (ruleset == NULL)
545130610Smlaier		senderr(1);
546130610Smlaier
547130610Smlaier	dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
548130610Smlaier	if (dyn->pfid_kt == NULL)
549130610Smlaier		senderr(1);
550130610Smlaier
551130610Smlaier	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
552130610Smlaier	dyn->pfid_iflags = aw->iflags;
553130610Smlaier	dyn->pfid_af = af;
554130610Smlaier	dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
555130610Smlaier	    pfi_dynaddr_update, dyn);
556130610Smlaier	if (dyn->pfid_hook_cookie == NULL)
557130610Smlaier		senderr(1);
558130610Smlaier
559130610Smlaier	aw->p.dyn = dyn;
560130610Smlaier	pfi_dynaddr_update(aw->p.dyn);
561130610Smlaier	splx(s);
562130610Smlaier	return (0);
563130610Smlaier
564130610Smlaier_bad:
565130610Smlaier	if (dyn->pfid_kt != NULL)
566130610Smlaier		pfr_detach_table(dyn->pfid_kt);
567130610Smlaier	if (ruleset != NULL)
568130610Smlaier		pf_remove_if_empty_ruleset(ruleset);
569130610Smlaier	if (dyn->pfid_kif != NULL)
570130610Smlaier		pfi_detach_rule(dyn->pfid_kif);
571130610Smlaier	pool_put(&pfi_addr_pl, dyn);
572130610Smlaier	splx(s);
573130610Smlaier	return (rv);
574130610Smlaier}
575130610Smlaier
576130610Smlaiervoid
577130610Smlaierpfi_dynaddr_update(void *p)
578130610Smlaier{
579130610Smlaier	struct pfi_dynaddr	*dyn = (struct pfi_dynaddr *)p;
580130610Smlaier	struct pfi_kif		*kif = dyn->pfid_kif;
581130610Smlaier	struct pfr_ktable	*kt = dyn->pfid_kt;
582130610Smlaier
583130610Smlaier	if (dyn == NULL || kif == NULL || kt == NULL)
584130610Smlaier		panic("pfi_dynaddr_update");
585130610Smlaier	if (kt->pfrkt_larg != pfi_update) {
586130610Smlaier		/* this table needs to be brought up-to-date */
587130610Smlaier		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
588130610Smlaier		kt->pfrkt_larg = pfi_update;
589130610Smlaier	}
590130610Smlaier	pfr_dynaddr_update(kt, dyn);
591130610Smlaier}
592130610Smlaier
593130610Smlaiervoid
594130610Smlaierpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
595130610Smlaier{
596130610Smlaier	int			 e, size2 = 0;
597130610Smlaier	struct pfi_kif		*p;
598130610Smlaier	struct pfr_table	 t;
599130610Smlaier
600130610Smlaier	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
601130610Smlaier		pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
602130610Smlaier		return;
603130610Smlaier	}
604130610Smlaier	pfi_buffer_cnt = 0;
605130610Smlaier	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
606130610Smlaier		pfi_instance_add(kif->pfik_ifp, net, flags);
607130610Smlaier	else if (strcmp(kif->pfik_name, "self")) {
608130610Smlaier		TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
609130610Smlaier			pfi_instance_add(p->pfik_ifp, net, flags);
610130610Smlaier	} else {
611130610Smlaier		RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
612130610Smlaier			if (p->pfik_flags & PFI_IFLAG_INSTANCE)
613130610Smlaier				pfi_instance_add(p->pfik_ifp, net, flags);
614130610Smlaier	}
615130610Smlaier	t = kt->pfrkt_t;
616130610Smlaier	t.pfrt_flags = 0;
617130610Smlaier	if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
618130610Smlaier	    NULL, NULL, NULL, 0)))
619130610Smlaier		printf("pfi_table_update: cannot set %d new addresses "
620130610Smlaier		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
621130610Smlaier}
622130610Smlaier
623130610Smlaiervoid
624130610Smlaierpfi_instance_add(struct ifnet *ifp, int net, int flags)
625130610Smlaier{
626130610Smlaier	struct ifaddr	*ia;
627130610Smlaier	int		 got4 = 0, got6 = 0;
628130610Smlaier	int		 net2, af;
629130610Smlaier
630130610Smlaier	if (ifp == NULL)
631130610Smlaier		return;
632130610Smlaier	TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
633130610Smlaier		if (ia->ifa_addr == NULL)
634130610Smlaier			continue;
635130610Smlaier		af = ia->ifa_addr->sa_family;
636130610Smlaier		if (af != AF_INET && af != AF_INET6)
637130610Smlaier			continue;
638135215Smlaier#ifdef __FreeBSD__
639135215Smlaier		/*
640135215Smlaier		 * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
641135215Smlaier		 *	jump over addresses without a proper route to work
642135215Smlaier		 *	around a problem with ppp not fully removing the
643135215Smlaier		 *	address used during IPCP.
644135215Smlaier		 */
645135215Smlaier		if ((ifp->if_flags & IFF_POINTOPOINT) &&
646135215Smlaier		    !(ia->ifa_flags & IFA_ROUTE) &&
647135215Smlaier		    (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
648133573Smlaier			continue;
649133872Smlaier#endif
650130610Smlaier		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
651130610Smlaier			continue;
652130610Smlaier		if ((flags & PFI_AFLAG_BROADCAST) &&
653130610Smlaier		    !(ifp->if_flags & IFF_BROADCAST))
654130610Smlaier			continue;
655130610Smlaier		if ((flags & PFI_AFLAG_PEER) &&
656130610Smlaier		    !(ifp->if_flags & IFF_POINTOPOINT))
657130610Smlaier			continue;
658130610Smlaier		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
659130610Smlaier		    IN6_IS_ADDR_LINKLOCAL(
660130610Smlaier		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
661130610Smlaier			continue;
662130610Smlaier		if (flags & PFI_AFLAG_NOALIAS) {
663130610Smlaier			if (af == AF_INET && got4)
664130610Smlaier				continue;
665130610Smlaier			if (af == AF_INET6 && got6)
666130610Smlaier				continue;
667130610Smlaier		}
668130610Smlaier		if (af == AF_INET)
669130610Smlaier			got4 = 1;
670130610Smlaier		else
671130610Smlaier			got6 = 1;
672130610Smlaier		net2 = net;
673130610Smlaier		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
674130610Smlaier			if (af == AF_INET) {
675130610Smlaier				net2 = pfi_unmask(&((struct sockaddr_in *)
676130610Smlaier				    ia->ifa_netmask)->sin_addr);
677130610Smlaier			} else {
678130610Smlaier				net2 = pfi_unmask(&((struct sockaddr_in6 *)
679130610Smlaier				    ia->ifa_netmask)->sin6_addr);
680130610Smlaier			}
681130610Smlaier		}
682130610Smlaier		if (af == AF_INET && net2 > 32)
683130610Smlaier			net2 = 32;
684130610Smlaier		if (flags & PFI_AFLAG_BROADCAST)
685130610Smlaier			pfi_address_add(ia->ifa_broadaddr, af, net2);
686130610Smlaier		else if (flags & PFI_AFLAG_PEER)
687130610Smlaier			pfi_address_add(ia->ifa_dstaddr, af, net2);
688130610Smlaier		else
689130610Smlaier			pfi_address_add(ia->ifa_addr, af, net2);
690130610Smlaier	}
691130610Smlaier}
692130610Smlaier
693130610Smlaiervoid
694130610Smlaierpfi_address_add(struct sockaddr *sa, int af, int net)
695130610Smlaier{
696130610Smlaier	struct pfr_addr	*p;
697130610Smlaier	int		 i;
698130610Smlaier
699130610Smlaier	if (pfi_buffer_cnt >= pfi_buffer_max) {
700130610Smlaier		int		 new_max = pfi_buffer_max * 2;
701130610Smlaier
702130610Smlaier		if (new_max > PFI_BUFFER_MAX) {
703130610Smlaier			printf("pfi_address_add: address buffer full (%d/%d)\n",
704130610Smlaier			    pfi_buffer_cnt, PFI_BUFFER_MAX);
705130610Smlaier			return;
706130610Smlaier		}
707130613Smlaier#ifdef __FreeBSD__
708130610Smlaier		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
709130613Smlaier		    M_NOWAIT);
710130613Smlaier#else
711130613Smlaier		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
712130610Smlaier		    M_DONTWAIT);
713130613Smlaier#endif
714130610Smlaier		if (p == NULL) {
715130610Smlaier			printf("pfi_address_add: no memory to grow buffer "
716130610Smlaier			    "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
717130610Smlaier			return;
718130610Smlaier		}
719130610Smlaier		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
720130610Smlaier		/* no need to zero buffer */
721130610Smlaier		free(pfi_buffer, PFI_MTYPE);
722130610Smlaier		pfi_buffer = p;
723130610Smlaier		pfi_buffer_max = new_max;
724130610Smlaier	}
725130610Smlaier	if (af == AF_INET && net > 32)
726130610Smlaier		net = 128;
727130610Smlaier	p = pfi_buffer + pfi_buffer_cnt++;
728130610Smlaier	bzero(p, sizeof(*p));
729130610Smlaier	p->pfra_af = af;
730130610Smlaier	p->pfra_net = net;
731130610Smlaier	if (af == AF_INET)
732130610Smlaier		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
733130610Smlaier	if (af == AF_INET6) {
734130610Smlaier		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
735130610Smlaier		if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
736130610Smlaier			p->pfra_ip6addr.s6_addr16[1] = 0;
737130610Smlaier	}
738130610Smlaier	/* mask network address bits */
739130610Smlaier	if (net < 128)
740130610Smlaier		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
741130610Smlaier	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
742130610Smlaier		((caddr_t)p)[i] = 0;
743130610Smlaier}
744130610Smlaier
745130610Smlaiervoid
746130610Smlaierpfi_dynaddr_remove(struct pf_addr_wrap *aw)
747130610Smlaier{
748130610Smlaier	int	s;
749130610Smlaier
750130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
751130610Smlaier	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
752130610Smlaier		return;
753130610Smlaier
754130610Smlaier	s = splsoftnet();
755130610Smlaier	hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
756130610Smlaier	    aw->p.dyn->pfid_hook_cookie);
757130610Smlaier	pfi_detach_rule(aw->p.dyn->pfid_kif);
758130610Smlaier	aw->p.dyn->pfid_kif = NULL;
759130610Smlaier	pfr_detach_table(aw->p.dyn->pfid_kt);
760130610Smlaier	aw->p.dyn->pfid_kt = NULL;
761130610Smlaier	pool_put(&pfi_addr_pl, aw->p.dyn);
762130610Smlaier	aw->p.dyn = NULL;
763130610Smlaier	splx(s);
764130610Smlaier}
765130610Smlaier
766130610Smlaiervoid
767130610Smlaierpfi_dynaddr_copyout(struct pf_addr_wrap *aw)
768130610Smlaier{
769130610Smlaier	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
770130610Smlaier	    aw->p.dyn->pfid_kif == NULL)
771130610Smlaier		return;
772130610Smlaier	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
773130610Smlaier}
774130610Smlaier
775130610Smlaiervoid
776130610Smlaierpfi_kifaddr_update(void *v)
777130610Smlaier{
778130610Smlaier	int		 s;
779130610Smlaier
780130610Smlaier	s = splsoftnet();
781130610Smlaier	pfi_update++;
782130610Smlaier	pfi_dohooks(v);
783130610Smlaier	splx(s);
784130610Smlaier}
785130610Smlaier
786130610Smlaierint
787130610Smlaierpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
788130610Smlaier{
789130610Smlaier	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
790130610Smlaier}
791130610Smlaier
792130610Smlaierstruct pfi_kif *
793130610Smlaierpfi_if_create(const char *name, struct pfi_kif *q, int flags)
794130610Smlaier{
795130610Smlaier	struct pfi_kif *p;
796130610Smlaier
797130613Smlaier#ifdef __FreeBSD__
798130613Smlaier	p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT);
799130613Smlaier#else
800130610Smlaier	p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
801130613Smlaier#endif
802130610Smlaier	if (p == NULL)
803130610Smlaier		return (NULL);
804130610Smlaier	bzero(p, sizeof(*p));
805130613Smlaier#ifdef __FreeBSD__
806130610Smlaier	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
807130613Smlaier	    M_NOWAIT);
808130613Smlaier#else
809130613Smlaier	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
810130610Smlaier	    M_DONTWAIT);
811130613Smlaier#endif
812130610Smlaier	if (p->pfik_ah_head == NULL) {
813130610Smlaier		free(p, PFI_MTYPE);
814130610Smlaier		return (NULL);
815130610Smlaier	}
816130610Smlaier	bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
817130610Smlaier	TAILQ_INIT(p->pfik_ah_head);
818130610Smlaier	TAILQ_INIT(&p->pfik_grouphead);
819130610Smlaier	strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
820130610Smlaier	RB_INIT(&p->pfik_lan_ext);
821130610Smlaier	RB_INIT(&p->pfik_ext_gwy);
822130610Smlaier	p->pfik_flags = flags;
823130610Smlaier	p->pfik_parent = q;
824130613Smlaier#ifdef __FreeBSD__
825130613Smlaier	p->pfik_tzero = time_second;
826130613Smlaier#else
827130610Smlaier	p->pfik_tzero = time.tv_sec;
828130613Smlaier#endif
829130610Smlaier
830130610Smlaier	RB_INSERT(pfi_ifhead, &pfi_ifs, p);
831130610Smlaier	if (q != NULL) {
832130610Smlaier		q->pfik_addcnt++;
833130610Smlaier		TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
834130610Smlaier	}
835130610Smlaier	pfi_ifcnt++;
836130610Smlaier	return (p);
837130610Smlaier}
838130610Smlaier
839130610Smlaierint
840130610Smlaierpfi_maybe_destroy(struct pfi_kif *p)
841130610Smlaier{
842130610Smlaier	int		 i, j, k, s;
843130610Smlaier	struct pfi_kif	*q = p->pfik_parent;
844130610Smlaier
845130610Smlaier	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
846130610Smlaier	    p->pfik_rules > 0 || p->pfik_states > 0)
847130613Smlaier#ifdef __FreeBSD__
848130613Smlaier		if (!(p->pfik_flags & PFI_IFLAG_PLACEHOLDER))
849130613Smlaier#endif
850130610Smlaier		return (0);
851130610Smlaier
852130610Smlaier	s = splsoftnet();
853130610Smlaier	if (q != NULL) {
854130610Smlaier		for (i = 0; i < 2; i++)
855130610Smlaier			for (j = 0; j < 2; j++)
856130610Smlaier				for (k = 0; k < 2; k++) {
857130610Smlaier					q->pfik_bytes[i][j][k] +=
858130610Smlaier					    p->pfik_bytes[i][j][k];
859130610Smlaier					q->pfik_packets[i][j][k] +=
860130610Smlaier					    p->pfik_packets[i][j][k];
861130613Smlaier#ifdef __FreeBSD__
862130613Smlaier			/* clear stats in case we return to the dummy group */
863130613Smlaier					p->pfik_bytes[i][j][k] = 0;
864130613Smlaier					p->pfik_packets[i][j][k] = 0;
865130613Smlaier#endif
866130610Smlaier				}
867130610Smlaier		q->pfik_delcnt++;
868130610Smlaier		TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
869130610Smlaier	}
870130613Smlaier#ifdef __FreeBSD__
871130613Smlaier	if (p->pfik_rules > 0 || p->pfik_states > 0) {
872130613Smlaier		/* move back to the dummy group */
873130613Smlaier		p->pfik_parent = pfi_dummy;
874137159Smlaier		p->pfik_flags &= ~PFI_IFLAG_INSTANCE;
875130613Smlaier		pfi_dummy->pfik_addcnt++;
876130613Smlaier		TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p,
877130613Smlaier		    pfik_instances);
878130613Smlaier		return (0);
879130613Smlaier	}
880130613Smlaier#endif
881130610Smlaier	pfi_ifcnt--;
882130610Smlaier	RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
883130610Smlaier	splx(s);
884130610Smlaier
885130610Smlaier	free(p->pfik_ah_head, PFI_MTYPE);
886130610Smlaier	free(p, PFI_MTYPE);
887130610Smlaier	return (1);
888130610Smlaier}
889130610Smlaier
890130610Smlaiervoid
891130610Smlaierpfi_copy_group(char *p, const char *q, int m)
892130610Smlaier{
893130610Smlaier	while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
894130610Smlaier		*p++ = *q++;
895130610Smlaier		m--;
896130610Smlaier	}
897130610Smlaier	if (m > 0)
898130610Smlaier		*p++ = '\0';
899130610Smlaier}
900130610Smlaier
901130610Smlaiervoid
902130610Smlaierpfi_dynamic_drivers(void)
903130610Smlaier{
904130613Smlaier#ifdef __FreeBSD__
905130613Smlaier	struct ifnet	*ifp;
906130613Smlaier
907130613Smlaier/*
908130613Smlaier * For FreeBSD basically every interface is "dynamic" as we can unload
909130613Smlaier * modules e.g.
910130613Smlaier */
911130613Smlaier
912130613Smlaier	IFNET_RLOCK();
913137159Smlaier	TAILQ_FOREACH(ifp, &ifnet, if_link)
914130613Smlaier		pfi_newgroup(ifp->if_dname, PFI_IFLAG_DYNAMIC);
915130613Smlaier	IFNET_RUNLOCK();
916130613Smlaier#else
917130610Smlaier	char		*buses[] = PFI_DYNAMIC_BUSES;
918130610Smlaier	int		 nbuses = sizeof(buses)/sizeof(buses[0]);
919130610Smlaier	int		 enabled[sizeof(buses)/sizeof(buses[0])];
920130610Smlaier	struct device	*dev;
921130610Smlaier	struct cfdata	*cf;
922130610Smlaier	struct cfdriver	*drv;
923130610Smlaier	short		*p;
924130610Smlaier	int		 i;
925130610Smlaier
926130610Smlaier	bzero(enabled, sizeof(enabled));
927130610Smlaier	TAILQ_FOREACH(dev, &alldevs, dv_list) {
928130610Smlaier		if (!(dev->dv_flags & DVF_ACTIVE))
929130610Smlaier			continue;
930130610Smlaier		for (i = 0; i < nbuses; i++)
931130610Smlaier			if (!enabled[i] && !strcmp(buses[i],
932130610Smlaier			    dev->dv_cfdata->cf_driver->cd_name))
933130610Smlaier				enabled[i] = 1;
934130610Smlaier	}
935130610Smlaier	for (cf = cfdata; cf->cf_driver; cf++) {
936130610Smlaier		if (cf->cf_driver->cd_class != DV_IFNET)
937130610Smlaier			continue;
938130610Smlaier		for (p = cf->cf_parents; p && *p >= 0; p++) {
939130610Smlaier			if ((drv = cfdata[*p].cf_driver) == NULL)
940130610Smlaier				continue;
941130610Smlaier			for (i = 0; i < nbuses; i++)
942130610Smlaier				if (enabled[i] &&
943130610Smlaier				    !strcmp(drv->cd_name, buses[i]))
944130610Smlaier					break;
945130610Smlaier			if (i < nbuses) {
946130610Smlaier				pfi_newgroup(cf->cf_driver->cd_name,
947130610Smlaier				    PFI_IFLAG_DYNAMIC);
948130610Smlaier				break;
949130610Smlaier			}
950130610Smlaier		}
951130610Smlaier	}
952130613Smlaier#endif
953130610Smlaier}
954130610Smlaier
955130610Smlaiervoid
956130610Smlaierpfi_newgroup(const char *name, int flags)
957130610Smlaier{
958130610Smlaier	struct pfi_kif	*p;
959130610Smlaier
960130610Smlaier	p = pfi_lookup_if(name);
961130610Smlaier	if (p == NULL)
962130610Smlaier		p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
963130610Smlaier	if (p == NULL) {
964130610Smlaier		printf("pfi_newgroup: cannot allocate '%s' group", name);
965130610Smlaier		return;
966130610Smlaier	}
967130610Smlaier	p->pfik_flags |= flags;
968130610Smlaier}
969130610Smlaier
970130610Smlaiervoid
971130610Smlaierpfi_fill_oldstatus(struct pf_status *pfs)
972130610Smlaier{
973130610Smlaier	struct pfi_kif	*p, key;
974130610Smlaier	int		 i, j, k, s;
975130610Smlaier
976130610Smlaier	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
977130610Smlaier	s = splsoftnet();
978130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
979130610Smlaier	if (p == NULL) {
980130610Smlaier		splx(s);
981130610Smlaier		return;
982130610Smlaier	}
983130610Smlaier	bzero(pfs->pcounters, sizeof(pfs->pcounters));
984130610Smlaier	bzero(pfs->bcounters, sizeof(pfs->bcounters));
985130610Smlaier	for (i = 0; i < 2; i++)
986130610Smlaier		for (j = 0; j < 2; j++)
987130610Smlaier			for (k = 0; k < 2; k++) {
988130610Smlaier				pfs->pcounters[i][j][k] =
989130610Smlaier					p->pfik_packets[i][j][k];
990130610Smlaier				pfs->bcounters[i][j] +=
991130610Smlaier					p->pfik_bytes[i][j][k];
992130610Smlaier			}
993130610Smlaier	splx(s);
994130610Smlaier}
995130610Smlaier
996130610Smlaierint
997130610Smlaierpfi_clr_istats(const char *name, int *nzero, int flags)
998130610Smlaier{
999130610Smlaier	struct pfi_kif	*p;
1000130610Smlaier	int		 n = 0, s;
1001130613Smlaier#ifdef __FreeBSD__
1002130613Smlaier	long		 tzero = time_second;
1003130613Smlaier#else
1004130610Smlaier	long		 tzero = time.tv_sec;
1005130613Smlaier#endif
1006130610Smlaier
1007130610Smlaier	s = splsoftnet();
1008130610Smlaier	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1009130610Smlaier	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1010130610Smlaier		if (pfi_skip_if(name, p, flags))
1011130610Smlaier			continue;
1012130610Smlaier		bzero(p->pfik_packets, sizeof(p->pfik_packets));
1013130610Smlaier		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
1014130610Smlaier		p->pfik_tzero = tzero;
1015130610Smlaier		n++;
1016130610Smlaier	}
1017130610Smlaier	splx(s);
1018130610Smlaier	if (nzero != NULL)
1019130610Smlaier		*nzero = n;
1020130610Smlaier	return (0);
1021130610Smlaier}
1022130610Smlaier
1023130610Smlaierint
1024130610Smlaierpfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
1025130610Smlaier{
1026130610Smlaier	struct pfi_kif	*p;
1027130610Smlaier	int		 s, n = 0;
1028130613Smlaier#ifdef __FreeBSD__
1029130613Smlaier	int		 ec;
1030130613Smlaier#endif
1031130610Smlaier
1032130610Smlaier	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1033130610Smlaier	s = splsoftnet();
1034130610Smlaier	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1035130610Smlaier		if (pfi_skip_if(name, p, flags))
1036130610Smlaier			continue;
1037130610Smlaier		if (*size > n++) {
1038130610Smlaier			if (!p->pfik_tzero)
1039130610Smlaier				p->pfik_tzero = boottime.tv_sec;
1040130613Smlaier#ifdef __FreeBSD__
1041130613Smlaier			PF_COPYOUT(p, buf++, sizeof(*buf), ec);
1042130613Smlaier			if (ec) {
1043130613Smlaier#else
1044130610Smlaier			if (copyout(p, buf++, sizeof(*buf))) {
1045130613Smlaier#endif
1046130610Smlaier				splx(s);
1047130610Smlaier				return (EFAULT);
1048130610Smlaier			}
1049130610Smlaier		}
1050130610Smlaier	}
1051130610Smlaier	splx(s);
1052130610Smlaier	*size = n;
1053130610Smlaier	return (0);
1054130610Smlaier}
1055130610Smlaier
1056130610Smlaierstruct pfi_kif *
1057130610Smlaierpfi_lookup_if(const char *name)
1058130610Smlaier{
1059130610Smlaier	struct pfi_kif	*p, key;
1060130610Smlaier
1061130610Smlaier	strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
1062130610Smlaier	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
1063130610Smlaier	return (p);
1064130610Smlaier}
1065130610Smlaier
1066130610Smlaierint
1067130610Smlaierpfi_skip_if(const char *filter, struct pfi_kif *p, int f)
1068130610Smlaier{
1069130610Smlaier	int	n;
1070130610Smlaier
1071130610Smlaier	if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
1072130610Smlaier		return (1);
1073130610Smlaier	if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
1074130610Smlaier		return (1);
1075130610Smlaier	if (filter == NULL || !*filter)
1076130610Smlaier		return (0);
1077130610Smlaier	if (!strcmp(p->pfik_name, filter))
1078130610Smlaier		return (0);	/* exact match */
1079130610Smlaier	n = strlen(filter);
1080130610Smlaier	if (n < 1 || n >= IFNAMSIZ)
1081130610Smlaier		return (1);	/* sanity check */
1082130610Smlaier	if (filter[n-1] >= '0' && filter[n-1] <= '9')
1083130610Smlaier		return (1);	/* only do exact match in that case */
1084130610Smlaier	if (strncmp(p->pfik_name, filter, n))
1085130610Smlaier		return (1);	/* prefix doesn't match */
1086130610Smlaier	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
1087130610Smlaier}
1088130610Smlaier
1089130610Smlaier/* from pf_print_state.c */
1090130610Smlaierint
1091130610Smlaierpfi_unmask(void *addr)
1092130610Smlaier{
1093130610Smlaier	struct pf_addr *m = addr;
1094130610Smlaier	int i = 31, j = 0, b = 0;
1095130610Smlaier	u_int32_t tmp;
1096130610Smlaier
1097130610Smlaier	while (j < 4 && m->addr32[j] == 0xffffffff) {
1098130610Smlaier		b += 32;
1099130610Smlaier		j++;
1100130610Smlaier	}
1101130610Smlaier	if (j < 4) {
1102130610Smlaier		tmp = ntohl(m->addr32[j]);
1103130610Smlaier		for (i = 31; tmp & (1 << i); --i)
1104130610Smlaier			b++;
1105130610Smlaier	}
1106130610Smlaier	return (b);
1107130610Smlaier}
1108130610Smlaier
1109130610Smlaiervoid
1110130610Smlaierpfi_dohooks(struct pfi_kif *p)
1111130610Smlaier{
1112130610Smlaier	for (; p != NULL; p = p->pfik_parent)
1113130610Smlaier		dohooks(p->pfik_ah_head, 0);
1114130610Smlaier}
1115130610Smlaier
1116130610Smlaierint
1117130610Smlaierpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
1118130610Smlaier{
1119130610Smlaier	if (af == AF_INET) {
1120130610Smlaier		switch (dyn->pfid_acnt4) {
1121130610Smlaier		case 0:
1122130610Smlaier			return (0);
1123130610Smlaier		case 1:
1124130610Smlaier			return (PF_MATCHA(0, &dyn->pfid_addr4,
1125130610Smlaier			    &dyn->pfid_mask4, a, AF_INET));
1126130610Smlaier		default:
1127130610Smlaier			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
1128130610Smlaier		}
1129130610Smlaier	} else {
1130130610Smlaier		switch (dyn->pfid_acnt6) {
1131130610Smlaier		case 0:
1132130610Smlaier			return (0);
1133130610Smlaier		case 1:
1134130610Smlaier			return (PF_MATCHA(0, &dyn->pfid_addr6,
1135130610Smlaier			    &dyn->pfid_mask6, a, AF_INET6));
1136130610Smlaier		default:
1137130610Smlaier			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
1138130610Smlaier		}
1139130610Smlaier	}
1140130610Smlaier}
1141