pf_if.c revision 133872
1214571Sdim/*	$FreeBSD: head/sys/contrib/pf/net/pf_if.c 133872 2004-08-16 17:58:12Z mlaier $ */
2214571Sdim/*	$OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */
3214571Sdim/* add	$OpenBSD: pf_if.c,v 1.19 2004/08/11 12:06:44 henning Exp $ */
4214571Sdim
5214571Sdim/*
6214571Sdim * Copyright (c) 2001 Daniel Hartmeier
7214571Sdim * Copyright (c) 2003 Cedric Berger
8214571Sdim * All rights reserved.
9214571Sdim *
10214571Sdim * Redistribution and use in source and binary forms, with or without
11214571Sdim * modification, are permitted provided that the following conditions
12214571Sdim * are met:
13214571Sdim *
14214571Sdim *    - Redistributions of source code must retain the above copyright
15214571Sdim *      notice, this list of conditions and the following disclaimer.
16214571Sdim *    - Redistributions in binary form must reproduce the above
17214571Sdim *      copyright notice, this list of conditions and the following
18214571Sdim *      disclaimer in the documentation and/or other materials provided
19214571Sdim *      with the distribution.
20214571Sdim *
21214571Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22214571Sdim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23214571Sdim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24214571Sdim * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25214571Sdim * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26214571Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27214571Sdim * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28214571Sdim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29214571Sdim * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30214571Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31214571Sdim * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32214571Sdim * POSSIBILITY OF SUCH DAMAGE.
33214571Sdim */
34214571Sdim
35214571Sdim#if defined(__FreeBSD__)
36214571Sdim#include "opt_inet.h"
37214571Sdim#include "opt_inet6.h"
38214571Sdim#endif
39214571Sdim
40214571Sdim#include <sys/param.h>
41214571Sdim#include <sys/systm.h>
42214571Sdim#ifdef __FreeBSD__
43214571Sdim#include <sys/malloc.h>
44214571Sdim#endif
45214571Sdim#include <sys/mbuf.h>
46214571Sdim#include <sys/filio.h>
47214571Sdim#include <sys/socket.h>
48214571Sdim#include <sys/socketvar.h>
49214571Sdim#include <sys/kernel.h>
50214571Sdim#ifndef __FreeBSD__
51214571Sdim#include <sys/device.h>
52214571Sdim#endif
53214571Sdim#include <sys/time.h>
54214571Sdim
55214571Sdim#include <net/if.h>
56214571Sdim#include <net/if_types.h>
57214571Sdim#include <net/route.h>
58214571Sdim
59214571Sdim#include <netinet/in.h>
60214571Sdim#include <netinet/in_var.h>
61214571Sdim#include <netinet/in_systm.h>
62214571Sdim#include <netinet/ip.h>
63214571Sdim#include <netinet/ip_var.h>
64214571Sdim
65214571Sdim#include <net/pfvar.h>
66214571Sdim
67214571Sdim#ifdef INET6
68214571Sdim#include <netinet/ip6.h>
69214571Sdim#endif /* INET6 */
70214571Sdim
71214571Sdim#define ACCEPT_FLAGS(oklist)			\
72214571Sdim	do {					\
73214571Sdim		if ((flags & ~(oklist)) &	\
74214571Sdim		    PFI_FLAG_ALLMASK)		\
75214571Sdim			return (EINVAL);	\
76214571Sdim	} while (0)
77214571Sdim
78214571Sdim#define senderr(e)      do { rv = (e); goto _bad; } while (0)
79214571Sdim
80214571Sdimstruct pfi_kif		**pfi_index2kif;
81214571Sdimstruct pfi_kif		 *pfi_self, *pfi_dummy;
82214571Sdimint			  pfi_indexlim;
83214571Sdimstruct pfi_ifhead	  pfi_ifs;
84214571Sdimstruct pfi_statehead	  pfi_statehead;
85214571Sdimint			  pfi_ifcnt;
86214571Sdim#ifdef __FreeBSD__
87214571Sdimuma_zone_t		  pfi_addr_pl;
88214571Sdim#else
89214571Sdimstruct pool		  pfi_addr_pl;
90214571Sdim#endif
91214571Sdimlong			  pfi_update = 1;
92214571Sdimstruct pfr_addr		 *pfi_buffer;
93214571Sdimint			  pfi_buffer_cnt;
94214571Sdimint			  pfi_buffer_max;
95214571Sdimchar			  pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] =
96214571Sdim				PF_RESERVED_ANCHOR;
97214571Sdimchar			  pfi_interface_ruleset[PF_RULESET_NAME_SIZE] =
98214571Sdim				PF_INTERFACE_RULESET;
99214571Sdim#ifdef __FreeBSD__
100214571Sdimeventhandler_tag	 pfi_clone_cookie = NULL;
101214571Sdimeventhandler_tag	 pfi_attach_cookie = NULL;
102214571Sdimeventhandler_tag	 pfi_detach_cookie = NULL;
103214571Sdim#endif
104214571Sdim
105214571Sdimvoid		 pfi_dynaddr_update(void *);
106214571Sdimvoid		 pfi_kifaddr_update(void *);
107214571Sdimvoid		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
108214571Sdim		    int, int);
109214571Sdimvoid		 pfi_instance_add(struct ifnet *, int, int);
110214571Sdimvoid		 pfi_address_add(struct sockaddr *, int, int);
111214571Sdimint		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
112214571Sdimstruct pfi_kif	*pfi_if_create(const char *, struct pfi_kif *, int);
113214571Sdimvoid		 pfi_copy_group(char *, const char *, int);
114214571Sdimvoid		 pfi_dynamic_drivers(void);
115214571Sdimvoid		 pfi_newgroup(const char *, int);
116214571Sdimint		 pfi_skip_if(const char *, struct pfi_kif *, int);
117214571Sdimint		 pfi_unmask(void *);
118214571Sdimvoid		 pfi_dohooks(struct pfi_kif *);
119214571Sdim#ifdef __FreeBSD__
120214571Sdimvoid		 pfi_kifaddr_update_event(void *, struct ifnet *);
121214571Sdimvoid		 pfi_attach_clone_event(void * __unused, struct if_clone *);
122214571Sdimvoid		 pfi_attach_ifnet_event(void * __unused, struct ifnet *);
123214571Sdimvoid		 pfi_detach_ifnet_event(void * __unused, struct ifnet *);
124214571Sdim#endif
125214571Sdim
126214571SdimRB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
127214571SdimRB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
128214571Sdim
129214571Sdim#define PFI_DYNAMIC_BUSES	{ "pcmcia", "cardbus", "uhub" }
130214571Sdim#define PFI_BUFFER_MAX		0x10000
131214571Sdim#ifdef __FreeBSD__
132214571SdimMALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
133214571Sdim#else
134214571Sdim#define PFI_MTYPE		M_IFADDR
135214571Sdim#endif
136214571Sdim
137214571Sdimvoid
138214571Sdimpfi_initialize(void)
139214571Sdim{
140214571Sdim#ifdef __FreeBSD__
141214571Sdim	struct ifnet	*ifp;
142214571Sdim#endif
143214571Sdim
144214571Sdim	if (pfi_self != NULL)	/* already initialized */
145214571Sdim		return;
146214571Sdim
147214571Sdim	TAILQ_INIT(&pfi_statehead);
148214571Sdim#ifndef __FreeBSD__
149214571Sdim	pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
150214571Sdim	    "pfiaddrpl", &pool_allocator_nointr);
151214571Sdim#endif
152214571Sdim	pfi_buffer_max = 64;
153214571Sdim	pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
154214571Sdim	    PFI_MTYPE, M_WAITOK);
155214571Sdim	pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
156214571Sdim	pfi_dynamic_drivers();
157214571Sdim#ifdef __FreeBSD__
158214571Sdim	PF_LOCK();
159214571Sdim	IFNET_RLOCK();
160214571Sdim	TAILQ_FOREACH(ifp, &ifnet, if_link)
161214571Sdim		if (ifp->if_dunit != IF_DUNIT_NONE) {
162214571Sdim			IFNET_RUNLOCK();
163214571Sdim			pfi_attach_ifnet(ifp);
164214571Sdim			IFNET_RLOCK();
165214571Sdim		}
166214571Sdim	IFNET_RUNLOCK();
167214571Sdim	PF_UNLOCK();
168214571Sdim	pfi_dummy = pfi_if_create("notyet", pfi_self,
169214571Sdim	    PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
170214571Sdim	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
171214571Sdim	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
172214571Sdim	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
173214571Sdim	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
174214571Sdim	pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
175214571Sdim	    pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY);
176214571Sdim#endif
177214571Sdim}
178214571Sdim
179214571Sdim#ifdef __FreeBSD__
180214571Sdimvoid
181214571Sdimpfi_cleanup(void)
182214571Sdim{
183214571Sdim	struct pfi_kif *p, key;
184214571Sdim	struct ifnet *ifp;
185214571Sdim
186214571Sdim	PF_ASSERT(MA_OWNED);
187214571Sdim
188214571Sdim	PF_UNLOCK();
189214571Sdim	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
190214571Sdim	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
191214571Sdim	EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
192214571Sdim	PF_LOCK();
193214571Sdim
194214571Sdim	IFNET_RLOCK();
195214571Sdim	/* release PFI_IFLAG_INSTANCE */
196214571Sdim	TAILQ_FOREACH(ifp, &ifnet, if_link) {
197214571Sdim		strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
198214571Sdim		p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
199214571Sdim		if (p != NULL) {
200214571Sdim			IFNET_RUNLOCK();
201214571Sdim			pfi_detach_ifnet(ifp);
202214571Sdim			IFNET_RLOCK();
203214571Sdim		}
204214571Sdim	}
205214571Sdim	IFNET_RUNLOCK();
206214571Sdim
207214571Sdim	/* XXX clear all other interface group */
208214571Sdim	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
209214571Sdim		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
210214571Sdim
211214571Sdim		free(p->pfik_ah_head, PFI_MTYPE);
212214571Sdim		free(p, PFI_MTYPE);
213214571Sdim	}
214214571Sdim	free(pfi_index2kif, PFI_MTYPE);
215214571Sdim	free(pfi_buffer, PFI_MTYPE);
216214571Sdim	pfi_index2kif = NULL;
217214571Sdim	pfi_buffer = NULL;
218214571Sdim	pfi_self = NULL;
219214571Sdim}
220214571Sdim
221214571Sdim/*
222214571Sdim * Wrapper functions for FreeBSD eventhandler
223214571Sdim */
224214571Sdimvoid
225214571Sdimpfi_kifaddr_update_event(void *arg, struct ifnet *ifp)
226214571Sdim{
227214571Sdim	struct pfi_kif *p = arg;
228214571Sdim
229214571Sdim	PF_LOCK();
230214571Sdim	/*
231214571Sdim	 * Check to see if it is 'our' interface as we do not have per
232214571Sdim	 * interface hooks and thus get an update for every interface.
233214571Sdim	 */
234214571Sdim	if (p && p->pfik_ifp == ifp)
235214571Sdim		pfi_kifaddr_update(p);
236214571Sdim	PF_UNLOCK();
237214571Sdim}
238214571Sdim
239214571Sdimvoid
240214571Sdimpfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
241214571Sdim{
242214571Sdim	PF_LOCK();
243214571Sdim	pfi_attach_clone(ifc);
244214571Sdim	PF_UNLOCK();
245214571Sdim}
246214571Sdim
247214571Sdimvoid
248214571Sdimpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
249214571Sdim{
250214571Sdim	PF_LOCK();
251214571Sdim	if (ifp->if_dunit != IF_DUNIT_NONE)
252214571Sdim		pfi_attach_ifnet(ifp);
253214571Sdim	PF_UNLOCK();
254214571Sdim}
255214571Sdim
256214571Sdimvoid
257214571Sdimpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
258214571Sdim{
259214571Sdim	PF_LOCK();
260214571Sdim	pfi_detach_ifnet(ifp);
261214571Sdim	PF_UNLOCK();
262214571Sdim}
263214571Sdim#endif /* __FreeBSD__ */
264214571Sdim
265214571Sdimvoid
266214571Sdimpfi_attach_clone(struct if_clone *ifc)
267214571Sdim{
268214571Sdim	pfi_initialize();
269214571Sdim	pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
270214571Sdim}
271214571Sdim
272214571Sdimvoid
273214571Sdimpfi_attach_ifnet(struct ifnet *ifp)
274214571Sdim{
275214571Sdim	struct pfi_kif	*p, *q, key;
276214571Sdim	int		 s;
277214571Sdim#ifdef __FreeBSD__
278214571Sdim	int		 realname;
279214571Sdim#endif
280214571Sdim
281214571Sdim	pfi_initialize();
282214571Sdim	s = splsoftnet();
283214571Sdim	pfi_update++;
284214571Sdim	if (ifp->if_index >= pfi_indexlim) {
285214571Sdim		/*
286214571Sdim		 * grow pfi_index2kif,  similar to ifindex2ifnet code in if.c
287214571Sdim		 */
288214571Sdim		size_t m, n, oldlim;
289214571Sdim		struct pfi_kif **mp, **np;
290214571Sdim
291214571Sdim		oldlim = pfi_indexlim;
292214571Sdim		if (pfi_indexlim == 0)
293214571Sdim			pfi_indexlim = 64;
294214571Sdim		while (ifp->if_index >= pfi_indexlim)
295214571Sdim			pfi_indexlim <<= 1;
296214571Sdim
297214571Sdim		m = oldlim * sizeof(struct pfi_kif *);
298214571Sdim		mp = pfi_index2kif;
299214571Sdim		n = pfi_indexlim * sizeof(struct pfi_kif *);
300214571Sdim#ifdef __FreeBSD__
301214571Sdim		np = malloc(n, PFI_MTYPE, M_NOWAIT);
302214571Sdim#else
303214571Sdim		np = malloc(n, PFI_MTYPE, M_DONTWAIT);
304214571Sdim#endif
305214571Sdim		if (np == NULL)
306214571Sdim			panic("pfi_attach_ifnet: "
307214571Sdim			    "cannot allocate translation table");
308214571Sdim		bzero(np, n);
309214571Sdim		if (mp != NULL)
310214571Sdim			bcopy(mp, np, m);
311214571Sdim		pfi_index2kif = np;
312214571Sdim		if (mp != NULL)
313214571Sdim			free(mp, PFI_MTYPE);
314214571Sdim	}
315214571Sdim
316214571Sdim	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
317214571Sdim	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
318214571Sdim#ifdef __FreeBSD__
319214571Sdim	/* some additional trickery for placeholders */
320214571Sdim	if ((p == NULL) || (p->pfik_parent == pfi_dummy)) {
321214571Sdim		/* are we looking at a renamed instance or not? */
322214571Sdim		pfi_copy_group(key.pfik_name, ifp->if_xname,
323214571Sdim		    sizeof(key.pfik_name));
324214571Sdim		realname = (strncmp(key.pfik_name, ifp->if_dname,
325214571Sdim		    sizeof(key.pfik_name)) == 0);
326214571Sdim		/* add group */
327214571Sdim		/* we can change if_xname, hence use if_dname as group id */
328214571Sdim		pfi_copy_group(key.pfik_name, ifp->if_dname,
329214571Sdim		    sizeof(key.pfik_name));
330214571Sdim		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
331214571Sdim		if (q == NULL)
332214571Sdim		    q = pfi_if_create(key.pfik_name, pfi_self,
333214571Sdim		        PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC);
334214571Sdim		else if (q->pfik_parent == pfi_dummy) {
335214571Sdim			q->pfik_parent = pfi_self;
336214571Sdim			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
337214571Sdim		}
338214571Sdim		if (q == NULL)
339214571Sdim			panic("pfi_attach_ifnet: "
340214571Sdim			    "cannot allocate '%s' group", key.pfik_name);
341214571Sdim
342214571Sdim		/* add/modify interface */
343214571Sdim		if (p == NULL)
344214571Sdim			p = pfi_if_create(ifp->if_xname, q,
345214571Sdim			    realname?PFI_IFLAG_INSTANCE:PFI_IFLAG_PLACEHOLDER);
346214571Sdim		else {
347214571Sdim			/* remove from the dummy group */
348214571Sdim			/* XXX: copy stats? We should not have any!!! */
349214571Sdim			pfi_dummy->pfik_delcnt++;
350214571Sdim			TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p,
351214571Sdim			    pfik_instances);
352214571Sdim			/* move to the right group */
353214571Sdim			p->pfik_parent = q;
354214571Sdim			q->pfik_addcnt++;
355214571Sdim			TAILQ_INSERT_TAIL(&q->pfik_grouphead, p,
356214571Sdim			    pfik_instances);
357214571Sdim			if (realname) {
358214571Sdim				p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER;
359214571Sdim				p->pfik_flags |= PFI_IFLAG_INSTANCE;
360214571Sdim			}
361214571Sdim		}
362214571Sdim		if (p == NULL)
363214571Sdim			panic("pfi_attach_ifnet: "
364214571Sdim			    "cannot allocate '%s' interface", ifp->if_xname);
365214571Sdim#else
366214571Sdim	if (p == NULL) {
367214571Sdim		/* add group */
368214571Sdim		pfi_copy_group(key.pfik_name, ifp->if_xname,
369214571Sdim		    sizeof(key.pfik_name));
370214571Sdim		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
371214571Sdim		if (q == NULL)
372214571Sdim		    q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
373214571Sdim		else if (q->pfik_parent == pfi_dummy) {
374214571Sdim			q->pfik_parent = pfi_self;
375214571Sdim			q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC);
376214571Sdim		}
377214571Sdim		if (q == NULL)
378214571Sdim			panic("pfi_attach_ifnet: "
379214571Sdim			    "cannot allocate '%s' group", key.pfik_name);
380214571Sdim
381214571Sdim		/* add interface */
382214571Sdim		p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
383214571Sdim		if (p == NULL)
384214571Sdim			panic("pfi_attach_ifnet: "
385214571Sdim			    "cannot allocate '%s' interface", ifp->if_xname);
386214571Sdim#endif
387214571Sdim	} else
388214571Sdim		q = p->pfik_parent;
389214571Sdim	p->pfik_ifp = ifp;
390214571Sdim	p->pfik_flags |= PFI_IFLAG_ATTACHED;
391214571Sdim#ifdef __FreeBSD__
392214571Sdim	PF_UNLOCK();
393214571Sdim	p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
394214571Sdim	    pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY);
395214571Sdim	PF_LOCK();
396214571Sdim#else
397214571Sdim	p->pfik_ah_cookie =
398214571Sdim	    hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
399214571Sdim#endif
400214571Sdim	pfi_index2kif[ifp->if_index] = p;
401214571Sdim	pfi_dohooks(p);
402214571Sdim	splx(s);
403214571Sdim}
404214571Sdim
405214571Sdimvoid
406214571Sdimpfi_detach_ifnet(struct ifnet *ifp)
407214571Sdim{
408214571Sdim	struct pfi_kif	*p, *q, key;
409214571Sdim	int		 s;
410214571Sdim
411214571Sdim	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
412214571Sdim
413214571Sdim	s = splsoftnet();
414214571Sdim	pfi_update++;
415214571Sdim	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
416214571Sdim	if (p == NULL) {
417214571Sdim		printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
418		splx(s);
419		return;
420	}
421#ifdef __FreeBSD__
422	PF_UNLOCK();
423	EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie);
424	PF_LOCK();
425#else
426	hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
427#endif
428	q = p->pfik_parent;
429	p->pfik_ifp = NULL;
430	p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
431	pfi_index2kif[ifp->if_index] = NULL;
432	pfi_dohooks(p);
433	pfi_maybe_destroy(p);
434	splx(s);
435}
436
437struct pfi_kif *
438pfi_lookup_create(const char *name)
439{
440	struct pfi_kif	*p, *q, key;
441	int		 s;
442
443	s = splsoftnet();
444	p = pfi_lookup_if(name);
445	if (p == NULL) {
446		pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
447		q = pfi_lookup_if(key.pfik_name);
448#ifdef __FreeBSD__
449		if ((q != NULL) && (q->pfik_parent != pfi_dummy))
450			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
451		else {
452			if (pfi_dummy == NULL)
453				panic("no 'notyet' dummy group");
454			p = pfi_if_create(name, pfi_dummy,
455			    PFI_IFLAG_PLACEHOLDER);
456		}
457#else
458		if (q != NULL)
459			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
460#endif
461	}
462	splx(s);
463	return (p);
464}
465
466struct pfi_kif *
467pfi_attach_rule(const char *name)
468{
469	struct pfi_kif	*p;
470
471	p = pfi_lookup_create(name);
472	if (p != NULL)
473		p->pfik_rules++;
474	return (p);
475}
476
477void
478pfi_detach_rule(struct pfi_kif *p)
479{
480	if (p == NULL)
481		return;
482	if (p->pfik_rules > 0)
483		p->pfik_rules--;
484	else
485		printf("pfi_detach_rule: reference count at 0\n");
486	pfi_maybe_destroy(p);
487}
488
489void
490pfi_attach_state(struct pfi_kif *p)
491{
492	if (!p->pfik_states++)
493		TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
494}
495
496void
497pfi_detach_state(struct pfi_kif *p)
498{
499	if (p == NULL)
500		return;
501	if (p->pfik_states <= 0) {
502		printf("pfi_detach_state: reference count <= 0\n");
503		return;
504	}
505	if (!--p->pfik_states)
506		TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
507	pfi_maybe_destroy(p);
508}
509
510int
511pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
512{
513	struct pfi_dynaddr	*dyn;
514	char			 tblname[PF_TABLE_NAME_SIZE];
515	struct pf_ruleset	*ruleset = NULL;
516	int			 s, rv = 0;
517
518	if (aw->type != PF_ADDR_DYNIFTL)
519		return (0);
520	dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
521	if (dyn == NULL)
522		return (1);
523	bzero(dyn, sizeof(*dyn));
524
525	s = splsoftnet();
526	dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
527	if (dyn->pfid_kif == NULL)
528		senderr(1);
529
530	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
531	if (af == AF_INET && dyn->pfid_net == 32)
532		dyn->pfid_net = 128;
533	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
534	if (aw->iflags & PFI_AFLAG_NETWORK)
535		strlcat(tblname, ":network", sizeof(tblname));
536	if (aw->iflags & PFI_AFLAG_BROADCAST)
537		strlcat(tblname, ":broadcast", sizeof(tblname));
538	if (aw->iflags & PFI_AFLAG_PEER)
539		strlcat(tblname, ":peer", sizeof(tblname));
540	if (aw->iflags & PFI_AFLAG_NOALIAS)
541		strlcat(tblname, ":0", sizeof(tblname));
542	if (dyn->pfid_net != 128)
543		snprintf(tblname + strlen(tblname),
544		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
545	ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor,
546	    pfi_interface_ruleset);
547	if (ruleset == NULL)
548		senderr(1);
549
550	dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
551	if (dyn->pfid_kt == NULL)
552		senderr(1);
553
554	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
555	dyn->pfid_iflags = aw->iflags;
556	dyn->pfid_af = af;
557	dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
558	    pfi_dynaddr_update, dyn);
559	if (dyn->pfid_hook_cookie == NULL)
560		senderr(1);
561
562	aw->p.dyn = dyn;
563	pfi_dynaddr_update(aw->p.dyn);
564	splx(s);
565	return (0);
566
567_bad:
568	if (dyn->pfid_kt != NULL)
569		pfr_detach_table(dyn->pfid_kt);
570	if (ruleset != NULL)
571		pf_remove_if_empty_ruleset(ruleset);
572	if (dyn->pfid_kif != NULL)
573		pfi_detach_rule(dyn->pfid_kif);
574	pool_put(&pfi_addr_pl, dyn);
575	splx(s);
576	return (rv);
577}
578
579void
580pfi_dynaddr_update(void *p)
581{
582	struct pfi_dynaddr	*dyn = (struct pfi_dynaddr *)p;
583	struct pfi_kif		*kif = dyn->pfid_kif;
584	struct pfr_ktable	*kt = dyn->pfid_kt;
585
586	if (dyn == NULL || kif == NULL || kt == NULL)
587		panic("pfi_dynaddr_update");
588	if (kt->pfrkt_larg != pfi_update) {
589		/* this table needs to be brought up-to-date */
590		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
591		kt->pfrkt_larg = pfi_update;
592	}
593	pfr_dynaddr_update(kt, dyn);
594}
595
596void
597pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
598{
599	int			 e, size2 = 0;
600	struct pfi_kif		*p;
601	struct pfr_table	 t;
602
603	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
604		pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
605		return;
606	}
607	pfi_buffer_cnt = 0;
608	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
609		pfi_instance_add(kif->pfik_ifp, net, flags);
610	else if (strcmp(kif->pfik_name, "self")) {
611		TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
612			pfi_instance_add(p->pfik_ifp, net, flags);
613	} else {
614		RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
615			if (p->pfik_flags & PFI_IFLAG_INSTANCE)
616				pfi_instance_add(p->pfik_ifp, net, flags);
617	}
618	t = kt->pfrkt_t;
619	t.pfrt_flags = 0;
620	if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
621	    NULL, NULL, NULL, 0)))
622		printf("pfi_table_update: cannot set %d new addresses "
623		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
624}
625
626void
627pfi_instance_add(struct ifnet *ifp, int net, int flags)
628{
629	struct ifaddr	*ia;
630	int		 got4 = 0, got6 = 0;
631	int		 net2, af;
632
633	if (ifp == NULL)
634		return;
635	TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
636		if (ia->ifa_addr == NULL)
637			continue;
638		af = ia->ifa_addr->sa_family;
639		if (af != AF_INET && af != AF_INET6)
640			continue;
641#ifdef notyet
642		if (!(ia->ifa_flags & IFA_ROUTE))
643			continue;
644#endif
645		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
646			continue;
647		if ((flags & PFI_AFLAG_BROADCAST) &&
648		    !(ifp->if_flags & IFF_BROADCAST))
649			continue;
650		if ((flags & PFI_AFLAG_PEER) &&
651		    !(ifp->if_flags & IFF_POINTOPOINT))
652			continue;
653		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
654		    IN6_IS_ADDR_LINKLOCAL(
655		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
656			continue;
657		if (flags & PFI_AFLAG_NOALIAS) {
658			if (af == AF_INET && got4)
659				continue;
660			if (af == AF_INET6 && got6)
661				continue;
662		}
663		if (af == AF_INET)
664			got4 = 1;
665		else
666			got6 = 1;
667		net2 = net;
668		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
669			if (af == AF_INET) {
670				net2 = pfi_unmask(&((struct sockaddr_in *)
671				    ia->ifa_netmask)->sin_addr);
672			} else {
673				net2 = pfi_unmask(&((struct sockaddr_in6 *)
674				    ia->ifa_netmask)->sin6_addr);
675			}
676		}
677		if (af == AF_INET && net2 > 32)
678			net2 = 32;
679		if (flags & PFI_AFLAG_BROADCAST)
680			pfi_address_add(ia->ifa_broadaddr, af, net2);
681		else if (flags & PFI_AFLAG_PEER)
682			pfi_address_add(ia->ifa_dstaddr, af, net2);
683		else
684			pfi_address_add(ia->ifa_addr, af, net2);
685	}
686}
687
688void
689pfi_address_add(struct sockaddr *sa, int af, int net)
690{
691	struct pfr_addr	*p;
692	int		 i;
693
694	if (pfi_buffer_cnt >= pfi_buffer_max) {
695		int		 new_max = pfi_buffer_max * 2;
696
697		if (new_max > PFI_BUFFER_MAX) {
698			printf("pfi_address_add: address buffer full (%d/%d)\n",
699			    pfi_buffer_cnt, PFI_BUFFER_MAX);
700			return;
701		}
702#ifdef __FreeBSD__
703		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
704		    M_NOWAIT);
705#else
706		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
707		    M_DONTWAIT);
708#endif
709		if (p == NULL) {
710			printf("pfi_address_add: no memory to grow buffer "
711			    "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
712			return;
713		}
714		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
715		/* no need to zero buffer */
716		free(pfi_buffer, PFI_MTYPE);
717		pfi_buffer = p;
718		pfi_buffer_max = new_max;
719	}
720	if (af == AF_INET && net > 32)
721		net = 128;
722	p = pfi_buffer + pfi_buffer_cnt++;
723	bzero(p, sizeof(*p));
724	p->pfra_af = af;
725	p->pfra_net = net;
726	if (af == AF_INET)
727		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
728	if (af == AF_INET6) {
729		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
730		if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
731			p->pfra_ip6addr.s6_addr16[1] = 0;
732	}
733	/* mask network address bits */
734	if (net < 128)
735		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
736	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
737		((caddr_t)p)[i] = 0;
738}
739
740void
741pfi_dynaddr_remove(struct pf_addr_wrap *aw)
742{
743	int	s;
744
745	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
746	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
747		return;
748
749	s = splsoftnet();
750	hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
751	    aw->p.dyn->pfid_hook_cookie);
752	pfi_detach_rule(aw->p.dyn->pfid_kif);
753	aw->p.dyn->pfid_kif = NULL;
754	pfr_detach_table(aw->p.dyn->pfid_kt);
755	aw->p.dyn->pfid_kt = NULL;
756	pool_put(&pfi_addr_pl, aw->p.dyn);
757	aw->p.dyn = NULL;
758	splx(s);
759}
760
761void
762pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
763{
764	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
765	    aw->p.dyn->pfid_kif == NULL)
766		return;
767	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
768}
769
770void
771pfi_kifaddr_update(void *v)
772{
773	int		 s;
774
775	s = splsoftnet();
776	pfi_update++;
777	pfi_dohooks(v);
778	splx(s);
779}
780
781int
782pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
783{
784	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
785}
786
787struct pfi_kif *
788pfi_if_create(const char *name, struct pfi_kif *q, int flags)
789{
790	struct pfi_kif *p;
791
792#ifdef __FreeBSD__
793	p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT);
794#else
795	p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
796#endif
797	if (p == NULL)
798		return (NULL);
799	bzero(p, sizeof(*p));
800#ifdef __FreeBSD__
801	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
802	    M_NOWAIT);
803#else
804	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
805	    M_DONTWAIT);
806#endif
807	if (p->pfik_ah_head == NULL) {
808		free(p, PFI_MTYPE);
809		return (NULL);
810	}
811	bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
812	TAILQ_INIT(p->pfik_ah_head);
813	TAILQ_INIT(&p->pfik_grouphead);
814	strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
815	RB_INIT(&p->pfik_lan_ext);
816	RB_INIT(&p->pfik_ext_gwy);
817	p->pfik_flags = flags;
818	p->pfik_parent = q;
819#ifdef __FreeBSD__
820	p->pfik_tzero = time_second;
821#else
822	p->pfik_tzero = time.tv_sec;
823#endif
824
825	RB_INSERT(pfi_ifhead, &pfi_ifs, p);
826	if (q != NULL) {
827		q->pfik_addcnt++;
828		TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
829	}
830	pfi_ifcnt++;
831	return (p);
832}
833
834int
835pfi_maybe_destroy(struct pfi_kif *p)
836{
837	int		 i, j, k, s;
838	struct pfi_kif	*q = p->pfik_parent;
839
840	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
841	    p->pfik_rules > 0 || p->pfik_states > 0)
842#ifdef __FreeBSD__
843		if (!(p->pfik_flags & PFI_IFLAG_PLACEHOLDER))
844#endif
845		return (0);
846
847	s = splsoftnet();
848	if (q != NULL) {
849		for (i = 0; i < 2; i++)
850			for (j = 0; j < 2; j++)
851				for (k = 0; k < 2; k++) {
852					q->pfik_bytes[i][j][k] +=
853					    p->pfik_bytes[i][j][k];
854					q->pfik_packets[i][j][k] +=
855					    p->pfik_packets[i][j][k];
856#ifdef __FreeBSD__
857			/* clear stats in case we return to the dummy group */
858					p->pfik_bytes[i][j][k] = 0;
859					p->pfik_packets[i][j][k] = 0;
860#endif
861				}
862		q->pfik_delcnt++;
863		TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
864	}
865#ifdef __FreeBSD__
866	if (p->pfik_rules > 0 || p->pfik_states > 0) {
867		/* move back to the dummy group */
868		p->pfik_parent = pfi_dummy;
869		pfi_dummy->pfik_addcnt++;
870		TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p,
871		    pfik_instances);
872		return (0);
873	}
874#endif
875	pfi_ifcnt--;
876	RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
877	splx(s);
878
879	free(p->pfik_ah_head, PFI_MTYPE);
880	free(p, PFI_MTYPE);
881	return (1);
882}
883
884void
885pfi_copy_group(char *p, const char *q, int m)
886{
887	while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
888		*p++ = *q++;
889		m--;
890	}
891	if (m > 0)
892		*p++ = '\0';
893}
894
895void
896pfi_dynamic_drivers(void)
897{
898#ifdef __FreeBSD__
899	struct ifnet	*ifp;
900
901/*
902 * For FreeBSD basically every interface is "dynamic" as we can unload
903 * modules e.g.
904 */
905
906	IFNET_RLOCK();
907	TAILQ_FOREACH(ifp, &ifnet, if_link) {
908		if (ifp->if_dunit == IF_DUNIT_NONE)
909			continue;
910		pfi_newgroup(ifp->if_dname, PFI_IFLAG_DYNAMIC);
911	}
912	IFNET_RUNLOCK();
913#else
914	char		*buses[] = PFI_DYNAMIC_BUSES;
915	int		 nbuses = sizeof(buses)/sizeof(buses[0]);
916	int		 enabled[sizeof(buses)/sizeof(buses[0])];
917	struct device	*dev;
918	struct cfdata	*cf;
919	struct cfdriver	*drv;
920	short		*p;
921	int		 i;
922
923	bzero(enabled, sizeof(enabled));
924	TAILQ_FOREACH(dev, &alldevs, dv_list) {
925		if (!(dev->dv_flags & DVF_ACTIVE))
926			continue;
927		for (i = 0; i < nbuses; i++)
928			if (!enabled[i] && !strcmp(buses[i],
929			    dev->dv_cfdata->cf_driver->cd_name))
930				enabled[i] = 1;
931	}
932	for (cf = cfdata; cf->cf_driver; cf++) {
933		if (cf->cf_driver->cd_class != DV_IFNET)
934			continue;
935		for (p = cf->cf_parents; p && *p >= 0; p++) {
936			if ((drv = cfdata[*p].cf_driver) == NULL)
937				continue;
938			for (i = 0; i < nbuses; i++)
939				if (enabled[i] &&
940				    !strcmp(drv->cd_name, buses[i]))
941					break;
942			if (i < nbuses) {
943				pfi_newgroup(cf->cf_driver->cd_name,
944				    PFI_IFLAG_DYNAMIC);
945				break;
946			}
947		}
948	}
949#endif
950}
951
952void
953pfi_newgroup(const char *name, int flags)
954{
955	struct pfi_kif	*p;
956
957	p = pfi_lookup_if(name);
958	if (p == NULL)
959		p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
960	if (p == NULL) {
961		printf("pfi_newgroup: cannot allocate '%s' group", name);
962		return;
963	}
964	p->pfik_flags |= flags;
965}
966
967void
968pfi_fill_oldstatus(struct pf_status *pfs)
969{
970	struct pfi_kif	*p, key;
971	int		 i, j, k, s;
972
973	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
974	s = splsoftnet();
975	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
976	if (p == NULL) {
977		splx(s);
978		return;
979	}
980	bzero(pfs->pcounters, sizeof(pfs->pcounters));
981	bzero(pfs->bcounters, sizeof(pfs->bcounters));
982	for (i = 0; i < 2; i++)
983		for (j = 0; j < 2; j++)
984			for (k = 0; k < 2; k++) {
985				pfs->pcounters[i][j][k] =
986					p->pfik_packets[i][j][k];
987				pfs->bcounters[i][j] +=
988					p->pfik_bytes[i][j][k];
989			}
990	splx(s);
991}
992
993int
994pfi_clr_istats(const char *name, int *nzero, int flags)
995{
996	struct pfi_kif	*p;
997	int		 n = 0, s;
998#ifdef __FreeBSD__
999	long		 tzero = time_second;
1000#else
1001	long		 tzero = time.tv_sec;
1002#endif
1003
1004	s = splsoftnet();
1005	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1006	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1007		if (pfi_skip_if(name, p, flags))
1008			continue;
1009		bzero(p->pfik_packets, sizeof(p->pfik_packets));
1010		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
1011		p->pfik_tzero = tzero;
1012		n++;
1013	}
1014	splx(s);
1015	if (nzero != NULL)
1016		*nzero = n;
1017	return (0);
1018}
1019
1020int
1021pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
1022{
1023	struct pfi_kif	*p;
1024	int		 s, n = 0;
1025#ifdef __FreeBSD__
1026	int		 ec;
1027#endif
1028
1029	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
1030	s = splsoftnet();
1031	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
1032		if (pfi_skip_if(name, p, flags))
1033			continue;
1034		if (*size > n++) {
1035			if (!p->pfik_tzero)
1036				p->pfik_tzero = boottime.tv_sec;
1037#ifdef __FreeBSD__
1038			PF_COPYOUT(p, buf++, sizeof(*buf), ec);
1039			if (ec) {
1040#else
1041			if (copyout(p, buf++, sizeof(*buf))) {
1042#endif
1043				splx(s);
1044				return (EFAULT);
1045			}
1046		}
1047	}
1048	splx(s);
1049	*size = n;
1050	return (0);
1051}
1052
1053struct pfi_kif *
1054pfi_lookup_if(const char *name)
1055{
1056	struct pfi_kif	*p, key;
1057
1058	strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
1059	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
1060	return (p);
1061}
1062
1063int
1064pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
1065{
1066	int	n;
1067
1068	if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
1069		return (1);
1070	if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
1071		return (1);
1072	if (filter == NULL || !*filter)
1073		return (0);
1074	if (!strcmp(p->pfik_name, filter))
1075		return (0);	/* exact match */
1076	n = strlen(filter);
1077	if (n < 1 || n >= IFNAMSIZ)
1078		return (1);	/* sanity check */
1079	if (filter[n-1] >= '0' && filter[n-1] <= '9')
1080		return (1);	/* only do exact match in that case */
1081	if (strncmp(p->pfik_name, filter, n))
1082		return (1);	/* prefix doesn't match */
1083	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
1084}
1085
1086/* from pf_print_state.c */
1087int
1088pfi_unmask(void *addr)
1089{
1090	struct pf_addr *m = addr;
1091	int i = 31, j = 0, b = 0;
1092	u_int32_t tmp;
1093
1094	while (j < 4 && m->addr32[j] == 0xffffffff) {
1095		b += 32;
1096		j++;
1097	}
1098	if (j < 4) {
1099		tmp = ntohl(m->addr32[j]);
1100		for (i = 31; tmp & (1 << i); --i)
1101			b++;
1102	}
1103	return (b);
1104}
1105
1106void
1107pfi_dohooks(struct pfi_kif *p)
1108{
1109	for (; p != NULL; p = p->pfik_parent)
1110		dohooks(p->pfik_ah_head, 0);
1111}
1112
1113int
1114pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
1115{
1116	if (af == AF_INET) {
1117		switch (dyn->pfid_acnt4) {
1118		case 0:
1119			return (0);
1120		case 1:
1121			return (PF_MATCHA(0, &dyn->pfid_addr4,
1122			    &dyn->pfid_mask4, a, AF_INET));
1123		default:
1124			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
1125		}
1126	} else {
1127		switch (dyn->pfid_acnt6) {
1128		case 0:
1129			return (0);
1130		case 1:
1131			return (PF_MATCHA(0, &dyn->pfid_addr6,
1132			    &dyn->pfid_mask6, a, AF_INET6));
1133		default:
1134			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
1135		}
1136	}
1137}
1138