pf_if.c revision 183550
1/*	$OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun 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#if defined(__FreeBSD__)
36#include "opt_inet.h"
37#include "opt_inet6.h"
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf_if.c 183550 2008-10-02 15:37:58Z zec $");
41#endif
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#ifdef __FreeBSD__
46#include <sys/malloc.h>
47#endif
48#include <sys/mbuf.h>
49#include <sys/filio.h>
50#include <sys/socket.h>
51#include <sys/socketvar.h>
52#include <sys/kernel.h>
53#ifndef __FreeBSD__
54#include <sys/device.h>
55#endif
56#include <sys/time.h>
57#include <sys/vimage.h>
58
59#include <net/if.h>
60#include <net/if_types.h>
61
62#include <netinet/in.h>
63#include <netinet/in_var.h>
64#include <netinet/in_systm.h>
65#include <netinet/ip.h>
66#include <netinet/ip_var.h>
67
68#include <net/pfvar.h>
69
70#ifdef INET6
71#include <netinet/ip6.h>
72#endif /* INET6 */
73
74struct pfi_kif		 *pfi_all = NULL;
75struct pfi_statehead	  pfi_statehead;
76#ifdef __FreeBSD__
77uma_zone_t		  pfi_addr_pl;
78#else
79struct pool		  pfi_addr_pl;
80#endif
81struct pfi_ifhead	  pfi_ifs;
82long			  pfi_update = 1;
83struct pfr_addr		 *pfi_buffer;
84int			  pfi_buffer_cnt;
85int			  pfi_buffer_max;
86#ifdef __FreeBSD__
87eventhandler_tag	  pfi_attach_cookie = NULL;
88eventhandler_tag	  pfi_detach_cookie = NULL;
89eventhandler_tag	  pfi_attach_group_cookie = NULL;
90eventhandler_tag	  pfi_change_group_cookie = NULL;
91eventhandler_tag	  pfi_detach_group_cookie = NULL;
92eventhandler_tag	  pfi_ifaddr_event_cookie = NULL;
93#endif
94
95void		 pfi_kif_update(struct pfi_kif *);
96void		 pfi_dynaddr_update(struct pfi_dynaddr *dyn);
97void		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
98		    int, int);
99void		 pfi_kifaddr_update(void *);
100void		 pfi_instance_add(struct ifnet *, int, int);
101void		 pfi_address_add(struct sockaddr *, int, int);
102int		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
103int		 pfi_skip_if(const char *, struct pfi_kif *);
104int		 pfi_unmask(void *);
105#ifdef __FreeBSD__
106void		 pfi_attach_ifnet_event(void * __unused, struct ifnet *);
107void		 pfi_detach_ifnet_event(void * __unused, struct ifnet *);
108void		 pfi_attach_group_event(void * __unused, struct ifg_group *);
109void		 pfi_change_group_event(void * __unused, char *);
110void		 pfi_detach_group_event(void * __unused, struct ifg_group *);
111void		 pfi_ifaddr_event(void * __unused, struct ifnet *);
112
113extern struct ifgrouphead ifg_head;
114#endif
115
116RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
117RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
118
119#define PFI_BUFFER_MAX		0x10000
120#define PFI_MTYPE		M_IFADDR
121
122void
123pfi_initialize(void)
124{
125	INIT_VNET_NET(curvnet);
126
127	if (pfi_all != NULL)	/* already initialized */
128		return;
129
130	TAILQ_INIT(&pfi_statehead);
131#ifndef __FreeBSD__
132	pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
133	    "pfiaddrpl", &pool_allocator_nointr);
134#endif
135	pfi_buffer_max = 64;
136	pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
137	    PFI_MTYPE, M_WAITOK);
138
139	if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
140		panic("pfi_kif_get for pfi_all failed");
141
142#ifdef __FreeBSD__
143	struct ifg_group *ifg;
144	struct ifnet *ifp;
145
146	IFNET_RLOCK();
147	TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
148		pfi_attach_ifgroup(ifg);
149	TAILQ_FOREACH(ifp, &V_ifnet, if_link)
150		pfi_attach_ifnet(ifp);
151	IFNET_RUNLOCK();
152
153	pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event,
154	    pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
155	pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
156	    pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
157	pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event,
158	    pfi_attach_group_event, NULL, EVENTHANDLER_PRI_ANY);
159	pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event,
160	    pfi_change_group_event, NULL, EVENTHANDLER_PRI_ANY);
161	pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event,
162	    pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY);
163	pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
164	    pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY);
165#endif
166}
167
168#ifdef __FreeBSD__
169void
170pfi_cleanup(void)
171{
172	struct pfi_kif *p;
173
174	PF_UNLOCK();
175	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie);
176	EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie);
177	EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie);
178	EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie);
179	EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie);
180	EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie);
181	PF_LOCK();
182
183	pfi_all = NULL;
184	while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
185		if (p->pfik_rules || p->pfik_states) {
186			printf("pfi_cleanup: dangling refs for %s\n",
187			    p->pfik_name);
188		}
189
190		RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
191		free(p, PFI_MTYPE);
192	}
193
194	free(pfi_buffer, PFI_MTYPE);
195}
196#endif
197
198struct pfi_kif *
199pfi_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_name, kif_name, sizeof(s.pfik_name));
206	if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL)
207		return (kif);
208
209	/* create new one */
210#ifdef __FreeBSD__
211	if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL)
212#else
213	if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL)
214#endif
215		return (NULL);
216
217	bzero(kif, sizeof(*kif));
218	strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
219#ifdef __FreeBSD__
220	/*
221	 * It seems that the value of time_second is in unintialzied state
222	 * when pf sets interface statistics clear time in boot phase if pf
223	 * was statically linked to kernel. Instead of setting the bogus
224	 * time value have pfi_get_ifaces handle this case. In
225	 * pfi_get_ifaces it uses boottime.tv_sec if it sees the time is 0.
226	 */
227	kif->pfik_tzero = time_second > 1 ? time_second : 0;
228#else
229	kif->pfik_tzero = time_second;
230#endif
231	TAILQ_INIT(&kif->pfik_dynaddrs);
232
233	RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
234	return (kif);
235}
236
237void
238pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
239{
240	switch (what) {
241	case PFI_KIF_REF_RULE:
242		kif->pfik_rules++;
243		break;
244	case PFI_KIF_REF_STATE:
245		if (!kif->pfik_states++)
246			TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states);
247		break;
248	default:
249		panic("pfi_kif_ref with unknown type");
250	}
251}
252
253void
254pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
255{
256	if (kif == NULL)
257		return;
258
259	switch (what) {
260	case PFI_KIF_REF_NONE:
261		break;
262	case PFI_KIF_REF_RULE:
263		if (kif->pfik_rules <= 0) {
264			printf("pfi_kif_unref: rules refcount <= 0\n");
265			return;
266		}
267		kif->pfik_rules--;
268		break;
269	case PFI_KIF_REF_STATE:
270		if (kif->pfik_states <= 0) {
271			printf("pfi_kif_unref: state refcount <= 0\n");
272			return;
273		}
274		if (!--kif->pfik_states)
275			TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states);
276		break;
277	default:
278		panic("pfi_kif_unref with unknown type");
279	}
280
281	if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
282		return;
283
284	if (kif->pfik_rules || kif->pfik_states)
285		return;
286
287	RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
288	free(kif, PFI_MTYPE);
289}
290
291int
292pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
293{
294	struct ifg_list	*p;
295
296	if (rule_kif == NULL || rule_kif == packet_kif)
297		return (1);
298
299	if (rule_kif->pfik_group != NULL)
300		TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
301			if (p->ifgl_group == rule_kif->pfik_group)
302				return (1);
303
304	return (0);
305}
306
307void
308pfi_attach_ifnet(struct ifnet *ifp)
309{
310	struct pfi_kif		*kif;
311	int			 s;
312
313	pfi_initialize();
314	s = splsoftnet();
315	pfi_update++;
316	if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
317		panic("pfi_kif_get failed");
318
319	kif->pfik_ifp = ifp;
320	ifp->if_pf_kif = (caddr_t)kif;
321
322#ifndef __FreeBSD__
323	if ((kif->pfik_ah_cookie = hook_establish(ifp->if_addrhooks, 1,
324	    pfi_kifaddr_update, kif)) == NULL)
325		panic("pfi_attach_ifnet: cannot allocate '%s' address hook",
326		    ifp->if_xname);
327#endif
328
329	pfi_kif_update(kif);
330
331	splx(s);
332}
333
334void
335pfi_detach_ifnet(struct ifnet *ifp)
336{
337	int			 s;
338	struct pfi_kif		*kif;
339
340	if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
341		return;
342
343	s = splsoftnet();
344	pfi_update++;
345#ifndef __FreeBSD__
346	hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie);
347#endif
348	pfi_kif_update(kif);
349
350	kif->pfik_ifp = NULL;
351	ifp->if_pf_kif = NULL;
352	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
353	splx(s);
354}
355
356void
357pfi_attach_ifgroup(struct ifg_group *ifg)
358{
359	struct pfi_kif	*kif;
360	int		 s;
361
362	pfi_initialize();
363	s = splsoftnet();
364	pfi_update++;
365	if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
366		panic("pfi_kif_get failed");
367
368	kif->pfik_group = ifg;
369	ifg->ifg_pf_kif = (caddr_t)kif;
370
371	splx(s);
372}
373
374void
375pfi_detach_ifgroup(struct ifg_group *ifg)
376{
377	int		 s;
378	struct pfi_kif	*kif;
379
380	if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
381		return;
382
383	s = splsoftnet();
384	pfi_update++;
385
386	kif->pfik_group = NULL;
387	ifg->ifg_pf_kif = NULL;
388	pfi_kif_unref(kif, PFI_KIF_REF_NONE);
389	splx(s);
390}
391
392void
393pfi_group_change(const char *group)
394{
395	struct pfi_kif		*kif;
396	int			 s;
397
398	s = splsoftnet();
399	pfi_update++;
400	if ((kif = pfi_kif_get(group)) == NULL)
401		panic("pfi_kif_get failed");
402
403	pfi_kif_update(kif);
404
405	splx(s);
406}
407
408int
409pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
410{
411	switch (af) {
412#ifdef INET
413	case AF_INET:
414		switch (dyn->pfid_acnt4) {
415		case 0:
416			return (0);
417		case 1:
418			return (PF_MATCHA(0, &dyn->pfid_addr4,
419			    &dyn->pfid_mask4, a, AF_INET));
420		default:
421			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
422		}
423		break;
424#endif /* INET */
425#ifdef INET6
426	case AF_INET6:
427		switch (dyn->pfid_acnt6) {
428		case 0:
429			return (0);
430		case 1:
431			return (PF_MATCHA(0, &dyn->pfid_addr6,
432			    &dyn->pfid_mask6, a, AF_INET6));
433		default:
434			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
435		}
436		break;
437#endif /* INET6 */
438	default:
439		return (0);
440	}
441}
442
443int
444pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
445{
446	struct pfi_dynaddr	*dyn;
447	char			 tblname[PF_TABLE_NAME_SIZE];
448	struct pf_ruleset	*ruleset = NULL;
449	int			 s, rv = 0;
450
451	if (aw->type != PF_ADDR_DYNIFTL)
452		return (0);
453	if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL)
454		return (1);
455	bzero(dyn, sizeof(*dyn));
456
457	s = splsoftnet();
458	if (!strcmp(aw->v.ifname, "self"))
459		dyn->pfid_kif = pfi_kif_get(IFG_ALL);
460	else
461		dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
462	if (dyn->pfid_kif == NULL) {
463		rv = 1;
464		goto _bad;
465	}
466	pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
467
468	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
469	if (af == AF_INET && dyn->pfid_net == 32)
470		dyn->pfid_net = 128;
471	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
472	if (aw->iflags & PFI_AFLAG_NETWORK)
473		strlcat(tblname, ":network", sizeof(tblname));
474	if (aw->iflags & PFI_AFLAG_BROADCAST)
475		strlcat(tblname, ":broadcast", sizeof(tblname));
476	if (aw->iflags & PFI_AFLAG_PEER)
477		strlcat(tblname, ":peer", sizeof(tblname));
478	if (aw->iflags & PFI_AFLAG_NOALIAS)
479		strlcat(tblname, ":0", sizeof(tblname));
480	if (dyn->pfid_net != 128)
481		snprintf(tblname + strlen(tblname),
482		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
483	if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
484		rv = 1;
485		goto _bad;
486	}
487
488	if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
489		rv = 1;
490		goto _bad;
491	}
492
493	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
494	dyn->pfid_iflags = aw->iflags;
495	dyn->pfid_af = af;
496
497	TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
498	aw->p.dyn = dyn;
499	pfi_kif_update(dyn->pfid_kif);
500	splx(s);
501	return (0);
502
503_bad:
504	if (dyn->pfid_kt != NULL)
505		pfr_detach_table(dyn->pfid_kt);
506	if (ruleset != NULL)
507		pf_remove_if_empty_ruleset(ruleset);
508	if (dyn->pfid_kif != NULL)
509		pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
510	pool_put(&pfi_addr_pl, dyn);
511	splx(s);
512	return (rv);
513}
514
515void
516pfi_kif_update(struct pfi_kif *kif)
517{
518	struct ifg_list		*ifgl;
519	struct pfi_dynaddr	*p;
520
521	/* update all dynaddr */
522	TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
523		pfi_dynaddr_update(p);
524
525	/* again for all groups kif is member of */
526	if (kif->pfik_ifp != NULL)
527		TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
528			pfi_kif_update((struct pfi_kif *)
529			    ifgl->ifgl_group->ifg_pf_kif);
530}
531
532void
533pfi_dynaddr_update(struct pfi_dynaddr *dyn)
534{
535	struct pfi_kif		*kif;
536	struct pfr_ktable	*kt;
537
538	if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
539		panic("pfi_dynaddr_update");
540
541	kif = dyn->pfid_kif;
542	kt = dyn->pfid_kt;
543
544	if (kt->pfrkt_larg != pfi_update) {
545		/* this table needs to be brought up-to-date */
546		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
547		kt->pfrkt_larg = pfi_update;
548	}
549	pfr_dynaddr_update(kt, dyn);
550}
551
552void
553pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
554{
555	int			 e, size2 = 0;
556	struct ifg_member	*ifgm;
557
558	pfi_buffer_cnt = 0;
559
560	if (kif->pfik_ifp != NULL)
561		pfi_instance_add(kif->pfik_ifp, net, flags);
562	else if (kif->pfik_group != NULL)
563		TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
564			pfi_instance_add(ifgm->ifgm_ifp, net, flags);
565
566	if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
567	    NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
568		printf("pfi_table_update: cannot set %d new addresses "
569		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
570}
571
572void
573pfi_instance_add(struct ifnet *ifp, int net, int flags)
574{
575	struct ifaddr	*ia;
576	int		 got4 = 0, got6 = 0;
577	int		 net2, af;
578
579	if (ifp == NULL)
580		return;
581	TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
582		if (ia->ifa_addr == NULL)
583			continue;
584		af = ia->ifa_addr->sa_family;
585		if (af != AF_INET && af != AF_INET6)
586			continue;
587#ifdef __FreeBSD__
588		/*
589		 * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
590		 *	jump over addresses without a proper route to work
591		 *	around a problem with ppp not fully removing the
592		 *	address used during IPCP.
593		 */
594		if ((ifp->if_flags & IFF_POINTOPOINT) &&
595		    !(ia->ifa_flags & IFA_ROUTE) &&
596		    (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
597			continue;
598#endif
599		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
600			continue;
601		if ((flags & PFI_AFLAG_BROADCAST) &&
602		    !(ifp->if_flags & IFF_BROADCAST))
603			continue;
604		if ((flags & PFI_AFLAG_PEER) &&
605		    !(ifp->if_flags & IFF_POINTOPOINT))
606			continue;
607		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
608		    IN6_IS_ADDR_LINKLOCAL(
609		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
610			continue;
611		if (flags & PFI_AFLAG_NOALIAS) {
612			if (af == AF_INET && got4)
613				continue;
614			if (af == AF_INET6 && got6)
615				continue;
616		}
617		if (af == AF_INET)
618			got4 = 1;
619		else if (af == AF_INET6)
620			got6 = 1;
621		net2 = net;
622		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
623			if (af == AF_INET)
624				net2 = pfi_unmask(&((struct sockaddr_in *)
625				    ia->ifa_netmask)->sin_addr);
626			else if (af == AF_INET6)
627				net2 = pfi_unmask(&((struct sockaddr_in6 *)
628				    ia->ifa_netmask)->sin6_addr);
629		}
630		if (af == AF_INET && net2 > 32)
631			net2 = 32;
632		if (flags & PFI_AFLAG_BROADCAST)
633			pfi_address_add(ia->ifa_broadaddr, af, net2);
634		else if (flags & PFI_AFLAG_PEER)
635			pfi_address_add(ia->ifa_dstaddr, af, net2);
636		else
637			pfi_address_add(ia->ifa_addr, af, net2);
638	}
639}
640
641void
642pfi_address_add(struct sockaddr *sa, int af, int net)
643{
644	struct pfr_addr	*p;
645	int		 i;
646
647	if (pfi_buffer_cnt >= pfi_buffer_max) {
648		int		 new_max = pfi_buffer_max * 2;
649
650		if (new_max > PFI_BUFFER_MAX) {
651			printf("pfi_address_add: address buffer full (%d/%d)\n",
652			    pfi_buffer_cnt, PFI_BUFFER_MAX);
653			return;
654		}
655		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
656#ifdef __FreeBSD__
657		    M_NOWAIT);
658#else
659		    M_DONTWAIT);
660#endif
661		if (p == NULL) {
662			printf("pfi_address_add: no memory to grow buffer "
663			    "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
664			return;
665		}
666		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
667		/* no need to zero buffer */
668		free(pfi_buffer, PFI_MTYPE);
669		pfi_buffer = p;
670		pfi_buffer_max = new_max;
671	}
672	if (af == AF_INET && net > 32)
673		net = 128;
674	p = pfi_buffer + pfi_buffer_cnt++;
675	bzero(p, sizeof(*p));
676	p->pfra_af = af;
677	p->pfra_net = net;
678	if (af == AF_INET)
679		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
680	else if (af == AF_INET6) {
681		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
682		if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
683			p->pfra_ip6addr.s6_addr16[1] = 0;
684	}
685	/* mask network address bits */
686	if (net < 128)
687		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
688	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
689		((caddr_t)p)[i] = 0;
690}
691
692void
693pfi_dynaddr_remove(struct pf_addr_wrap *aw)
694{
695	int	s;
696
697	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
698	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
699		return;
700
701	s = splsoftnet();
702	TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
703	pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
704	aw->p.dyn->pfid_kif = NULL;
705	pfr_detach_table(aw->p.dyn->pfid_kt);
706	aw->p.dyn->pfid_kt = NULL;
707	pool_put(&pfi_addr_pl, aw->p.dyn);
708	aw->p.dyn = NULL;
709	splx(s);
710}
711
712void
713pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
714{
715	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
716	    aw->p.dyn->pfid_kif == NULL)
717		return;
718	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
719}
720
721void
722pfi_kifaddr_update(void *v)
723{
724	int			 s;
725	struct pfi_kif		*kif = (struct pfi_kif *)v;
726
727	s = splsoftnet();
728	pfi_update++;
729	pfi_kif_update(kif);
730	splx(s);
731}
732
733int
734pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
735{
736	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
737}
738
739void
740pfi_fill_oldstatus(struct pf_status *pfs)
741{
742	struct pfi_kif		*p;
743	struct pfi_kif_cmp 	 key;
744	int			 i, j, k, s;
745
746	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
747	s = splsoftnet();
748	p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
749	if (p == NULL) {
750		splx(s);
751		return;
752	}
753	bzero(pfs->pcounters, sizeof(pfs->pcounters));
754	bzero(pfs->bcounters, sizeof(pfs->bcounters));
755	for (i = 0; i < 2; i++)
756		for (j = 0; j < 2; j++)
757			for (k = 0; k < 2; k++) {
758				pfs->pcounters[i][j][k] =
759					p->pfik_packets[i][j][k];
760				pfs->bcounters[i][j] +=
761					p->pfik_bytes[i][j][k];
762			}
763	splx(s);
764}
765
766int
767pfi_clr_istats(const char *name)
768{
769	struct pfi_kif	*p;
770	int		 s;
771
772	s = splsoftnet();
773	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
774		if (pfi_skip_if(name, p))
775			continue;
776		bzero(p->pfik_packets, sizeof(p->pfik_packets));
777		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
778		p->pfik_tzero = time_second;
779	}
780	splx(s);
781
782	return (0);
783}
784
785int
786pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
787{
788	struct pfi_kif	*p, *nextp;
789	int		 s, n = 0;
790#ifdef __FreeBSD__
791	int		 error;
792#endif
793
794	s = splsoftnet();
795	for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
796		nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
797		if (pfi_skip_if(name, p))
798			continue;
799		if (*size > n++) {
800			if (!p->pfik_tzero)
801				p->pfik_tzero = time_second;
802			pfi_kif_ref(p, PFI_KIF_REF_RULE);
803#ifdef __FreeBSD__
804			PF_COPYOUT(p, buf++, sizeof(*buf), error);
805			if (error) {
806#else
807			if (copyout(p, buf++, sizeof(*buf))) {
808#endif
809				pfi_kif_unref(p, PFI_KIF_REF_RULE);
810				splx(s);
811				return (EFAULT);
812			}
813			nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
814			pfi_kif_unref(p, PFI_KIF_REF_RULE);
815		}
816	}
817	splx(s);
818	*size = n;
819	return (0);
820}
821
822int
823pfi_skip_if(const char *filter, struct pfi_kif *p)
824{
825	int	n;
826
827	if (filter == NULL || !*filter)
828		return (0);
829	if (!strcmp(p->pfik_name, filter))
830		return (0);	/* exact match */
831	n = strlen(filter);
832	if (n < 1 || n >= IFNAMSIZ)
833		return (1);	/* sanity check */
834	if (filter[n-1] >= '0' && filter[n-1] <= '9')
835		return (1);	/* only do exact match in that case */
836	if (strncmp(p->pfik_name, filter, n))
837		return (1);	/* prefix doesn't match */
838	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
839}
840
841int
842pfi_set_flags(const char *name, int flags)
843{
844	struct pfi_kif	*p;
845	int		 s;
846
847	s = splsoftnet();
848	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
849		if (pfi_skip_if(name, p))
850			continue;
851		p->pfik_flags |= flags;
852	}
853	splx(s);
854	return (0);
855}
856
857int
858pfi_clear_flags(const char *name, int flags)
859{
860	struct pfi_kif	*p;
861	int		 s;
862
863	s = splsoftnet();
864	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
865		if (pfi_skip_if(name, p))
866			continue;
867		p->pfik_flags &= ~flags;
868	}
869	splx(s);
870	return (0);
871}
872
873/* from pf_print_state.c */
874int
875pfi_unmask(void *addr)
876{
877	struct pf_addr *m = addr;
878	int i = 31, j = 0, b = 0;
879	u_int32_t tmp;
880
881	while (j < 4 && m->addr32[j] == 0xffffffff) {
882		b += 32;
883		j++;
884	}
885	if (j < 4) {
886		tmp = ntohl(m->addr32[j]);
887		for (i = 31; tmp & (1 << i); --i)
888			b++;
889	}
890	return (b);
891}
892
893#ifdef __FreeBSD__
894void
895pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
896{
897	PF_LOCK();
898	pfi_attach_ifnet(ifp);
899#ifdef ALTQ
900	pf_altq_ifnet_event(ifp, 0);
901#endif
902	PF_UNLOCK();
903}
904
905void
906pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
907{
908	PF_LOCK();
909	pfi_detach_ifnet(ifp);
910#ifdef ALTQ
911	pf_altq_ifnet_event(ifp, 1);
912#endif
913	PF_UNLOCK();
914}
915
916void
917pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg)
918{
919	PF_LOCK();
920	pfi_attach_ifgroup(ifg);
921	PF_UNLOCK();
922}
923
924void
925pfi_change_group_event(void *arg __unused, char *gname)
926{
927	PF_LOCK();
928	pfi_group_change(gname);
929	PF_UNLOCK();
930}
931
932void
933pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg)
934{
935	PF_LOCK();
936	pfi_detach_ifgroup(ifg);
937	PF_UNLOCK();
938}
939
940void
941pfi_ifaddr_event(void *arg __unused, struct ifnet *ifp)
942{
943	PF_LOCK();
944	if (ifp && ifp->if_pf_kif)
945		pfi_kifaddr_update(ifp->if_pf_kif);
946	PF_UNLOCK();
947}
948#endif /* __FreeBSD__ */
949