xref: /netbsd/sys/dist/pf/net/pf_if.c (revision 97107414)
1*97107414Speter /*	$NetBSD: pf_if.c,v 1.9 2005/07/01 12:37:35 peter Exp $	*/
2*97107414Speter /*	$OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
36adffbf9Sitojun 
46adffbf9Sitojun /*
56adffbf9Sitojun  * Copyright (c) 2001 Daniel Hartmeier
66adffbf9Sitojun  * Copyright (c) 2003 Cedric Berger
76adffbf9Sitojun  * All rights reserved.
86adffbf9Sitojun  *
96adffbf9Sitojun  * Redistribution and use in source and binary forms, with or without
106adffbf9Sitojun  * modification, are permitted provided that the following conditions
116adffbf9Sitojun  * are met:
126adffbf9Sitojun  *
136adffbf9Sitojun  *    - Redistributions of source code must retain the above copyright
146adffbf9Sitojun  *      notice, this list of conditions and the following disclaimer.
156adffbf9Sitojun  *    - Redistributions in binary form must reproduce the above
166adffbf9Sitojun  *      copyright notice, this list of conditions and the following
176adffbf9Sitojun  *      disclaimer in the documentation and/or other materials provided
186adffbf9Sitojun  *      with the distribution.
196adffbf9Sitojun  *
206adffbf9Sitojun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
216adffbf9Sitojun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
226adffbf9Sitojun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
236adffbf9Sitojun  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
246adffbf9Sitojun  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
256adffbf9Sitojun  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
266adffbf9Sitojun  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
276adffbf9Sitojun  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
286adffbf9Sitojun  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296adffbf9Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
306adffbf9Sitojun  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
316adffbf9Sitojun  * POSSIBILITY OF SUCH DAMAGE.
326adffbf9Sitojun  */
336adffbf9Sitojun 
34bfcdaa57Sitojun #ifdef _KERNEL_OPT
35bfcdaa57Sitojun #include "opt_inet.h"
36bfcdaa57Sitojun #endif
37bfcdaa57Sitojun 
386adffbf9Sitojun #include <sys/param.h>
396adffbf9Sitojun #include <sys/systm.h>
406adffbf9Sitojun #include <sys/mbuf.h>
416adffbf9Sitojun #include <sys/filio.h>
426adffbf9Sitojun #include <sys/socket.h>
436adffbf9Sitojun #include <sys/socketvar.h>
446adffbf9Sitojun #include <sys/kernel.h>
456adffbf9Sitojun #include <sys/device.h>
466adffbf9Sitojun #include <sys/time.h>
476adffbf9Sitojun 
486adffbf9Sitojun #include <net/if.h>
496adffbf9Sitojun #include <net/if_types.h>
506adffbf9Sitojun 
516adffbf9Sitojun #include <netinet/in.h>
526adffbf9Sitojun #include <netinet/in_var.h>
536adffbf9Sitojun #include <netinet/in_systm.h>
546adffbf9Sitojun #include <netinet/ip.h>
556adffbf9Sitojun #include <netinet/ip_var.h>
566adffbf9Sitojun 
576adffbf9Sitojun #include <net/pfvar.h>
586adffbf9Sitojun 
596adffbf9Sitojun #ifdef INET6
606adffbf9Sitojun #include <netinet/ip6.h>
616adffbf9Sitojun #endif /* INET6 */
626adffbf9Sitojun 
636adffbf9Sitojun #define ACCEPT_FLAGS(oklist)			\
646adffbf9Sitojun 	do {					\
656adffbf9Sitojun 		if ((flags & ~(oklist)) &	\
666adffbf9Sitojun 		    PFI_FLAG_ALLMASK)		\
676adffbf9Sitojun 			return (EINVAL);	\
686adffbf9Sitojun 	} while (0)
696adffbf9Sitojun 
706adffbf9Sitojun #define senderr(e)      do { rv = (e); goto _bad; } while (0)
716adffbf9Sitojun 
726adffbf9Sitojun struct pfi_kif		**pfi_index2kif;
736adffbf9Sitojun struct pfi_kif		 *pfi_self;
746adffbf9Sitojun int			  pfi_indexlim;
756adffbf9Sitojun struct pfi_ifhead	  pfi_ifs;
766adffbf9Sitojun struct pfi_statehead	  pfi_statehead;
776adffbf9Sitojun int			  pfi_ifcnt;
786adffbf9Sitojun struct pool		  pfi_addr_pl;
796adffbf9Sitojun long			  pfi_update = 1;
806adffbf9Sitojun struct pfr_addr		 *pfi_buffer;
816adffbf9Sitojun int			  pfi_buffer_cnt;
826adffbf9Sitojun int			  pfi_buffer_max;
836adffbf9Sitojun 
846adffbf9Sitojun void		 pfi_dynaddr_update(void *);
856adffbf9Sitojun void		 pfi_kifaddr_update(void *);
8646abcaebSyamt #ifdef __NetBSD__
8746abcaebSyamt void		 pfi_kifaddr_update_if(struct ifnet *);
8846abcaebSyamt #endif
896adffbf9Sitojun void		 pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
906adffbf9Sitojun 		    int, int);
916adffbf9Sitojun void		 pfi_instance_add(struct ifnet *, int, int);
926adffbf9Sitojun void		 pfi_address_add(struct sockaddr *, int, int);
936adffbf9Sitojun int		 pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
946adffbf9Sitojun struct pfi_kif	*pfi_if_create(const char *, struct pfi_kif *, int);
956adffbf9Sitojun void		 pfi_copy_group(char *, const char *, int);
966adffbf9Sitojun void		 pfi_newgroup(const char *, int);
976adffbf9Sitojun int		 pfi_skip_if(const char *, struct pfi_kif *, int);
986adffbf9Sitojun int		 pfi_unmask(void *);
996adffbf9Sitojun void		 pfi_dohooks(struct pfi_kif *);
1006adffbf9Sitojun 
1016adffbf9Sitojun RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
1026adffbf9Sitojun RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
1036adffbf9Sitojun 
1046adffbf9Sitojun #define PFI_BUFFER_MAX		0x10000
1056adffbf9Sitojun #define PFI_MTYPE		M_IFADDR
1066adffbf9Sitojun 
107bfcdaa57Sitojun #ifdef __NetBSD__
108bfcdaa57Sitojun static void	*hook_establish(struct hook_desc_head *, int, void (*)(void *),
109bfcdaa57Sitojun 			void *);
110bfcdaa57Sitojun static void	hook_disestablish(struct hook_desc_head *, void *);
11146abcaebSyamt static void	dohooks(struct hook_desc_head *, int);
112bfcdaa57Sitojun 
113bfcdaa57Sitojun #define HOOK_REMOVE	0x01
114bfcdaa57Sitojun #define HOOK_FREE	0x02
115bfcdaa57Sitojun #endif
116bfcdaa57Sitojun 
1176adffbf9Sitojun void
1186adffbf9Sitojun pfi_initialize(void)
1196adffbf9Sitojun {
1206adffbf9Sitojun 	if (pfi_self != NULL)	/* already initialized */
1216adffbf9Sitojun 		return;
1226adffbf9Sitojun 
1236adffbf9Sitojun 	TAILQ_INIT(&pfi_statehead);
1246adffbf9Sitojun 	pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
1256adffbf9Sitojun 	    "pfiaddrpl", &pool_allocator_nointr);
1266adffbf9Sitojun 	pfi_buffer_max = 64;
1276adffbf9Sitojun 	pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
1286adffbf9Sitojun 	    PFI_MTYPE, M_WAITOK);
1296adffbf9Sitojun 	pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
1306adffbf9Sitojun }
1316adffbf9Sitojun 
1320407dd42Sitojun #ifdef _LKM
1330407dd42Sitojun void
1340407dd42Sitojun pfi_destroy(void)
1350407dd42Sitojun {
1360407dd42Sitojun 	pool_destroy(&pfi_addr_pl);
1370407dd42Sitojun 
138fd3bd491Speter 	free(pfi_buffer, PFI_MTYPE);
1390407dd42Sitojun }
1400407dd42Sitojun #endif
1410407dd42Sitojun 
1426adffbf9Sitojun void
1436adffbf9Sitojun pfi_attach_clone(struct if_clone *ifc)
1446adffbf9Sitojun {
1456adffbf9Sitojun 	pfi_initialize();
1466adffbf9Sitojun 	pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
1476adffbf9Sitojun }
1486adffbf9Sitojun 
1496adffbf9Sitojun void
1506adffbf9Sitojun pfi_attach_ifnet(struct ifnet *ifp)
1516adffbf9Sitojun {
1526adffbf9Sitojun 	struct pfi_kif	*p, *q, key;
1536adffbf9Sitojun 	int		 s;
1546adffbf9Sitojun 
1556adffbf9Sitojun 	pfi_initialize();
1566adffbf9Sitojun 	s = splsoftnet();
1576adffbf9Sitojun 	pfi_update++;
1586adffbf9Sitojun 	if (ifp->if_index >= pfi_indexlim) {
1596adffbf9Sitojun 		/*
1606adffbf9Sitojun 		 * grow pfi_index2kif,  similar to ifindex2ifnet code in if.c
1616adffbf9Sitojun 		 */
1626adffbf9Sitojun 		size_t m, n, oldlim;
1636adffbf9Sitojun 		struct pfi_kif **mp, **np;
1646adffbf9Sitojun 
1656adffbf9Sitojun 		oldlim = pfi_indexlim;
1666adffbf9Sitojun 		if (pfi_indexlim == 0)
1676adffbf9Sitojun 			pfi_indexlim = 64;
1686adffbf9Sitojun 		while (ifp->if_index >= pfi_indexlim)
1696adffbf9Sitojun 			pfi_indexlim <<= 1;
1706adffbf9Sitojun 
1716adffbf9Sitojun 		m = oldlim * sizeof(struct pfi_kif *);
1726adffbf9Sitojun 		mp = pfi_index2kif;
1736adffbf9Sitojun 		n = pfi_indexlim * sizeof(struct pfi_kif *);
1746adffbf9Sitojun 		np = malloc(n, PFI_MTYPE, M_DONTWAIT);
1756adffbf9Sitojun 		if (np == NULL)
1766adffbf9Sitojun 			panic("pfi_attach_ifnet: "
1776adffbf9Sitojun 			    "cannot allocate translation table");
1786adffbf9Sitojun 		bzero(np, n);
1796adffbf9Sitojun 		if (mp != NULL)
1806adffbf9Sitojun 			bcopy(mp, np, m);
1816adffbf9Sitojun 		pfi_index2kif = np;
1826adffbf9Sitojun 		if (mp != NULL)
1836adffbf9Sitojun 			free(mp, PFI_MTYPE);
1846adffbf9Sitojun 	}
1856adffbf9Sitojun 
1866adffbf9Sitojun 	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
1876adffbf9Sitojun 	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
1886adffbf9Sitojun 	if (p == NULL) {
1896adffbf9Sitojun 		/* add group */
1906adffbf9Sitojun 		pfi_copy_group(key.pfik_name, ifp->if_xname,
1916adffbf9Sitojun 		    sizeof(key.pfik_name));
1926adffbf9Sitojun 		q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
1936adffbf9Sitojun 		if (q == NULL)
1946adffbf9Sitojun 		    q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
1956adffbf9Sitojun 		if (q == NULL)
1966adffbf9Sitojun 			panic("pfi_attach_ifnet: "
1976adffbf9Sitojun 			    "cannot allocate '%s' group", key.pfik_name);
1986adffbf9Sitojun 
1996adffbf9Sitojun 		/* add interface */
2006adffbf9Sitojun 		p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
2016adffbf9Sitojun 		if (p == NULL)
2026adffbf9Sitojun 			panic("pfi_attach_ifnet: "
2036adffbf9Sitojun 			    "cannot allocate '%s' interface", ifp->if_xname);
2046adffbf9Sitojun 	} else
2056adffbf9Sitojun 		q = p->pfik_parent;
2066adffbf9Sitojun 	p->pfik_ifp = ifp;
2076adffbf9Sitojun 	p->pfik_flags |= PFI_IFLAG_ATTACHED;
208bfcdaa57Sitojun #ifdef __OpenBSD__
2096adffbf9Sitojun 	p->pfik_ah_cookie =
2106adffbf9Sitojun 	    hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
211bfcdaa57Sitojun #else
212bfcdaa57Sitojun 	p->pfik_ah_cookie =
2130a7a28fcSyamt 	    hook_establish(&p->pfik_ifaddrhooks, 1, pfi_kifaddr_update, p);
214bfcdaa57Sitojun #endif
2156adffbf9Sitojun 	pfi_index2kif[ifp->if_index] = p;
2166adffbf9Sitojun 	pfi_dohooks(p);
2176adffbf9Sitojun 	splx(s);
2186adffbf9Sitojun }
2196adffbf9Sitojun 
2206adffbf9Sitojun void
2216adffbf9Sitojun pfi_detach_ifnet(struct ifnet *ifp)
2226adffbf9Sitojun {
2236adffbf9Sitojun 	struct pfi_kif	*p, *q, key;
2246adffbf9Sitojun 	int		 s;
2256adffbf9Sitojun 
2266adffbf9Sitojun 	strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
2276adffbf9Sitojun 
2286adffbf9Sitojun 	s = splsoftnet();
2296adffbf9Sitojun 	pfi_update++;
2306adffbf9Sitojun 	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
2316adffbf9Sitojun 	if (p == NULL) {
2326adffbf9Sitojun 		printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
2336adffbf9Sitojun 		splx(s);
2346adffbf9Sitojun 		return;
2356adffbf9Sitojun 	}
236bfcdaa57Sitojun #ifdef __OpenBSD__
2376adffbf9Sitojun 	hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
238bfcdaa57Sitojun #else
2390a7a28fcSyamt 	hook_disestablish(&p->pfik_ifaddrhooks, p->pfik_ah_cookie);
240bfcdaa57Sitojun #endif
2416adffbf9Sitojun 	q = p->pfik_parent;
2426adffbf9Sitojun 	p->pfik_ifp = NULL;
2436adffbf9Sitojun 	p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
2446adffbf9Sitojun 	pfi_index2kif[ifp->if_index] = NULL;
2456adffbf9Sitojun 	pfi_dohooks(p);
2466adffbf9Sitojun 	pfi_maybe_destroy(p);
2476adffbf9Sitojun 	splx(s);
2486adffbf9Sitojun }
2496adffbf9Sitojun 
2506adffbf9Sitojun struct pfi_kif *
2516adffbf9Sitojun pfi_lookup_create(const char *name)
2526adffbf9Sitojun {
2536adffbf9Sitojun 	struct pfi_kif	*p, *q, key;
2546adffbf9Sitojun 	int		 s;
2556adffbf9Sitojun 
2566adffbf9Sitojun 	s = splsoftnet();
2576adffbf9Sitojun 	p = pfi_lookup_if(name);
2586adffbf9Sitojun 	if (p == NULL) {
2596adffbf9Sitojun 		pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
2606adffbf9Sitojun 		q = pfi_lookup_if(key.pfik_name);
261da186141Syamt 		if (q == NULL) {
262da186141Syamt 			pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC);
263da186141Syamt 			q = pfi_lookup_if(key.pfik_name);
264da186141Syamt 		}
265da186141Syamt 		p = pfi_lookup_if(name);
266da186141Syamt 		if (p == NULL && q != NULL)
2676adffbf9Sitojun 			p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
2686adffbf9Sitojun 	}
2696adffbf9Sitojun 	splx(s);
2706adffbf9Sitojun 	return (p);
2716adffbf9Sitojun }
2726adffbf9Sitojun 
2736adffbf9Sitojun struct pfi_kif *
2746adffbf9Sitojun pfi_attach_rule(const char *name)
2756adffbf9Sitojun {
2766adffbf9Sitojun 	struct pfi_kif	*p;
2776adffbf9Sitojun 
2786adffbf9Sitojun 	p = pfi_lookup_create(name);
2796adffbf9Sitojun 	if (p != NULL)
2806adffbf9Sitojun 		p->pfik_rules++;
2816adffbf9Sitojun 	return (p);
2826adffbf9Sitojun }
2836adffbf9Sitojun 
2846adffbf9Sitojun void
2856adffbf9Sitojun pfi_detach_rule(struct pfi_kif *p)
2866adffbf9Sitojun {
2876adffbf9Sitojun 	if (p == NULL)
2886adffbf9Sitojun 		return;
2896adffbf9Sitojun 	if (p->pfik_rules > 0)
2906adffbf9Sitojun 		p->pfik_rules--;
2916adffbf9Sitojun 	else
2926adffbf9Sitojun 		printf("pfi_detach_rule: reference count at 0\n");
2936adffbf9Sitojun 	pfi_maybe_destroy(p);
2946adffbf9Sitojun }
2956adffbf9Sitojun 
2966adffbf9Sitojun void
2976adffbf9Sitojun pfi_attach_state(struct pfi_kif *p)
2986adffbf9Sitojun {
2996adffbf9Sitojun 	if (!p->pfik_states++)
3006adffbf9Sitojun 		TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
3016adffbf9Sitojun }
3026adffbf9Sitojun 
3036adffbf9Sitojun void
3046adffbf9Sitojun pfi_detach_state(struct pfi_kif *p)
3056adffbf9Sitojun {
3066adffbf9Sitojun 	if (p == NULL)
3076adffbf9Sitojun 		return;
3086adffbf9Sitojun 	if (p->pfik_states <= 0) {
3096adffbf9Sitojun 		printf("pfi_detach_state: reference count <= 0\n");
3106adffbf9Sitojun 		return;
3116adffbf9Sitojun 	}
3126adffbf9Sitojun 	if (!--p->pfik_states)
3136adffbf9Sitojun 		TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
3146adffbf9Sitojun 	pfi_maybe_destroy(p);
3156adffbf9Sitojun }
3166adffbf9Sitojun 
3176adffbf9Sitojun int
3186adffbf9Sitojun pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
3196adffbf9Sitojun {
3206adffbf9Sitojun 	struct pfi_dynaddr	*dyn;
3216adffbf9Sitojun 	char			 tblname[PF_TABLE_NAME_SIZE];
3226adffbf9Sitojun 	struct pf_ruleset	*ruleset = NULL;
3236adffbf9Sitojun 	int			 s, rv = 0;
3246adffbf9Sitojun 
3256adffbf9Sitojun 	if (aw->type != PF_ADDR_DYNIFTL)
3266adffbf9Sitojun 		return (0);
3276adffbf9Sitojun 	dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
3286adffbf9Sitojun 	if (dyn == NULL)
3296adffbf9Sitojun 		return (1);
3306adffbf9Sitojun 	bzero(dyn, sizeof(*dyn));
3316adffbf9Sitojun 
3326adffbf9Sitojun 	s = splsoftnet();
3336adffbf9Sitojun 	dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
3346adffbf9Sitojun 	if (dyn->pfid_kif == NULL)
3356adffbf9Sitojun 		senderr(1);
3366adffbf9Sitojun 
3376adffbf9Sitojun 	dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
3386adffbf9Sitojun 	if (af == AF_INET && dyn->pfid_net == 32)
3396adffbf9Sitojun 		dyn->pfid_net = 128;
3406adffbf9Sitojun 	strlcpy(tblname, aw->v.ifname, sizeof(tblname));
3416adffbf9Sitojun 	if (aw->iflags & PFI_AFLAG_NETWORK)
3426adffbf9Sitojun 		strlcat(tblname, ":network", sizeof(tblname));
3436adffbf9Sitojun 	if (aw->iflags & PFI_AFLAG_BROADCAST)
3446adffbf9Sitojun 		strlcat(tblname, ":broadcast", sizeof(tblname));
3456adffbf9Sitojun 	if (aw->iflags & PFI_AFLAG_PEER)
3466adffbf9Sitojun 		strlcat(tblname, ":peer", sizeof(tblname));
3476adffbf9Sitojun 	if (aw->iflags & PFI_AFLAG_NOALIAS)
3486adffbf9Sitojun 		strlcat(tblname, ":0", sizeof(tblname));
3496adffbf9Sitojun 	if (dyn->pfid_net != 128)
3506adffbf9Sitojun 		snprintf(tblname + strlen(tblname),
3516adffbf9Sitojun 		    sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
352da186141Syamt 	ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR);
3536adffbf9Sitojun 	if (ruleset == NULL)
3546adffbf9Sitojun 		senderr(1);
3556adffbf9Sitojun 
3566adffbf9Sitojun 	dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
3576adffbf9Sitojun 	if (dyn->pfid_kt == NULL)
3586adffbf9Sitojun 		senderr(1);
3596adffbf9Sitojun 
3606adffbf9Sitojun 	dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
3616adffbf9Sitojun 	dyn->pfid_iflags = aw->iflags;
3626adffbf9Sitojun 	dyn->pfid_af = af;
3636adffbf9Sitojun 	dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
3646adffbf9Sitojun 	    pfi_dynaddr_update, dyn);
3656adffbf9Sitojun 	if (dyn->pfid_hook_cookie == NULL)
3666adffbf9Sitojun 		senderr(1);
3676adffbf9Sitojun 
3686adffbf9Sitojun 	aw->p.dyn = dyn;
3696adffbf9Sitojun 	pfi_dynaddr_update(aw->p.dyn);
3706adffbf9Sitojun 	splx(s);
3716adffbf9Sitojun 	return (0);
3726adffbf9Sitojun 
3736adffbf9Sitojun _bad:
3746adffbf9Sitojun 	if (dyn->pfid_kt != NULL)
3756adffbf9Sitojun 		pfr_detach_table(dyn->pfid_kt);
3766adffbf9Sitojun 	if (ruleset != NULL)
3776adffbf9Sitojun 		pf_remove_if_empty_ruleset(ruleset);
3786adffbf9Sitojun 	if (dyn->pfid_kif != NULL)
3796adffbf9Sitojun 		pfi_detach_rule(dyn->pfid_kif);
3806adffbf9Sitojun 	pool_put(&pfi_addr_pl, dyn);
3816adffbf9Sitojun 	splx(s);
3826adffbf9Sitojun 	return (rv);
3836adffbf9Sitojun }
3846adffbf9Sitojun 
3856adffbf9Sitojun void
3866adffbf9Sitojun pfi_dynaddr_update(void *p)
3876adffbf9Sitojun {
3886adffbf9Sitojun 	struct pfi_dynaddr	*dyn = (struct pfi_dynaddr *)p;
389*97107414Speter 	struct pfi_kif		*kif;
390*97107414Speter 	struct pfr_ktable	*kt;
3916adffbf9Sitojun 
392*97107414Speter 	if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
3936adffbf9Sitojun 		panic("pfi_dynaddr_update");
394*97107414Speter 
395*97107414Speter 	kif = dyn->pfid_kif;
396*97107414Speter 	kt = dyn->pfid_kt;
3976adffbf9Sitojun 	if (kt->pfrkt_larg != pfi_update) {
3986adffbf9Sitojun 		/* this table needs to be brought up-to-date */
3996adffbf9Sitojun 		pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
4006adffbf9Sitojun 		kt->pfrkt_larg = pfi_update;
4016adffbf9Sitojun 	}
4026adffbf9Sitojun 	pfr_dynaddr_update(kt, dyn);
4036adffbf9Sitojun }
4046adffbf9Sitojun 
4056adffbf9Sitojun void
4066adffbf9Sitojun pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
4076adffbf9Sitojun {
4086adffbf9Sitojun 	int			 e, size2 = 0;
4096adffbf9Sitojun 	struct pfi_kif		*p;
4106adffbf9Sitojun 	struct pfr_table	 t;
4116adffbf9Sitojun 
4126adffbf9Sitojun 	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
4136adffbf9Sitojun 		pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
4146adffbf9Sitojun 		return;
4156adffbf9Sitojun 	}
4166adffbf9Sitojun 	pfi_buffer_cnt = 0;
4176adffbf9Sitojun 	if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
4186adffbf9Sitojun 		pfi_instance_add(kif->pfik_ifp, net, flags);
4196adffbf9Sitojun 	else if (strcmp(kif->pfik_name, "self")) {
4206adffbf9Sitojun 		TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
4216adffbf9Sitojun 			pfi_instance_add(p->pfik_ifp, net, flags);
4226adffbf9Sitojun 	} else {
4236adffbf9Sitojun 		RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
4246adffbf9Sitojun 			if (p->pfik_flags & PFI_IFLAG_INSTANCE)
4256adffbf9Sitojun 				pfi_instance_add(p->pfik_ifp, net, flags);
4266adffbf9Sitojun 	}
4276adffbf9Sitojun 	t = kt->pfrkt_t;
4286adffbf9Sitojun 	t.pfrt_flags = 0;
4296adffbf9Sitojun 	if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
4306adffbf9Sitojun 	    NULL, NULL, NULL, 0)))
4316adffbf9Sitojun 		printf("pfi_table_update: cannot set %d new addresses "
4326adffbf9Sitojun 		    "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
4336adffbf9Sitojun }
4346adffbf9Sitojun 
4356adffbf9Sitojun void
4366adffbf9Sitojun pfi_instance_add(struct ifnet *ifp, int net, int flags)
4376adffbf9Sitojun {
4386adffbf9Sitojun 	struct ifaddr	*ia;
4396adffbf9Sitojun 	int		 got4 = 0, got6 = 0;
4406adffbf9Sitojun 	int		 net2, af;
4416adffbf9Sitojun 
4426adffbf9Sitojun 	if (ifp == NULL)
4436adffbf9Sitojun 		return;
4446adffbf9Sitojun 	TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) {
4456adffbf9Sitojun 		if (ia->ifa_addr == NULL)
4466adffbf9Sitojun 			continue;
4476adffbf9Sitojun 		af = ia->ifa_addr->sa_family;
4486adffbf9Sitojun 		if (af != AF_INET && af != AF_INET6)
4496adffbf9Sitojun 			continue;
4506adffbf9Sitojun 		if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
4516adffbf9Sitojun 			continue;
4526adffbf9Sitojun 		if ((flags & PFI_AFLAG_BROADCAST) &&
4536adffbf9Sitojun 		    !(ifp->if_flags & IFF_BROADCAST))
4546adffbf9Sitojun 			continue;
4556adffbf9Sitojun 		if ((flags & PFI_AFLAG_PEER) &&
4566adffbf9Sitojun 		    !(ifp->if_flags & IFF_POINTOPOINT))
4576adffbf9Sitojun 			continue;
4586adffbf9Sitojun 		if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
4596adffbf9Sitojun 		    IN6_IS_ADDR_LINKLOCAL(
4606adffbf9Sitojun 		    &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
4616adffbf9Sitojun 			continue;
4626adffbf9Sitojun 		if (flags & PFI_AFLAG_NOALIAS) {
4636adffbf9Sitojun 			if (af == AF_INET && got4)
4646adffbf9Sitojun 				continue;
4656adffbf9Sitojun 			if (af == AF_INET6 && got6)
4666adffbf9Sitojun 				continue;
4676adffbf9Sitojun 		}
4686adffbf9Sitojun 		if (af == AF_INET)
4696adffbf9Sitojun 			got4 = 1;
470da186141Syamt 		else if (af == AF_INET6)
4716adffbf9Sitojun 			got6 = 1;
4726adffbf9Sitojun 		net2 = net;
4736adffbf9Sitojun 		if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
4746adffbf9Sitojun 			if (af == AF_INET) {
4756adffbf9Sitojun 				net2 = pfi_unmask(&((struct sockaddr_in *)
4766adffbf9Sitojun 				    ia->ifa_netmask)->sin_addr);
477da186141Syamt 			} else if (af == AF_INET6) {
4786adffbf9Sitojun 				net2 = pfi_unmask(&((struct sockaddr_in6 *)
4796adffbf9Sitojun 				    ia->ifa_netmask)->sin6_addr);
4806adffbf9Sitojun 			}
4816adffbf9Sitojun 		}
4826adffbf9Sitojun 		if (af == AF_INET && net2 > 32)
4836adffbf9Sitojun 			net2 = 32;
4846adffbf9Sitojun 		if (flags & PFI_AFLAG_BROADCAST)
4856adffbf9Sitojun 			pfi_address_add(ia->ifa_broadaddr, af, net2);
4866adffbf9Sitojun 		else if (flags & PFI_AFLAG_PEER)
4876adffbf9Sitojun 			pfi_address_add(ia->ifa_dstaddr, af, net2);
4886adffbf9Sitojun 		else
4896adffbf9Sitojun 			pfi_address_add(ia->ifa_addr, af, net2);
4906adffbf9Sitojun 	}
4916adffbf9Sitojun }
4926adffbf9Sitojun 
4936adffbf9Sitojun void
4946adffbf9Sitojun pfi_address_add(struct sockaddr *sa, int af, int net)
4956adffbf9Sitojun {
4966adffbf9Sitojun 	struct pfr_addr	*p;
4976adffbf9Sitojun 	int		 i;
4986adffbf9Sitojun 
4996adffbf9Sitojun 	if (pfi_buffer_cnt >= pfi_buffer_max) {
5006adffbf9Sitojun 		int		 new_max = pfi_buffer_max * 2;
5016adffbf9Sitojun 
5026adffbf9Sitojun 		if (new_max > PFI_BUFFER_MAX) {
5036adffbf9Sitojun 			printf("pfi_address_add: address buffer full (%d/%d)\n",
5046adffbf9Sitojun 			    pfi_buffer_cnt, PFI_BUFFER_MAX);
5056adffbf9Sitojun 			return;
5066adffbf9Sitojun 		}
5076adffbf9Sitojun 		p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
5086adffbf9Sitojun 		    M_DONTWAIT);
5096adffbf9Sitojun 		if (p == NULL) {
5106adffbf9Sitojun 			printf("pfi_address_add: no memory to grow buffer "
5116adffbf9Sitojun 			    "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
5126adffbf9Sitojun 			return;
5136adffbf9Sitojun 		}
5146adffbf9Sitojun 		memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
5156adffbf9Sitojun 		/* no need to zero buffer */
5166adffbf9Sitojun 		free(pfi_buffer, PFI_MTYPE);
5176adffbf9Sitojun 		pfi_buffer = p;
5186adffbf9Sitojun 		pfi_buffer_max = new_max;
5196adffbf9Sitojun 	}
5206adffbf9Sitojun 	if (af == AF_INET && net > 32)
5216adffbf9Sitojun 		net = 128;
5226adffbf9Sitojun 	p = pfi_buffer + pfi_buffer_cnt++;
5236adffbf9Sitojun 	bzero(p, sizeof(*p));
5246adffbf9Sitojun 	p->pfra_af = af;
5256adffbf9Sitojun 	p->pfra_net = net;
5266adffbf9Sitojun 	if (af == AF_INET)
5276adffbf9Sitojun 		p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
5286adffbf9Sitojun 	if (af == AF_INET6) {
5296adffbf9Sitojun 		p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
5306adffbf9Sitojun 		if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
5316adffbf9Sitojun 			p->pfra_ip6addr.s6_addr16[1] = 0;
5326adffbf9Sitojun 	}
5336adffbf9Sitojun 	/* mask network address bits */
5346adffbf9Sitojun 	if (net < 128)
5356adffbf9Sitojun 		((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
5366adffbf9Sitojun 	for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
5376adffbf9Sitojun 		((caddr_t)p)[i] = 0;
5386adffbf9Sitojun }
5396adffbf9Sitojun 
5406adffbf9Sitojun void
5416adffbf9Sitojun pfi_dynaddr_remove(struct pf_addr_wrap *aw)
5426adffbf9Sitojun {
5436adffbf9Sitojun 	int	s;
5446adffbf9Sitojun 
5456adffbf9Sitojun 	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
5466adffbf9Sitojun 	    aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
5476adffbf9Sitojun 		return;
5486adffbf9Sitojun 
5496adffbf9Sitojun 	s = splsoftnet();
5506adffbf9Sitojun 	hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
5516adffbf9Sitojun 	    aw->p.dyn->pfid_hook_cookie);
5526adffbf9Sitojun 	pfi_detach_rule(aw->p.dyn->pfid_kif);
5536adffbf9Sitojun 	aw->p.dyn->pfid_kif = NULL;
5546adffbf9Sitojun 	pfr_detach_table(aw->p.dyn->pfid_kt);
5556adffbf9Sitojun 	aw->p.dyn->pfid_kt = NULL;
5566adffbf9Sitojun 	pool_put(&pfi_addr_pl, aw->p.dyn);
5576adffbf9Sitojun 	aw->p.dyn = NULL;
5586adffbf9Sitojun 	splx(s);
5596adffbf9Sitojun }
5606adffbf9Sitojun 
5616adffbf9Sitojun void
5626adffbf9Sitojun pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
5636adffbf9Sitojun {
5646adffbf9Sitojun 	if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
5656adffbf9Sitojun 	    aw->p.dyn->pfid_kif == NULL)
5666adffbf9Sitojun 		return;
5676adffbf9Sitojun 	aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
5686adffbf9Sitojun }
5696adffbf9Sitojun 
5706adffbf9Sitojun void
5716adffbf9Sitojun pfi_kifaddr_update(void *v)
5726adffbf9Sitojun {
5736adffbf9Sitojun 	int		 s;
5746adffbf9Sitojun 
5756adffbf9Sitojun 	s = splsoftnet();
5766adffbf9Sitojun 	pfi_update++;
5776adffbf9Sitojun 	pfi_dohooks(v);
5786adffbf9Sitojun 	splx(s);
5796adffbf9Sitojun }
5806adffbf9Sitojun 
58146abcaebSyamt #ifdef __NetBSD__
58246abcaebSyamt void
58346abcaebSyamt pfi_kifaddr_update_if(struct ifnet *ifp)
58446abcaebSyamt {
58546abcaebSyamt 	struct pfi_kif *p;
58646abcaebSyamt 
58746abcaebSyamt 	p = pfi_lookup_if(ifp->if_xname);
58846abcaebSyamt 	if (p == NULL)
58946abcaebSyamt 		panic("can't find interface");
59046abcaebSyamt 	pfi_kifaddr_update(p);
59146abcaebSyamt }
59246abcaebSyamt #endif
59346abcaebSyamt 
5946adffbf9Sitojun int
5956adffbf9Sitojun pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
5966adffbf9Sitojun {
5976adffbf9Sitojun 	return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
5986adffbf9Sitojun }
5996adffbf9Sitojun 
6006adffbf9Sitojun struct pfi_kif *
6016adffbf9Sitojun pfi_if_create(const char *name, struct pfi_kif *q, int flags)
6026adffbf9Sitojun {
6036adffbf9Sitojun 	struct pfi_kif *p;
6046adffbf9Sitojun 
6056adffbf9Sitojun 	p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
6066adffbf9Sitojun 	if (p == NULL)
6076adffbf9Sitojun 		return (NULL);
6086adffbf9Sitojun 	bzero(p, sizeof(*p));
6096adffbf9Sitojun 	p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
6106adffbf9Sitojun 	    M_DONTWAIT);
6116adffbf9Sitojun 	if (p->pfik_ah_head == NULL) {
6126adffbf9Sitojun 		free(p, PFI_MTYPE);
6136adffbf9Sitojun 		return (NULL);
6146adffbf9Sitojun 	}
6156adffbf9Sitojun 	bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
6166adffbf9Sitojun 	TAILQ_INIT(p->pfik_ah_head);
6176adffbf9Sitojun 	TAILQ_INIT(&p->pfik_grouphead);
618bfcdaa57Sitojun #ifdef __NetBSD__
6190a7a28fcSyamt 	bzero(&p->pfik_ifaddrhooks, sizeof(p->pfik_ifaddrhooks));
6200a7a28fcSyamt 	TAILQ_INIT(&p->pfik_ifaddrhooks);
621bfcdaa57Sitojun #endif
6226adffbf9Sitojun 	strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
6236adffbf9Sitojun 	RB_INIT(&p->pfik_lan_ext);
6246adffbf9Sitojun 	RB_INIT(&p->pfik_ext_gwy);
6256adffbf9Sitojun 	p->pfik_flags = flags;
6266adffbf9Sitojun 	p->pfik_parent = q;
627da186141Syamt 	p->pfik_tzero = time_second;
6286adffbf9Sitojun 
6296adffbf9Sitojun 	RB_INSERT(pfi_ifhead, &pfi_ifs, p);
6306adffbf9Sitojun 	if (q != NULL) {
6316adffbf9Sitojun 		q->pfik_addcnt++;
6326adffbf9Sitojun 		TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
6336adffbf9Sitojun 	}
6346adffbf9Sitojun 	pfi_ifcnt++;
6356adffbf9Sitojun 	return (p);
6366adffbf9Sitojun }
6376adffbf9Sitojun 
6386adffbf9Sitojun int
6396adffbf9Sitojun pfi_maybe_destroy(struct pfi_kif *p)
6406adffbf9Sitojun {
6416adffbf9Sitojun 	int		 i, j, k, s;
6426adffbf9Sitojun 	struct pfi_kif	*q = p->pfik_parent;
6436adffbf9Sitojun 
6446adffbf9Sitojun 	if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
6456adffbf9Sitojun 	    p->pfik_rules > 0 || p->pfik_states > 0)
6466adffbf9Sitojun 		return (0);
6476adffbf9Sitojun 
6486adffbf9Sitojun 	s = splsoftnet();
6496adffbf9Sitojun 	if (q != NULL) {
6506adffbf9Sitojun 		for (i = 0; i < 2; i++)
6516adffbf9Sitojun 			for (j = 0; j < 2; j++)
6526adffbf9Sitojun 				for (k = 0; k < 2; k++) {
6536adffbf9Sitojun 					q->pfik_bytes[i][j][k] +=
6546adffbf9Sitojun 					    p->pfik_bytes[i][j][k];
6556adffbf9Sitojun 					q->pfik_packets[i][j][k] +=
6566adffbf9Sitojun 					    p->pfik_packets[i][j][k];
6576adffbf9Sitojun 				}
6586adffbf9Sitojun 		q->pfik_delcnt++;
6596adffbf9Sitojun 		TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
6606adffbf9Sitojun 	}
6616adffbf9Sitojun 	pfi_ifcnt--;
6626adffbf9Sitojun 	RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
6636adffbf9Sitojun 	splx(s);
6646adffbf9Sitojun 
6656adffbf9Sitojun 	free(p->pfik_ah_head, PFI_MTYPE);
6666adffbf9Sitojun 	free(p, PFI_MTYPE);
6676adffbf9Sitojun 	return (1);
6686adffbf9Sitojun }
6696adffbf9Sitojun 
6706adffbf9Sitojun void
6716adffbf9Sitojun pfi_copy_group(char *p, const char *q, int m)
6726adffbf9Sitojun {
6736adffbf9Sitojun 	while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
6746adffbf9Sitojun 		*p++ = *q++;
6756adffbf9Sitojun 		m--;
6766adffbf9Sitojun 	}
6776adffbf9Sitojun 	if (m > 0)
6786adffbf9Sitojun 		*p++ = '\0';
6796adffbf9Sitojun }
6806adffbf9Sitojun 
6816adffbf9Sitojun void
6826adffbf9Sitojun pfi_newgroup(const char *name, int flags)
6836adffbf9Sitojun {
6846adffbf9Sitojun 	struct pfi_kif	*p;
6856adffbf9Sitojun 
6866adffbf9Sitojun 	p = pfi_lookup_if(name);
6876adffbf9Sitojun 	if (p == NULL)
6886adffbf9Sitojun 		p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
6896adffbf9Sitojun 	if (p == NULL) {
6906adffbf9Sitojun 		printf("pfi_newgroup: cannot allocate '%s' group", name);
6916adffbf9Sitojun 		return;
6926adffbf9Sitojun 	}
6936adffbf9Sitojun 	p->pfik_flags |= flags;
6946adffbf9Sitojun }
6956adffbf9Sitojun 
6966adffbf9Sitojun void
6976adffbf9Sitojun pfi_fill_oldstatus(struct pf_status *pfs)
6986adffbf9Sitojun {
6996adffbf9Sitojun 	struct pfi_kif	*p, key;
7006adffbf9Sitojun 	int		 i, j, k, s;
7016adffbf9Sitojun 
7026adffbf9Sitojun 	strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
7036adffbf9Sitojun 	s = splsoftnet();
7046adffbf9Sitojun 	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
7056adffbf9Sitojun 	if (p == NULL) {
7066adffbf9Sitojun 		splx(s);
7076adffbf9Sitojun 		return;
7086adffbf9Sitojun 	}
7096adffbf9Sitojun 	bzero(pfs->pcounters, sizeof(pfs->pcounters));
7106adffbf9Sitojun 	bzero(pfs->bcounters, sizeof(pfs->bcounters));
7116adffbf9Sitojun 	for (i = 0; i < 2; i++)
7126adffbf9Sitojun 		for (j = 0; j < 2; j++)
7136adffbf9Sitojun 			for (k = 0; k < 2; k++) {
7146adffbf9Sitojun 				pfs->pcounters[i][j][k] =
7156adffbf9Sitojun 					p->pfik_packets[i][j][k];
7166adffbf9Sitojun 				pfs->bcounters[i][j] +=
7176adffbf9Sitojun 					p->pfik_bytes[i][j][k];
7186adffbf9Sitojun 			}
7196adffbf9Sitojun 	splx(s);
7206adffbf9Sitojun }
7216adffbf9Sitojun 
7226adffbf9Sitojun int
7236adffbf9Sitojun pfi_clr_istats(const char *name, int *nzero, int flags)
7246adffbf9Sitojun {
7256adffbf9Sitojun 	struct pfi_kif	*p;
7266adffbf9Sitojun 	int		 n = 0, s;
727da186141Syamt 	long		 tzero = time_second;
7286adffbf9Sitojun 
7296adffbf9Sitojun 	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
730*97107414Speter 	s = splsoftnet();
7316adffbf9Sitojun 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
7326adffbf9Sitojun 		if (pfi_skip_if(name, p, flags))
7336adffbf9Sitojun 			continue;
7346adffbf9Sitojun 		bzero(p->pfik_packets, sizeof(p->pfik_packets));
7356adffbf9Sitojun 		bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
7366adffbf9Sitojun 		p->pfik_tzero = tzero;
7376adffbf9Sitojun 		n++;
7386adffbf9Sitojun 	}
7396adffbf9Sitojun 	splx(s);
7406adffbf9Sitojun 	if (nzero != NULL)
7416adffbf9Sitojun 		*nzero = n;
7426adffbf9Sitojun 	return (0);
7436adffbf9Sitojun }
7446adffbf9Sitojun 
7456adffbf9Sitojun int
746*97107414Speter pfi_set_flags(const char *name, int flags)
747*97107414Speter {
748*97107414Speter 	struct pfi_kif	*p;
749*97107414Speter 	int		 s;
750*97107414Speter 
751*97107414Speter 	if (flags & ~PFI_IFLAG_SETABLE_MASK)
752*97107414Speter 		return (EINVAL);
753*97107414Speter 
754*97107414Speter 	s = splsoftnet();
755*97107414Speter 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
756*97107414Speter 		if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
757*97107414Speter 			continue;
758*97107414Speter 		p->pfik_flags |= flags;
759*97107414Speter 	}
760*97107414Speter 	splx(s);
761*97107414Speter 	return (0);
762*97107414Speter }
763*97107414Speter 
764*97107414Speter int
765*97107414Speter pfi_clear_flags(const char *name, int flags)
766*97107414Speter {
767*97107414Speter 	struct pfi_kif	*p;
768*97107414Speter 	int		 s;
769*97107414Speter 
770*97107414Speter 	if (flags & ~PFI_IFLAG_SETABLE_MASK)
771*97107414Speter 		return (EINVAL);
772*97107414Speter 
773*97107414Speter 	s = splsoftnet();
774*97107414Speter 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
775*97107414Speter 		if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
776*97107414Speter 			continue;
777*97107414Speter 		p->pfik_flags &= ~flags;
778*97107414Speter 	}
779*97107414Speter 	splx(s);
780*97107414Speter 	return (0);
781*97107414Speter }
782*97107414Speter 
783*97107414Speter int
7846adffbf9Sitojun pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
7856adffbf9Sitojun {
7866adffbf9Sitojun 	struct pfi_kif	*p;
7876adffbf9Sitojun 	int		 s, n = 0;
7886adffbf9Sitojun 
7896adffbf9Sitojun 	ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
7906adffbf9Sitojun 	s = splsoftnet();
7916adffbf9Sitojun 	RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
7926adffbf9Sitojun 		if (pfi_skip_if(name, p, flags))
7936adffbf9Sitojun 			continue;
7946adffbf9Sitojun 		if (*size > n++) {
7956adffbf9Sitojun 			if (!p->pfik_tzero)
796da186141Syamt 				p->pfik_tzero = time_second;
7976adffbf9Sitojun 			if (copyout(p, buf++, sizeof(*buf))) {
7986adffbf9Sitojun 				splx(s);
7996adffbf9Sitojun 				return (EFAULT);
8006adffbf9Sitojun 			}
8016adffbf9Sitojun 		}
8026adffbf9Sitojun 	}
8036adffbf9Sitojun 	splx(s);
8046adffbf9Sitojun 	*size = n;
8056adffbf9Sitojun 	return (0);
8066adffbf9Sitojun }
8076adffbf9Sitojun 
8086adffbf9Sitojun struct pfi_kif *
8096adffbf9Sitojun pfi_lookup_if(const char *name)
8106adffbf9Sitojun {
8116adffbf9Sitojun 	struct pfi_kif	*p, key;
8126adffbf9Sitojun 
8136adffbf9Sitojun 	strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
8146adffbf9Sitojun 	p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
8156adffbf9Sitojun 	return (p);
8166adffbf9Sitojun }
8176adffbf9Sitojun 
8186adffbf9Sitojun int
8196adffbf9Sitojun pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
8206adffbf9Sitojun {
8216adffbf9Sitojun 	int	n;
8226adffbf9Sitojun 
8236adffbf9Sitojun 	if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
8246adffbf9Sitojun 		return (1);
8256adffbf9Sitojun 	if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
8266adffbf9Sitojun 		return (1);
8276adffbf9Sitojun 	if (filter == NULL || !*filter)
8286adffbf9Sitojun 		return (0);
8296adffbf9Sitojun 	if (!strcmp(p->pfik_name, filter))
8306adffbf9Sitojun 		return (0);	/* exact match */
8316adffbf9Sitojun 	n = strlen(filter);
8326adffbf9Sitojun 	if (n < 1 || n >= IFNAMSIZ)
8336adffbf9Sitojun 		return (1);	/* sanity check */
8346adffbf9Sitojun 	if (filter[n-1] >= '0' && filter[n-1] <= '9')
8356adffbf9Sitojun 		return (1);	/* only do exact match in that case */
8366adffbf9Sitojun 	if (strncmp(p->pfik_name, filter, n))
8376adffbf9Sitojun 		return (1);	/* prefix doesn't match */
8386adffbf9Sitojun 	return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
8396adffbf9Sitojun }
8406adffbf9Sitojun 
8416adffbf9Sitojun /* from pf_print_state.c */
8426adffbf9Sitojun int
8436adffbf9Sitojun pfi_unmask(void *addr)
8446adffbf9Sitojun {
8456adffbf9Sitojun 	struct pf_addr *m = addr;
8466adffbf9Sitojun 	int i = 31, j = 0, b = 0;
8476adffbf9Sitojun 	u_int32_t tmp;
8486adffbf9Sitojun 
8496adffbf9Sitojun 	while (j < 4 && m->addr32[j] == 0xffffffff) {
8506adffbf9Sitojun 		b += 32;
8516adffbf9Sitojun 		j++;
8526adffbf9Sitojun 	}
8536adffbf9Sitojun 	if (j < 4) {
8546adffbf9Sitojun 		tmp = ntohl(m->addr32[j]);
8556adffbf9Sitojun 		for (i = 31; tmp & (1 << i); --i)
8566adffbf9Sitojun 			b++;
8576adffbf9Sitojun 	}
8586adffbf9Sitojun 	return (b);
8596adffbf9Sitojun }
8606adffbf9Sitojun 
8616adffbf9Sitojun void
8626adffbf9Sitojun pfi_dohooks(struct pfi_kif *p)
8636adffbf9Sitojun {
8646adffbf9Sitojun 	for (; p != NULL; p = p->pfik_parent)
8656adffbf9Sitojun 		dohooks(p->pfik_ah_head, 0);
8666adffbf9Sitojun }
8676adffbf9Sitojun 
8686adffbf9Sitojun int
8696adffbf9Sitojun pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
8706adffbf9Sitojun {
871da186141Syamt 	switch (af) {
872da186141Syamt #ifdef INET
873da186141Syamt 	case AF_INET:
8746adffbf9Sitojun 		switch (dyn->pfid_acnt4) {
8756adffbf9Sitojun 		case 0:
8766adffbf9Sitojun 			return (0);
8776adffbf9Sitojun 		case 1:
8786adffbf9Sitojun 			return (PF_MATCHA(0, &dyn->pfid_addr4,
8796adffbf9Sitojun 			    &dyn->pfid_mask4, a, AF_INET));
8806adffbf9Sitojun 		default:
8816adffbf9Sitojun 			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
8826adffbf9Sitojun 		}
883da186141Syamt 		break;
884da186141Syamt #endif /* INET */
885da186141Syamt #ifdef INET6
886da186141Syamt 	case AF_INET6:
8876adffbf9Sitojun 		switch (dyn->pfid_acnt6) {
8886adffbf9Sitojun 		case 0:
8896adffbf9Sitojun 			return (0);
8906adffbf9Sitojun 		case 1:
8916adffbf9Sitojun 			return (PF_MATCHA(0, &dyn->pfid_addr6,
8926adffbf9Sitojun 			    &dyn->pfid_mask6, a, AF_INET6));
8936adffbf9Sitojun 		default:
8946adffbf9Sitojun 			return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
8956adffbf9Sitojun 		}
896da186141Syamt 		break;
897da186141Syamt #endif /* INET6 */
898da186141Syamt 	default:
899da186141Syamt 		return (0);
9006adffbf9Sitojun 	}
9016adffbf9Sitojun }
902bfcdaa57Sitojun 
903bfcdaa57Sitojun /* from openbsd/sys/kern/kern_subr.c */
904bfcdaa57Sitojun #ifdef __NetBSD__
905bfcdaa57Sitojun static void *
9064f755d07Syamt hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
9074f755d07Syamt     void *arg)
908bfcdaa57Sitojun {
909bfcdaa57Sitojun 	struct hook_desc *hdp;
910bfcdaa57Sitojun 
911bfcdaa57Sitojun 	hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
912bfcdaa57Sitojun 	if (hdp == NULL)
913bfcdaa57Sitojun 		return (NULL);
914bfcdaa57Sitojun 
915bfcdaa57Sitojun 	hdp->hd_fn = fn;
916bfcdaa57Sitojun 	hdp->hd_arg = arg;
917bfcdaa57Sitojun 	if (tail)
918bfcdaa57Sitojun 		TAILQ_INSERT_TAIL(head, hdp, hd_list);
919bfcdaa57Sitojun 	else
920bfcdaa57Sitojun 		TAILQ_INSERT_HEAD(head, hdp, hd_list);
921bfcdaa57Sitojun 
922bfcdaa57Sitojun 	return (hdp);
923bfcdaa57Sitojun }
924bfcdaa57Sitojun 
925bfcdaa57Sitojun static void
9264f755d07Syamt hook_disestablish(struct hook_desc_head *head, void *vhook)
927bfcdaa57Sitojun {
928bfcdaa57Sitojun 	struct hook_desc *hdp;
929bfcdaa57Sitojun 
930bfcdaa57Sitojun #ifdef DIAGNOSTIC
931bfcdaa57Sitojun 	for (hdp = TAILQ_FIRST(head); hdp != NULL;
932bfcdaa57Sitojun 	    hdp = TAILQ_NEXT(hdp, hd_list))
933bfcdaa57Sitojun                 if (hdp == vhook)
934bfcdaa57Sitojun 			break;
935bfcdaa57Sitojun 	if (hdp == NULL)
936bfcdaa57Sitojun 		panic("hook_disestablish: hook not established");
937bfcdaa57Sitojun #endif
938bfcdaa57Sitojun 	hdp = vhook;
939bfcdaa57Sitojun 	TAILQ_REMOVE(head, hdp, hd_list);
940bfcdaa57Sitojun 	free(hdp, M_DEVBUF);
941bfcdaa57Sitojun }
94246abcaebSyamt 
94346abcaebSyamt static void
94446abcaebSyamt dohooks(struct hook_desc_head *head, int flags)
94546abcaebSyamt {
94646abcaebSyamt 	struct hook_desc *hdp;
94746abcaebSyamt 
94846abcaebSyamt 	if ((flags & HOOK_REMOVE) == 0) {
94946abcaebSyamt 		TAILQ_FOREACH(hdp, head, hd_list) {
95046abcaebSyamt 			(*hdp->hd_fn)(hdp->hd_arg);
95146abcaebSyamt 		}
95246abcaebSyamt 	} else {
95346abcaebSyamt 		while ((hdp = TAILQ_FIRST(head)) != NULL) {
95446abcaebSyamt 			TAILQ_REMOVE(head, hdp, hd_list);
95546abcaebSyamt 			(*hdp->hd_fn)(hdp->hd_arg);
95646abcaebSyamt 			if ((flags & HOOK_FREE) != 0)
95746abcaebSyamt 				free(hdp, M_DEVBUF);
95846abcaebSyamt 		}
95946abcaebSyamt 	}
96046abcaebSyamt }
961bfcdaa57Sitojun #endif
962