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