xref: /dragonfly/sys/net/pf/pf_if.c (revision cfd1aba3)
1 /*	$OpenBSD: pf_if.c,v 1.54 2008/06/14 16:55:28 mk Exp $ */
2 
3 /*
4  * Copyright 2005 Henning Brauer <henning@openbsd.org>
5  * Copyright 2005 Ryan McBride <mcbride@openbsd.org>
6  * Copyright (c) 2001 Daniel Hartmeier
7  * Copyright (c) 2003 Cedric Berger
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  *    - Redistributions of source code must retain the above copyright
15  *      notice, this list of conditions and the following disclaimer.
16  *    - Redistributions in binary form must reproduce the above
17  *      copyright notice, this list of conditions and the following
18  *      disclaimer in the documentation and/or other materials provided
19  *      with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "opt_inet.h"
36 #include "opt_inet6.h"
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/eventhandler.h>
43 #include <sys/filio.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/kernel.h>
47 #include <sys/thread2.h>
48 #include <sys/time.h>
49 
50 #include <net/if.h>
51 #include <net/if_types.h>
52 #include <net/route.h>
53 
54 #include <netinet/in.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 
60 #include <net/pf/pfvar.h>
61 
62 #ifdef INET6
63 #include <netinet/ip6.h>
64 #endif /* INET6 */
65 
66 struct pfi_kif		 *pfi_all = NULL;
67 struct pfi_ifhead	  pfi_ifs;
68 long			  pfi_update = 1;
69 struct pfr_addr		 *pfi_buffer;
70 int			  pfi_buffer_cnt;
71 int			  pfi_buffer_max;
72 
73 eventhandler_tag	 pfi_clone_cookie = NULL;
74 eventhandler_tag	 pfi_attach_cookie = NULL;
75 eventhandler_tag	 pfi_detach_cookie = NULL;
76 
77 void		 pfi_kif_update(struct pfi_kif *);
78 void		 pfi_dynaddr_update(struct pfi_dynaddr *dyn);
79 void		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
80 		    int, int);
81 void		 pfi_kifaddr_update(void *);
82 void		 pfi_instance_add(struct ifnet *, int, int);
83 void		 pfi_address_add(struct sockaddr *, int, int);
84 int		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
85 int		 pfi_skip_if(const char *, struct pfi_kif *);
86 int		 pfi_unmask(void *);
87 void		 pfi_kifaddr_update_event(void *, struct ifnet *,
88 		     enum ifaddr_event, struct ifaddr *);
89 /*XXX jl void		 pfi_attach_clone_event(void *, struct if_clone *);*/
90 void		 pfi_attach_ifnet_event(void *, struct ifnet *);
91 void		 pfi_detach_ifnet_event(void *, struct ifnet *);
92 
93 RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
94 RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
95 
96 #define PFI_BUFFER_MAX		0x10000
97 MALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table");
98 static MALLOC_DEFINE(M_PFIADDRPL, "pfiaddrpl", "pf interface address pool list");
99 
100 
101 void
102 pfi_initialize(void)
103 {
104 	struct ifnet	*ifp;
105 
106 	if (pfi_all != NULL)	/* already initialized */
107 		return;
108 
109 	pfi_buffer_max = 64;
110 	pfi_buffer = kmalloc(pfi_buffer_max * sizeof(*pfi_buffer),
111 	    PFI_MTYPE, M_WAITOK);
112 
113 	if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
114 		panic("pfi_kif_get for pfi_all failed");
115 
116 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
117 		if (ifp->if_dunit != IF_DUNIT_NONE)
118 			pfi_attach_ifnet(ifp);
119 	}
120 	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_attach_event,
121 	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
122 	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_detach_event,
123 	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
124 /* XXX jl	pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event,
125 	    pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY); */
126 
127 	if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
128 		panic("pfi_kif_get for pfi_all failed");
129 }
130 
131 void
132 pfi_cleanup(void)
133 {
134 	struct pfi_kif *p, key;
135 	struct ifnet *ifp;
136 
137 	EVENTHANDLER_DEREGISTER(ifnet_attach_event, pfi_attach_cookie);
138 	EVENTHANDLER_DEREGISTER(ifnet_detach_event, pfi_detach_cookie);
139 	EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
140 
141 	/* release PFI_IFLAG_INSTANCE */
142 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
143 		strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
144 		p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
145 		if (p != NULL)
146 			pfi_detach_ifnet(ifp);
147 	}
148 
149 	/* XXX clear all other interface group */
150 	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
151 		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
152 
153 		kfree(p, PFI_MTYPE);
154 	}
155 	kfree(pfi_buffer, PFI_MTYPE);
156 	pfi_buffer = NULL;
157 	pfi_all = NULL;
158 }
159 
160 /*
161  * Wrapper functions for FreeBSD eventhandler
162  */
163 void
164 pfi_kifaddr_update_event(void *arg, struct ifnet *ifp,
165     enum ifaddr_event event __unused, struct ifaddr *ifa __unused)
166 {
167 	struct pfi_kif *p = arg;
168 
169 	/*
170 	 * Check to see if it is 'our' interface as we do not have per
171 	 * interface hooks and thus get an update for every interface.
172 	 */
173 	if (p && p->pfik_ifp == ifp)
174 		pfi_kifaddr_update(p);
175 }
176 
177 /* XXX jl
178 void
179 pfi_attach_clone_event(void *arg __unused, struct if_clone *ifc)
180 {
181 	pfi_attach_clone(ifc);
182 }
183 */
184 
185 void
186 pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
187 {
188 	if (ifp->if_dunit != IF_DUNIT_NONE)
189 		pfi_attach_ifnet(ifp);
190 }
191 
192 void
193 pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
194 {
195 	pfi_detach_ifnet(ifp);
196 }
197 
198 struct pfi_kif *
199 pfi_kif_get(const char *kif_name)
200 {
201 	struct pfi_kif		*kif;
202 	struct pfi_kif_cmp	 s;
203 
204 	bzero(&s, sizeof(s));
205 	strlcpy(s.pfik_ifname, kif_name, sizeof(s.pfik_ifname));
206 	if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
207 		return (kif);
208 
209 	/* create new one */
210 	if ((kif = kmalloc(sizeof(*kif), PFI_MTYPE, M_WAITOK)) == NULL)
211 		return (NULL);
212 
213 	strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
214 	kif->pfik_tzero = time_second;
215 	TAILQ_INIT(&kif->pfik_dynaddrs);
216 
217 	RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
218 	return (kif);
219 }
220 
221 void
222 pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
223 {
224 	switch (what) {
225 	case PFI_KIF_REF_RULE:
226 		kif->pfik_rules++;
227 		break;
228 	case PFI_KIF_REF_STATE:
229 		kif->pfik_states++;
230 		break;
231 	default:
232 		panic("pfi_kif_ref with unknown type");
233 	}
234 }
235 
236 void
237 pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
238 {
239 	if (kif == NULL)
240 		return;
241 
242 	switch (what) {
243 	case PFI_KIF_REF_NONE:
244 		break;
245 	case PFI_KIF_REF_RULE:
246 		if (kif->pfik_rules <= 0) {
247 			kprintf("pfi_kif_unref: rules refcount <= 0\n");
248 			return;
249 		}
250 		kif->pfik_rules--;
251 		break;
252 	case PFI_KIF_REF_STATE:
253 		if (kif->pfik_states <= 0) {
254 			kprintf("pfi_kif_unref: state refcount <= 0\n");
255 			return;
256 		}
257 		kif->pfik_states--;
258 		break;
259 	default:
260 		panic("pfi_kif_unref with unknown type");
261 	}
262 
263 	if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
264 		return;
265 
266 	if (kif->pfik_rules || kif->pfik_states)
267 		return;
268 
269 	RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
270 	kfree(kif, PFI_MTYPE);
271 }
272 
273 int
274 pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
275 {
276 	struct ifg_list	*p;
277 
278 	if (rule_kif == NULL || rule_kif == packet_kif)
279 		return (1);
280 
281 	if (rule_kif->pfik_group != NULL)
282 		TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
283 			if (p->ifgl_group == rule_kif->pfik_group)
284 				return (1);
285 
286 	return (0);
287 }
288 
289 void
290 pfi_attach_ifnet(struct ifnet *ifp)
291 {
292 	struct pfi_kif		*kif;
293 
294 	pfi_initialize();
295 	crit_enter();
296 	pfi_update++;
297 	if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
298 		panic("pfi_kif_get failed");
299 
300 	kif->pfik_ifp = ifp;
301 	ifp->if_pf_kif = (caddr_t)kif;
302 
303 	pfi_kif_update(kif);
304 
305 	crit_exit();
306 }
307 
308 void
309 pfi_detach_ifnet(struct ifnet *ifp)
310 {
311 	struct pfi_kif		*kif;
312 
313 	if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
314 		return;
315 
316 	crit_enter();
317 	pfi_update++;
318 	pfi_kif_update(kif);
319 
320 	kif->pfik_ifp = NULL;
321 	ifp->if_pf_kif = NULL;
322 	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
323 	crit_exit();
324 }
325 
326 void
327 pfi_attach_ifgroup(struct ifg_group *ifg)
328 {
329 	struct pfi_kif	*kif;
330 
331 	pfi_initialize();
332 	crit_enter();
333 	pfi_update++;
334 	if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
335 		panic("pfi_kif_get failed");
336 
337 	kif->pfik_group = ifg;
338 	ifg->ifg_pf_kif = (caddr_t)kif;
339 
340 	crit_exit();
341 }
342 
343 void
344 pfi_detach_ifgroup(struct ifg_group *ifg)
345 {
346 	struct pfi_kif	*kif;
347 
348 	if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
349 		return;
350 
351 	crit_enter();
352 	pfi_update++;
353 
354 	kif->pfik_group = NULL;
355 	ifg->ifg_pf_kif = NULL;
356 	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
357 	crit_exit();
358 }
359 
360 void
361 pfi_group_change(const char *group)
362 {
363 	struct pfi_kif		*kif;
364 
365 	crit_enter();
366 	pfi_update++;
367 	if ((kif = pfi_kif_get(group)) == NULL)
368 		panic("pfi_kif_get failed");
369 
370 	pfi_kif_update(kif);
371 
372 	crit_exit();
373 }
374 
375 int
376 pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
377 {
378 	switch (af) {
379 #ifdef INET
380 	case AF_INET:
381 		switch (dyn->pfid_acnt4) {
382 		case 0:
383 			return (0);
384 		case 1:
385 			return (PF_MATCHA(0, &dyn->pfid_addr4,
386 			    &dyn->pfid_mask4, a, AF_INET));
387 		default:
388 			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
389 		}
390 		break;
391 #endif /* INET */
392 #ifdef INET6
393 	case AF_INET6:
394 		switch (dyn->pfid_acnt6) {
395 		case 0:
396 			return (0);
397 		case 1:
398 			return (PF_MATCHA(0, &dyn->pfid_addr6,
399 			    &dyn->pfid_mask6, a, AF_INET6));
400 		default:
401 			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
402 		}
403 		break;
404 #endif /* INET6 */
405 	default:
406 		return (0);
407 	}
408 }
409 
410 int
411 pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
412 {
413 	struct pfi_dynaddr	*dyn;
414 	char			 tblname[PF_TABLE_NAME_SIZE];
415 	struct pf_ruleset	*ruleset = NULL;
416 	int			 rv = 0;
417 
418 	if (aw->type != PF_ADDR_DYNIFTL)
419 		return (0);
420 	if ((dyn = kmalloc(sizeof(struct pfi_dynaddr), M_PFIADDRPL, M_WAITOK|M_NULLOK|M_ZERO))
421 	    == NULL)
422 		return (1);
423 
424 	crit_enter();
425 	if (!strcmp(aw->v.ifname, "self"))
426 		dyn->pfid_kif = pfi_kif_get(IFG_ALL);
427 	else
428 		dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
429 	if (dyn->pfid_kif == NULL) {
430 		rv = 1;
431 		goto _bad;
432 	}
433 	pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
434 
435 	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
436 	if (af == AF_INET && dyn->pfid_net == 32)
437 		dyn->pfid_net = 128;
438 	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
439 	if (aw->iflags & PFI_AFLAG_NETWORK)
440 		strlcat(tblname, ":network", sizeof(tblname));
441 	if (aw->iflags & PFI_AFLAG_BROADCAST)
442 		strlcat(tblname, ":broadcast", sizeof(tblname));
443 	if (aw->iflags & PFI_AFLAG_PEER)
444 		strlcat(tblname, ":peer", sizeof(tblname));
445 	if (aw->iflags & PFI_AFLAG_NOALIAS)
446 		strlcat(tblname, ":0", sizeof(tblname));
447 	if (dyn->pfid_net != 128)
448 		ksnprintf(tblname + strlen(tblname),
449 		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
450 	if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
451 		rv = 1;
452 		goto _bad;
453 	}
454 
455 	if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
456 		rv = 1;
457 		goto _bad;
458 	}
459 
460 	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
461 	dyn->pfid_iflags = aw->iflags;
462 	dyn->pfid_af = af;
463 
464 	TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
465 	aw->p.dyn = dyn;
466 	pfi_kif_update(dyn->pfid_kif);
467 	crit_exit();
468 	return (0);
469 
470 _bad:
471 	if (dyn->pfid_kt != NULL)
472 		pfr_detach_table(dyn->pfid_kt);
473 	if (ruleset != NULL)
474 		pf_remove_if_empty_ruleset(ruleset);
475 	if (dyn->pfid_kif != NULL)
476 		pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
477 	kfree(dyn, M_PFIADDRPL);
478 	crit_exit();
479 	return (rv);
480 }
481 
482 void
483 pfi_kif_update(struct pfi_kif *kif)
484 {
485 	struct ifg_list		*ifgl;
486 	struct pfi_dynaddr	*p;
487 
488 	/* update all dynaddr */
489 	TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
490 		pfi_dynaddr_update(p);
491 
492 	/* again for all groups kif is member of */
493 	if (kif->pfik_ifp != NULL)
494 		TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
495 			pfi_kif_update((struct pfi_kif *)
496 			    ifgl->ifgl_group->ifg_pf_kif);
497 }
498 
499 void
500 pfi_dynaddr_update(struct pfi_dynaddr *dyn)
501 {
502 	struct pfi_kif		*kif;
503 	struct pfr_ktable	*kt;
504 
505 	if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
506 		panic("pfi_dynaddr_update");
507 
508 	kif = dyn->pfid_kif;
509 	kt = dyn->pfid_kt;
510 
511 	if (kt->pfrkt_larg != pfi_update) {
512 		/* this table needs to be brought up-to-date */
513 		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
514 		kt->pfrkt_larg = pfi_update;
515 	}
516 	pfr_dynaddr_update(kt, dyn);
517 }
518 
519 void
520 pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
521 {
522 	int			 e, size2 = 0;
523 	struct ifg_member	*ifgm;
524 
525 	pfi_buffer_cnt = 0;
526 
527 	if (kif->pfik_ifp != NULL)
528 		pfi_instance_add(kif->pfik_ifp, net, flags);
529 	else if (kif->pfik_group != NULL)
530 		TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
531 			pfi_instance_add(ifgm->ifgm_ifp, net, flags);
532 
533 	if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
534 	    NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
535 		kprintf("pfi_table_update: cannot set %d new addresses "
536 		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
537 }
538 
539 void
540 pfi_instance_add(struct ifnet *ifp, int net, int flags)
541 {
542 	struct ifaddr_container *ifac;
543 	int		 got4 = 0, got6 = 0;
544 	int		 net2, af;
545 
546 	if (ifp == NULL)
547 		return;
548 	TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
549 		struct ifaddr *ia = ifac->ifa;
550 
551 		if (ia->ifa_addr == NULL)
552 			continue;
553 		af = ia->ifa_addr->sa_family;
554 		if (af != AF_INET && af != AF_INET6)
555 			continue;
556 		/*
557 		 * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
558 		 *	jump over address without a proper route to work
559 		 *	around a problem with ppp not fully removing the
560 		 *	address used during IPCP.
561 		 */
562 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
563 		    !(ia->ifa_flags & IFA_ROUTE) &&
564 		    (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
565 			continue;
566 		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
567 			continue;
568 		if ((flags & PFI_AFLAG_BROADCAST) &&
569 		    !(ifp->if_flags & IFF_BROADCAST))
570 			continue;
571 		if ((flags & PFI_AFLAG_PEER) &&
572 		    !(ifp->if_flags & IFF_POINTOPOINT))
573 			continue;
574 		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
575 		    IN6_IS_ADDR_LINKLOCAL(
576 		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
577 			continue;
578 		if (flags & PFI_AFLAG_NOALIAS) {
579 			if (af == AF_INET && got4)
580 				continue;
581 			if (af == AF_INET6 && got6)
582 				continue;
583 		}
584 		if (af == AF_INET)
585 			got4 = 1;
586 		else if (af == AF_INET6)
587 			got6 = 1;
588 		net2 = net;
589 		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
590 			if (af == AF_INET)
591 				net2 = pfi_unmask(&((struct sockaddr_in *)
592 				    ia->ifa_netmask)->sin_addr);
593 			else if (af == AF_INET6)
594 				net2 = pfi_unmask(&((struct sockaddr_in6 *)
595 				    ia->ifa_netmask)->sin6_addr);
596 		}
597 		if (af == AF_INET && net2 > 32)
598 			net2 = 32;
599 		if (flags & PFI_AFLAG_BROADCAST)
600 			pfi_address_add(ia->ifa_broadaddr, af, net2);
601 		else if (flags & PFI_AFLAG_PEER)
602 			pfi_address_add(ia->ifa_dstaddr, af, net2);
603 		else
604 			pfi_address_add(ia->ifa_addr, af, net2);
605 	}
606 }
607 
608 void
609 pfi_address_add(struct sockaddr *sa, int af, int net)
610 {
611 	struct pfr_addr	*p;
612 	int		 i;
613 
614 	if (pfi_buffer_cnt >= pfi_buffer_max) {
615 		int		 new_max = pfi_buffer_max * 2;
616 
617 		if (new_max > PFI_BUFFER_MAX) {
618 			kprintf("pfi_address_add: address buffer full (%d/%d)\n",
619 			    pfi_buffer_cnt, PFI_BUFFER_MAX);
620 			return;
621 		}
622 		p = kmalloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, M_WAITOK);
623 		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
624 		/* no need to zero buffer */
625 		kfree(pfi_buffer, PFI_MTYPE);
626 		pfi_buffer = p;
627 		pfi_buffer_max = new_max;
628 	}
629 	if (af == AF_INET && net > 32)
630 		net = 128;
631 	p = pfi_buffer + pfi_buffer_cnt++;
632 	bzero(p, sizeof(*p));
633 	p->pfra_af = af;
634 	p->pfra_net = net;
635 	if (af == AF_INET)
636 		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
637 	else if (af == AF_INET6) {
638 		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
639 		if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
640 			p->pfra_ip6addr.s6_addr16[1] = 0;
641 	}
642 	/* mask network address bits */
643 	if (net < 128)
644 		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
645 	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
646 		((caddr_t)p)[i] = 0;
647 }
648 
649 void
650 pfi_dynaddr_remove(struct pf_addr_wrap *aw)
651 {
652 	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
653 	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
654 		return;
655 
656 	crit_enter();
657 	TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
658 	pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
659 	aw->p.dyn->pfid_kif = NULL;
660 	pfr_detach_table(aw->p.dyn->pfid_kt);
661 	aw->p.dyn->pfid_kt = NULL;
662 	kfree(aw->p.dyn, M_PFIADDRPL);
663 	aw->p.dyn = NULL;
664 	crit_exit();
665 }
666 
667 void
668 pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
669 {
670 	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
671 	    aw->p.dyn->pfid_kif == NULL)
672 		return;
673 	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
674 }
675 
676 void
677 pfi_kifaddr_update(void *v)
678 {
679 	struct pfi_kif		*kif = (struct pfi_kif *)v;
680 
681 	crit_enter();
682 	pfi_update++;
683 	pfi_kif_update(kif);
684 	crit_exit();
685 }
686 
687 int
688 pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
689 {
690 	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
691 }
692 
693 void
694 pfi_update_status(const char *name, struct pf_status *pfs)
695 {
696 	struct pfi_kif		*p;
697 	struct pfi_kif_cmp 	 key;
698 	struct ifg_member	 p_member, *ifgm;
699 	TAILQ_HEAD(, ifg_member) ifg_members;
700 	int			 i, j, k;
701 
702 	strlcpy(key.pfik_ifname, name, sizeof(key.pfik_ifname));
703 	crit_enter();
704 	p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
705 	if (p == NULL) {
706 		crit_exit();
707 		return;
708 	}
709 	if (p->pfik_group != NULL) {
710 		bcopy(&p->pfik_group->ifg_members, &ifg_members,
711 		    sizeof(ifg_members));
712 	} else {
713 		/* build a temporary list for p only */
714 		bzero(&p_member, sizeof(p_member));
715 		p_member.ifgm_ifp = p->pfik_ifp;
716 		TAILQ_INIT(&ifg_members);
717 		TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next);
718 	}
719 	if (pfs) {
720 		bzero(pfs->pcounters, sizeof(pfs->pcounters));
721 		bzero(pfs->bcounters, sizeof(pfs->bcounters));
722 	}
723 	TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) {
724 		if (ifgm->ifgm_ifp == NULL)
725 			continue;
726 		p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif;
727 
728 		/* just clear statistics */
729 		if (pfs == NULL) {
730 			bzero(p->pfik_packets, sizeof(p->pfik_packets));
731 			bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
732 			p->pfik_tzero = time_second;
733 			continue;
734 		}
735 		for (i = 0; i < 2; i++)
736 			for (j = 0; j < 2; j++)
737 				for (k = 0; k < 2; k++) {
738 					pfs->pcounters[i][j][k] +=
739 						p->pfik_packets[i][j][k];
740 					pfs->bcounters[i][j] +=
741 						p->pfik_bytes[i][j][k];
742 				}
743 	}
744 	crit_exit();
745 }
746 
747 int
748 pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
749 {
750 	struct pfi_kif	*p, *nextp;
751 	int		 n = 0;
752 
753 	crit_enter();
754 	for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
755 		nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
756 		if (pfi_skip_if(name, p))
757 			continue;
758 		if (*size > n++) {
759 			if (!p->pfik_tzero)
760 				p->pfik_tzero = time_second;
761 			pfi_kif_ref(p, PFI_KIF_REF_RULE);
762 			if (copyout(p, buf++, sizeof(*buf))) {
763 				pfi_kif_unref(p, PFI_KIF_REF_RULE);
764 				crit_exit();
765 				return (EFAULT);
766 			}
767 			nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
768 			pfi_kif_unref(p, PFI_KIF_REF_RULE);
769 		}
770 	}
771 	crit_exit();
772 	*size = n;
773 	return (0);
774 }
775 
776 int
777 pfi_skip_if(const char *filter, struct pfi_kif *p)
778 {
779 	int	n;
780 
781 	if (filter == NULL || !*filter)
782 		return (0);
783 	if (!strcmp(p->pfik_name, filter))
784 		return (0);	/* exact match */
785 	n = strlen(filter);
786 	if (n < 1 || n >= IFNAMSIZ)
787 		return (1);	/* sanity check */
788 	if (filter[n-1] >= '0' && filter[n-1] <= '9')
789 		return (1);	/* only do exact match in that case */
790 	if (strncmp(p->pfik_name, filter, n))
791 		return (1);	/* prefix doesn't match */
792 	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
793 }
794 
795 int
796 pfi_set_flags(const char *name, int flags)
797 {
798 	struct pfi_kif	*p;
799 
800 	crit_enter();
801 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
802 		if (pfi_skip_if(name, p))
803 			continue;
804 		p->pfik_flags |= flags;
805 	}
806 	crit_exit();
807 	return (0);
808 }
809 
810 int
811 pfi_clear_flags(const char *name, int flags)
812 {
813 	struct pfi_kif	*p;
814 
815 	crit_enter();
816 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
817 		if (pfi_skip_if(name, p))
818 			continue;
819 		p->pfik_flags &= ~flags;
820 	}
821 	crit_exit();
822 	return (0);
823 }
824 
825 /* from pf_print_state.c */
826 int
827 pfi_unmask(void *addr)
828 {
829 	struct pf_addr *m = addr;
830 	int i = 31, j = 0, b = 0;
831 	u_int32_t tmp;
832 
833 	while (j < 4 && m->addr32[j] == 0xffffffff) {
834 		b += 32;
835 		j++;
836 	}
837 	if (j < 4) {
838 		tmp = ntohl(m->addr32[j]);
839 		for (i = 31; tmp & (1 << i); --i)
840 			b++;
841 	}
842 	return (b);
843 }
844 
845