pf_if.c revision 137159
1130613Smlaier/* $FreeBSD: head/sys/contrib/pf/net/pf_if.c 137159 2004-11-03 17:21:12Z mlaier $ */ 2130610Smlaier/* $OpenBSD: pf_if.c,v 1.11 2004/03/15 11:38:23 cedric Exp $ */ 3133573Smlaier/* add $OpenBSD: pf_if.c,v 1.19 2004/08/11 12:06:44 henning Exp $ */ 4130610Smlaier 5130610Smlaier/* 6130610Smlaier * Copyright (c) 2001 Daniel Hartmeier 7130610Smlaier * Copyright (c) 2003 Cedric Berger 8130610Smlaier * All rights reserved. 9130610Smlaier * 10130610Smlaier * Redistribution and use in source and binary forms, with or without 11130610Smlaier * modification, are permitted provided that the following conditions 12130610Smlaier * are met: 13130610Smlaier * 14130610Smlaier * - Redistributions of source code must retain the above copyright 15130610Smlaier * notice, this list of conditions and the following disclaimer. 16130610Smlaier * - Redistributions in binary form must reproduce the above 17130610Smlaier * copyright notice, this list of conditions and the following 18130610Smlaier * disclaimer in the documentation and/or other materials provided 19130610Smlaier * with the distribution. 20130610Smlaier * 21130610Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22130610Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23130610Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24130610Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25130610Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26130610Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27130610Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28130610Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29130610Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30130610Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31130610Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32130610Smlaier * POSSIBILITY OF SUCH DAMAGE. 33130610Smlaier */ 34130610Smlaier 35130613Smlaier#if defined(__FreeBSD__) 36130613Smlaier#include "opt_inet.h" 37130613Smlaier#include "opt_inet6.h" 38130613Smlaier#endif 39130613Smlaier 40130610Smlaier#include <sys/param.h> 41130610Smlaier#include <sys/systm.h> 42130613Smlaier#ifdef __FreeBSD__ 43130613Smlaier#include <sys/malloc.h> 44130613Smlaier#endif 45130610Smlaier#include <sys/mbuf.h> 46130610Smlaier#include <sys/filio.h> 47130610Smlaier#include <sys/socket.h> 48130610Smlaier#include <sys/socketvar.h> 49130610Smlaier#include <sys/kernel.h> 50130613Smlaier#ifndef __FreeBSD__ 51130610Smlaier#include <sys/device.h> 52130613Smlaier#endif 53130610Smlaier#include <sys/time.h> 54130610Smlaier 55130610Smlaier#include <net/if.h> 56130610Smlaier#include <net/if_types.h> 57133573Smlaier#include <net/route.h> 58130610Smlaier 59130610Smlaier#include <netinet/in.h> 60130610Smlaier#include <netinet/in_var.h> 61130610Smlaier#include <netinet/in_systm.h> 62130610Smlaier#include <netinet/ip.h> 63130610Smlaier#include <netinet/ip_var.h> 64130610Smlaier 65130610Smlaier#include <net/pfvar.h> 66130610Smlaier 67130610Smlaier#ifdef INET6 68130610Smlaier#include <netinet/ip6.h> 69130610Smlaier#endif /* INET6 */ 70130610Smlaier 71130610Smlaier#define ACCEPT_FLAGS(oklist) \ 72130610Smlaier do { \ 73130610Smlaier if ((flags & ~(oklist)) & \ 74130610Smlaier PFI_FLAG_ALLMASK) \ 75130610Smlaier return (EINVAL); \ 76130610Smlaier } while (0) 77130610Smlaier 78130610Smlaier#define senderr(e) do { rv = (e); goto _bad; } while (0) 79130610Smlaier 80130610Smlaierstruct pfi_kif **pfi_index2kif; 81130613Smlaierstruct pfi_kif *pfi_self, *pfi_dummy; 82130610Smlaierint pfi_indexlim; 83130610Smlaierstruct pfi_ifhead pfi_ifs; 84130610Smlaierstruct pfi_statehead pfi_statehead; 85130610Smlaierint pfi_ifcnt; 86130613Smlaier#ifdef __FreeBSD__ 87130613Smlaieruma_zone_t pfi_addr_pl; 88130613Smlaier#else 89130610Smlaierstruct pool pfi_addr_pl; 90130613Smlaier#endif 91130610Smlaierlong pfi_update = 1; 92130610Smlaierstruct pfr_addr *pfi_buffer; 93130610Smlaierint pfi_buffer_cnt; 94130610Smlaierint pfi_buffer_max; 95130610Smlaierchar pfi_reserved_anchor[PF_ANCHOR_NAME_SIZE] = 96130610Smlaier PF_RESERVED_ANCHOR; 97130610Smlaierchar pfi_interface_ruleset[PF_RULESET_NAME_SIZE] = 98130610Smlaier PF_INTERFACE_RULESET; 99130613Smlaier#ifdef __FreeBSD__ 100130613Smlaiereventhandler_tag pfi_clone_cookie = NULL; 101130613Smlaiereventhandler_tag pfi_attach_cookie = NULL; 102130613Smlaiereventhandler_tag pfi_detach_cookie = NULL; 103130613Smlaier#endif 104130610Smlaier 105130610Smlaiervoid pfi_dynaddr_update(void *); 106130610Smlaiervoid pfi_kifaddr_update(void *); 107130610Smlaiervoid pfi_table_update(struct pfr_ktable *, struct pfi_kif *, 108130610Smlaier int, int); 109130610Smlaiervoid pfi_instance_add(struct ifnet *, int, int); 110130610Smlaiervoid pfi_address_add(struct sockaddr *, int, int); 111130610Smlaierint pfi_if_compare(struct pfi_kif *, struct pfi_kif *); 112130610Smlaierstruct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int); 113130610Smlaiervoid pfi_copy_group(char *, const char *, int); 114130610Smlaiervoid pfi_dynamic_drivers(void); 115130610Smlaiervoid pfi_newgroup(const char *, int); 116130610Smlaierint pfi_skip_if(const char *, struct pfi_kif *, int); 117130610Smlaierint pfi_unmask(void *); 118130610Smlaiervoid pfi_dohooks(struct pfi_kif *); 119130613Smlaier#ifdef __FreeBSD__ 120130613Smlaiervoid pfi_kifaddr_update_event(void *, struct ifnet *); 121130613Smlaiervoid pfi_attach_clone_event(void * __unused, struct if_clone *); 122130613Smlaiervoid pfi_attach_ifnet_event(void * __unused, struct ifnet *); 123130613Smlaiervoid pfi_detach_ifnet_event(void * __unused, struct ifnet *); 124130613Smlaier#endif 125130610Smlaier 126130610SmlaierRB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 127130610SmlaierRB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); 128130610Smlaier 129130610Smlaier#define PFI_DYNAMIC_BUSES { "pcmcia", "cardbus", "uhub" } 130130610Smlaier#define PFI_BUFFER_MAX 0x10000 131130613Smlaier#ifdef __FreeBSD__ 132130613SmlaierMALLOC_DEFINE(PFI_MTYPE, "pf_if", "pf interface table"); 133130613Smlaier#else 134130610Smlaier#define PFI_MTYPE M_IFADDR 135130613Smlaier#endif 136130610Smlaier 137130610Smlaiervoid 138130610Smlaierpfi_initialize(void) 139130610Smlaier{ 140130613Smlaier#ifdef __FreeBSD__ 141130613Smlaier struct ifnet *ifp; 142130613Smlaier#endif 143130613Smlaier 144130610Smlaier if (pfi_self != NULL) /* already initialized */ 145130610Smlaier return; 146130610Smlaier 147130610Smlaier TAILQ_INIT(&pfi_statehead); 148130613Smlaier#ifndef __FreeBSD__ 149130610Smlaier pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, 150130610Smlaier "pfiaddrpl", &pool_allocator_nointr); 151130613Smlaier#endif 152130610Smlaier pfi_buffer_max = 64; 153130610Smlaier pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), 154130610Smlaier PFI_MTYPE, M_WAITOK); 155130610Smlaier pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP); 156130610Smlaier pfi_dynamic_drivers(); 157130613Smlaier#ifdef __FreeBSD__ 158130613Smlaier PF_LOCK(); 159130613Smlaier IFNET_RLOCK(); 160137159Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) { 161137159Smlaier IFNET_RUNLOCK(); 162137159Smlaier pfi_attach_ifnet(ifp); 163137159Smlaier IFNET_RLOCK(); 164137159Smlaier } 165130613Smlaier IFNET_RUNLOCK(); 166130613Smlaier PF_UNLOCK(); 167130613Smlaier pfi_dummy = pfi_if_create("notyet", pfi_self, 168130613Smlaier PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 169130613Smlaier pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, 170130613Smlaier pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 171130613Smlaier pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 172130613Smlaier pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 173130613Smlaier pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event, 174130613Smlaier pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY); 175130613Smlaier#endif 176130610Smlaier} 177130610Smlaier 178130613Smlaier#ifdef __FreeBSD__ 179130610Smlaiervoid 180130613Smlaierpfi_cleanup(void) 181130613Smlaier{ 182130613Smlaier struct pfi_kif *p, key; 183130613Smlaier struct ifnet *ifp; 184130613Smlaier 185130613Smlaier PF_ASSERT(MA_OWNED); 186132567Smlaier 187130613Smlaier PF_UNLOCK(); 188130613Smlaier EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); 189130613Smlaier EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); 190130613Smlaier EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie); 191132567Smlaier PF_LOCK(); 192130613Smlaier 193130613Smlaier IFNET_RLOCK(); 194130613Smlaier /* release PFI_IFLAG_INSTANCE */ 195130613Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) { 196130613Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 197130613Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 198130613Smlaier if (p != NULL) { 199132567Smlaier IFNET_RUNLOCK(); 200130613Smlaier pfi_detach_ifnet(ifp); 201132567Smlaier IFNET_RLOCK(); 202130613Smlaier } 203130613Smlaier } 204130613Smlaier IFNET_RUNLOCK(); 205130613Smlaier 206130613Smlaier /* XXX clear all other interface group */ 207130613Smlaier while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { 208130613Smlaier RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 209130613Smlaier 210130613Smlaier free(p->pfik_ah_head, PFI_MTYPE); 211130613Smlaier free(p, PFI_MTYPE); 212130613Smlaier } 213130613Smlaier free(pfi_index2kif, PFI_MTYPE); 214130613Smlaier free(pfi_buffer, PFI_MTYPE); 215130613Smlaier pfi_index2kif = NULL; 216130613Smlaier pfi_buffer = NULL; 217130613Smlaier pfi_self = NULL; 218130613Smlaier} 219130613Smlaier 220130613Smlaier/* 221130613Smlaier * Wrapper functions for FreeBSD eventhandler 222130613Smlaier */ 223130613Smlaiervoid 224130613Smlaierpfi_kifaddr_update_event(void *arg, struct ifnet *ifp) 225130613Smlaier{ 226130613Smlaier struct pfi_kif *p = arg; 227130613Smlaier 228130613Smlaier PF_LOCK(); 229130613Smlaier /* 230130613Smlaier * Check to see if it is 'our' interface as we do not have per 231130613Smlaier * interface hooks and thus get an update for every interface. 232130613Smlaier */ 233130613Smlaier if (p && p->pfik_ifp == ifp) 234130613Smlaier pfi_kifaddr_update(p); 235130613Smlaier PF_UNLOCK(); 236130613Smlaier} 237130613Smlaier 238130613Smlaiervoid 239130613Smlaierpfi_attach_clone_event(void *arg __unused, struct if_clone *ifc) 240130613Smlaier{ 241130613Smlaier PF_LOCK(); 242130613Smlaier pfi_attach_clone(ifc); 243130613Smlaier PF_UNLOCK(); 244130613Smlaier} 245130613Smlaier 246130613Smlaiervoid 247130613Smlaierpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) 248130613Smlaier{ 249130613Smlaier PF_LOCK(); 250137159Smlaier pfi_attach_ifnet(ifp); 251130613Smlaier PF_UNLOCK(); 252130613Smlaier} 253130613Smlaier 254130613Smlaiervoid 255130613Smlaierpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) 256130613Smlaier{ 257130613Smlaier PF_LOCK(); 258130613Smlaier pfi_detach_ifnet(ifp); 259130613Smlaier PF_UNLOCK(); 260130613Smlaier} 261130613Smlaier#endif /* __FreeBSD__ */ 262130613Smlaier 263130613Smlaiervoid 264130610Smlaierpfi_attach_clone(struct if_clone *ifc) 265130610Smlaier{ 266130610Smlaier pfi_initialize(); 267130610Smlaier pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE); 268130610Smlaier} 269130610Smlaier 270130610Smlaiervoid 271130610Smlaierpfi_attach_ifnet(struct ifnet *ifp) 272130610Smlaier{ 273130610Smlaier struct pfi_kif *p, *q, key; 274130610Smlaier int s; 275130613Smlaier#ifdef __FreeBSD__ 276130613Smlaier int realname; 277130613Smlaier#endif 278130610Smlaier 279130610Smlaier pfi_initialize(); 280130610Smlaier s = splsoftnet(); 281130610Smlaier pfi_update++; 282130610Smlaier if (ifp->if_index >= pfi_indexlim) { 283130610Smlaier /* 284130610Smlaier * grow pfi_index2kif, similar to ifindex2ifnet code in if.c 285130610Smlaier */ 286130610Smlaier size_t m, n, oldlim; 287130610Smlaier struct pfi_kif **mp, **np; 288130610Smlaier 289130610Smlaier oldlim = pfi_indexlim; 290130610Smlaier if (pfi_indexlim == 0) 291130610Smlaier pfi_indexlim = 64; 292130610Smlaier while (ifp->if_index >= pfi_indexlim) 293130610Smlaier pfi_indexlim <<= 1; 294130610Smlaier 295130610Smlaier m = oldlim * sizeof(struct pfi_kif *); 296130610Smlaier mp = pfi_index2kif; 297130610Smlaier n = pfi_indexlim * sizeof(struct pfi_kif *); 298130613Smlaier#ifdef __FreeBSD__ 299130613Smlaier np = malloc(n, PFI_MTYPE, M_NOWAIT); 300130613Smlaier#else 301130610Smlaier np = malloc(n, PFI_MTYPE, M_DONTWAIT); 302130613Smlaier#endif 303130610Smlaier if (np == NULL) 304130610Smlaier panic("pfi_attach_ifnet: " 305130610Smlaier "cannot allocate translation table"); 306130610Smlaier bzero(np, n); 307130610Smlaier if (mp != NULL) 308130610Smlaier bcopy(mp, np, m); 309130610Smlaier pfi_index2kif = np; 310130610Smlaier if (mp != NULL) 311130610Smlaier free(mp, PFI_MTYPE); 312130610Smlaier } 313130610Smlaier 314130610Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 315130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 316130613Smlaier#ifdef __FreeBSD__ 317130613Smlaier /* some additional trickery for placeholders */ 318130613Smlaier if ((p == NULL) || (p->pfik_parent == pfi_dummy)) { 319130613Smlaier /* are we looking at a renamed instance or not? */ 320130613Smlaier pfi_copy_group(key.pfik_name, ifp->if_xname, 321130613Smlaier sizeof(key.pfik_name)); 322130613Smlaier realname = (strncmp(key.pfik_name, ifp->if_dname, 323130613Smlaier sizeof(key.pfik_name)) == 0); 324130613Smlaier /* add group */ 325130613Smlaier /* we can change if_xname, hence use if_dname as group id */ 326130613Smlaier pfi_copy_group(key.pfik_name, ifp->if_dname, 327130613Smlaier sizeof(key.pfik_name)); 328130613Smlaier q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 329130613Smlaier if (q == NULL) 330130613Smlaier q = pfi_if_create(key.pfik_name, pfi_self, 331130613Smlaier PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC); 332130613Smlaier else if (q->pfik_parent == pfi_dummy) { 333130613Smlaier q->pfik_parent = pfi_self; 334130613Smlaier q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 335130613Smlaier } 336130613Smlaier if (q == NULL) 337130613Smlaier panic("pfi_attach_ifnet: " 338130613Smlaier "cannot allocate '%s' group", key.pfik_name); 339130613Smlaier 340130613Smlaier /* add/modify interface */ 341130613Smlaier if (p == NULL) 342137159Smlaier p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE | 343137159Smlaier (realname?0:PFI_IFLAG_PLACEHOLDER)); 344130613Smlaier else { 345130613Smlaier /* remove from the dummy group */ 346130613Smlaier /* XXX: copy stats? We should not have any!!! */ 347130613Smlaier pfi_dummy->pfik_delcnt++; 348130613Smlaier TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p, 349130613Smlaier pfik_instances); 350130613Smlaier /* move to the right group */ 351130613Smlaier p->pfik_parent = q; 352130613Smlaier q->pfik_addcnt++; 353130613Smlaier TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, 354130613Smlaier pfik_instances); 355137159Smlaier if (realname) 356130613Smlaier p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER; 357137159Smlaier p->pfik_flags |= PFI_IFLAG_INSTANCE; 358130613Smlaier } 359130613Smlaier if (p == NULL) 360130613Smlaier panic("pfi_attach_ifnet: " 361130613Smlaier "cannot allocate '%s' interface", ifp->if_xname); 362130613Smlaier#else 363130610Smlaier if (p == NULL) { 364130610Smlaier /* add group */ 365130610Smlaier pfi_copy_group(key.pfik_name, ifp->if_xname, 366130610Smlaier sizeof(key.pfik_name)); 367130610Smlaier q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 368130610Smlaier if (q == NULL) 369130610Smlaier q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP); 370130613Smlaier else if (q->pfik_parent == pfi_dummy) { 371130613Smlaier q->pfik_parent = pfi_self; 372130613Smlaier q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 373130613Smlaier } 374130610Smlaier if (q == NULL) 375130610Smlaier panic("pfi_attach_ifnet: " 376130610Smlaier "cannot allocate '%s' group", key.pfik_name); 377130610Smlaier 378130610Smlaier /* add interface */ 379130610Smlaier p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE); 380130610Smlaier if (p == NULL) 381130610Smlaier panic("pfi_attach_ifnet: " 382130610Smlaier "cannot allocate '%s' interface", ifp->if_xname); 383130613Smlaier#endif 384130610Smlaier } else 385130610Smlaier q = p->pfik_parent; 386130610Smlaier p->pfik_ifp = ifp; 387130610Smlaier p->pfik_flags |= PFI_IFLAG_ATTACHED; 388130613Smlaier#ifdef __FreeBSD__ 389130613Smlaier PF_UNLOCK(); 390130613Smlaier p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event, 391130613Smlaier pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY); 392130613Smlaier PF_LOCK(); 393130613Smlaier#else 394130610Smlaier p->pfik_ah_cookie = 395130610Smlaier hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p); 396130613Smlaier#endif 397130610Smlaier pfi_index2kif[ifp->if_index] = p; 398130610Smlaier pfi_dohooks(p); 399130610Smlaier splx(s); 400130610Smlaier} 401130610Smlaier 402130610Smlaiervoid 403130610Smlaierpfi_detach_ifnet(struct ifnet *ifp) 404130610Smlaier{ 405130610Smlaier struct pfi_kif *p, *q, key; 406130610Smlaier int s; 407130610Smlaier 408130610Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 409130610Smlaier 410130610Smlaier s = splsoftnet(); 411130610Smlaier pfi_update++; 412130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 413130610Smlaier if (p == NULL) { 414130610Smlaier printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname); 415130610Smlaier splx(s); 416130610Smlaier return; 417130610Smlaier } 418130613Smlaier#ifdef __FreeBSD__ 419130613Smlaier PF_UNLOCK(); 420130613Smlaier EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie); 421130613Smlaier PF_LOCK(); 422130613Smlaier#else 423130610Smlaier hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie); 424130613Smlaier#endif 425130610Smlaier q = p->pfik_parent; 426130610Smlaier p->pfik_ifp = NULL; 427130610Smlaier p->pfik_flags &= ~PFI_IFLAG_ATTACHED; 428130610Smlaier pfi_index2kif[ifp->if_index] = NULL; 429130610Smlaier pfi_dohooks(p); 430130610Smlaier pfi_maybe_destroy(p); 431130610Smlaier splx(s); 432130610Smlaier} 433130610Smlaier 434130610Smlaierstruct pfi_kif * 435130610Smlaierpfi_lookup_create(const char *name) 436130610Smlaier{ 437130610Smlaier struct pfi_kif *p, *q, key; 438130610Smlaier int s; 439130610Smlaier 440130610Smlaier s = splsoftnet(); 441130610Smlaier p = pfi_lookup_if(name); 442130610Smlaier if (p == NULL) { 443130610Smlaier pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name)); 444130610Smlaier q = pfi_lookup_if(key.pfik_name); 445130613Smlaier#ifdef __FreeBSD__ 446130613Smlaier if ((q != NULL) && (q->pfik_parent != pfi_dummy)) 447130613Smlaier p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); 448130613Smlaier else { 449130613Smlaier if (pfi_dummy == NULL) 450130613Smlaier panic("no 'notyet' dummy group"); 451130613Smlaier p = pfi_if_create(name, pfi_dummy, 452130613Smlaier PFI_IFLAG_PLACEHOLDER); 453130613Smlaier } 454130613Smlaier#else 455130610Smlaier if (q != NULL) 456130610Smlaier p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); 457130613Smlaier#endif 458130610Smlaier } 459130610Smlaier splx(s); 460130610Smlaier return (p); 461130610Smlaier} 462130610Smlaier 463130610Smlaierstruct pfi_kif * 464130610Smlaierpfi_attach_rule(const char *name) 465130610Smlaier{ 466130610Smlaier struct pfi_kif *p; 467130610Smlaier 468130610Smlaier p = pfi_lookup_create(name); 469130610Smlaier if (p != NULL) 470130610Smlaier p->pfik_rules++; 471130610Smlaier return (p); 472130610Smlaier} 473130610Smlaier 474130610Smlaiervoid 475130610Smlaierpfi_detach_rule(struct pfi_kif *p) 476130610Smlaier{ 477130610Smlaier if (p == NULL) 478130610Smlaier return; 479130610Smlaier if (p->pfik_rules > 0) 480130610Smlaier p->pfik_rules--; 481130610Smlaier else 482130610Smlaier printf("pfi_detach_rule: reference count at 0\n"); 483130610Smlaier pfi_maybe_destroy(p); 484130610Smlaier} 485130610Smlaier 486130610Smlaiervoid 487130610Smlaierpfi_attach_state(struct pfi_kif *p) 488130610Smlaier{ 489130610Smlaier if (!p->pfik_states++) 490130610Smlaier TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states); 491130610Smlaier} 492130610Smlaier 493130610Smlaiervoid 494130610Smlaierpfi_detach_state(struct pfi_kif *p) 495130610Smlaier{ 496130610Smlaier if (p == NULL) 497130610Smlaier return; 498130610Smlaier if (p->pfik_states <= 0) { 499130610Smlaier printf("pfi_detach_state: reference count <= 0\n"); 500130610Smlaier return; 501130610Smlaier } 502130610Smlaier if (!--p->pfik_states) 503130610Smlaier TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states); 504130610Smlaier pfi_maybe_destroy(p); 505130610Smlaier} 506130610Smlaier 507130610Smlaierint 508130610Smlaierpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) 509130610Smlaier{ 510130610Smlaier struct pfi_dynaddr *dyn; 511130610Smlaier char tblname[PF_TABLE_NAME_SIZE]; 512130610Smlaier struct pf_ruleset *ruleset = NULL; 513130610Smlaier int s, rv = 0; 514130610Smlaier 515130610Smlaier if (aw->type != PF_ADDR_DYNIFTL) 516130610Smlaier return (0); 517130610Smlaier dyn = pool_get(&pfi_addr_pl, PR_NOWAIT); 518130610Smlaier if (dyn == NULL) 519130610Smlaier return (1); 520130610Smlaier bzero(dyn, sizeof(*dyn)); 521130610Smlaier 522130610Smlaier s = splsoftnet(); 523130610Smlaier dyn->pfid_kif = pfi_attach_rule(aw->v.ifname); 524130610Smlaier if (dyn->pfid_kif == NULL) 525130610Smlaier senderr(1); 526130610Smlaier 527130610Smlaier dyn->pfid_net = pfi_unmask(&aw->v.a.mask); 528130610Smlaier if (af == AF_INET && dyn->pfid_net == 32) 529130610Smlaier dyn->pfid_net = 128; 530130610Smlaier strlcpy(tblname, aw->v.ifname, sizeof(tblname)); 531130610Smlaier if (aw->iflags & PFI_AFLAG_NETWORK) 532130610Smlaier strlcat(tblname, ":network", sizeof(tblname)); 533130610Smlaier if (aw->iflags & PFI_AFLAG_BROADCAST) 534130610Smlaier strlcat(tblname, ":broadcast", sizeof(tblname)); 535130610Smlaier if (aw->iflags & PFI_AFLAG_PEER) 536130610Smlaier strlcat(tblname, ":peer", sizeof(tblname)); 537130610Smlaier if (aw->iflags & PFI_AFLAG_NOALIAS) 538130610Smlaier strlcat(tblname, ":0", sizeof(tblname)); 539130610Smlaier if (dyn->pfid_net != 128) 540130610Smlaier snprintf(tblname + strlen(tblname), 541130610Smlaier sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); 542130610Smlaier ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor, 543130610Smlaier pfi_interface_ruleset); 544130610Smlaier if (ruleset == NULL) 545130610Smlaier senderr(1); 546130610Smlaier 547130610Smlaier dyn->pfid_kt = pfr_attach_table(ruleset, tblname); 548130610Smlaier if (dyn->pfid_kt == NULL) 549130610Smlaier senderr(1); 550130610Smlaier 551130610Smlaier dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; 552130610Smlaier dyn->pfid_iflags = aw->iflags; 553130610Smlaier dyn->pfid_af = af; 554130610Smlaier dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1, 555130610Smlaier pfi_dynaddr_update, dyn); 556130610Smlaier if (dyn->pfid_hook_cookie == NULL) 557130610Smlaier senderr(1); 558130610Smlaier 559130610Smlaier aw->p.dyn = dyn; 560130610Smlaier pfi_dynaddr_update(aw->p.dyn); 561130610Smlaier splx(s); 562130610Smlaier return (0); 563130610Smlaier 564130610Smlaier_bad: 565130610Smlaier if (dyn->pfid_kt != NULL) 566130610Smlaier pfr_detach_table(dyn->pfid_kt); 567130610Smlaier if (ruleset != NULL) 568130610Smlaier pf_remove_if_empty_ruleset(ruleset); 569130610Smlaier if (dyn->pfid_kif != NULL) 570130610Smlaier pfi_detach_rule(dyn->pfid_kif); 571130610Smlaier pool_put(&pfi_addr_pl, dyn); 572130610Smlaier splx(s); 573130610Smlaier return (rv); 574130610Smlaier} 575130610Smlaier 576130610Smlaiervoid 577130610Smlaierpfi_dynaddr_update(void *p) 578130610Smlaier{ 579130610Smlaier struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p; 580130610Smlaier struct pfi_kif *kif = dyn->pfid_kif; 581130610Smlaier struct pfr_ktable *kt = dyn->pfid_kt; 582130610Smlaier 583130610Smlaier if (dyn == NULL || kif == NULL || kt == NULL) 584130610Smlaier panic("pfi_dynaddr_update"); 585130610Smlaier if (kt->pfrkt_larg != pfi_update) { 586130610Smlaier /* this table needs to be brought up-to-date */ 587130610Smlaier pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 588130610Smlaier kt->pfrkt_larg = pfi_update; 589130610Smlaier } 590130610Smlaier pfr_dynaddr_update(kt, dyn); 591130610Smlaier} 592130610Smlaier 593130610Smlaiervoid 594130610Smlaierpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 595130610Smlaier{ 596130610Smlaier int e, size2 = 0; 597130610Smlaier struct pfi_kif *p; 598130610Smlaier struct pfr_table t; 599130610Smlaier 600130610Smlaier if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) { 601130610Smlaier pfr_clr_addrs(&kt->pfrkt_t, NULL, 0); 602130610Smlaier return; 603130610Smlaier } 604130610Smlaier pfi_buffer_cnt = 0; 605130610Smlaier if ((kif->pfik_flags & PFI_IFLAG_INSTANCE)) 606130610Smlaier pfi_instance_add(kif->pfik_ifp, net, flags); 607130610Smlaier else if (strcmp(kif->pfik_name, "self")) { 608130610Smlaier TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances) 609130610Smlaier pfi_instance_add(p->pfik_ifp, net, flags); 610130610Smlaier } else { 611130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) 612130610Smlaier if (p->pfik_flags & PFI_IFLAG_INSTANCE) 613130610Smlaier pfi_instance_add(p->pfik_ifp, net, flags); 614130610Smlaier } 615130610Smlaier t = kt->pfrkt_t; 616130610Smlaier t.pfrt_flags = 0; 617130610Smlaier if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2, 618130610Smlaier NULL, NULL, NULL, 0))) 619130610Smlaier printf("pfi_table_update: cannot set %d new addresses " 620130610Smlaier "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); 621130610Smlaier} 622130610Smlaier 623130610Smlaiervoid 624130610Smlaierpfi_instance_add(struct ifnet *ifp, int net, int flags) 625130610Smlaier{ 626130610Smlaier struct ifaddr *ia; 627130610Smlaier int got4 = 0, got6 = 0; 628130610Smlaier int net2, af; 629130610Smlaier 630130610Smlaier if (ifp == NULL) 631130610Smlaier return; 632130610Smlaier TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) { 633130610Smlaier if (ia->ifa_addr == NULL) 634130610Smlaier continue; 635130610Smlaier af = ia->ifa_addr->sa_family; 636130610Smlaier if (af != AF_INET && af != AF_INET6) 637130610Smlaier continue; 638135215Smlaier#ifdef __FreeBSD__ 639135215Smlaier /* 640135215Smlaier * XXX: For point-to-point interfaces, (ifname:0) and IPv4, 641135215Smlaier * jump over addresses without a proper route to work 642135215Smlaier * around a problem with ppp not fully removing the 643135215Smlaier * address used during IPCP. 644135215Smlaier */ 645135215Smlaier if ((ifp->if_flags & IFF_POINTOPOINT) && 646135215Smlaier !(ia->ifa_flags & IFA_ROUTE) && 647135215Smlaier (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET)) 648133573Smlaier continue; 649133872Smlaier#endif 650130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 651130610Smlaier continue; 652130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && 653130610Smlaier !(ifp->if_flags & IFF_BROADCAST)) 654130610Smlaier continue; 655130610Smlaier if ((flags & PFI_AFLAG_PEER) && 656130610Smlaier !(ifp->if_flags & IFF_POINTOPOINT)) 657130610Smlaier continue; 658130610Smlaier if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 659130610Smlaier IN6_IS_ADDR_LINKLOCAL( 660130610Smlaier &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 661130610Smlaier continue; 662130610Smlaier if (flags & PFI_AFLAG_NOALIAS) { 663130610Smlaier if (af == AF_INET && got4) 664130610Smlaier continue; 665130610Smlaier if (af == AF_INET6 && got6) 666130610Smlaier continue; 667130610Smlaier } 668130610Smlaier if (af == AF_INET) 669130610Smlaier got4 = 1; 670130610Smlaier else 671130610Smlaier got6 = 1; 672130610Smlaier net2 = net; 673130610Smlaier if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 674130610Smlaier if (af == AF_INET) { 675130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in *) 676130610Smlaier ia->ifa_netmask)->sin_addr); 677130610Smlaier } else { 678130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in6 *) 679130610Smlaier ia->ifa_netmask)->sin6_addr); 680130610Smlaier } 681130610Smlaier } 682130610Smlaier if (af == AF_INET && net2 > 32) 683130610Smlaier net2 = 32; 684130610Smlaier if (flags & PFI_AFLAG_BROADCAST) 685130610Smlaier pfi_address_add(ia->ifa_broadaddr, af, net2); 686130610Smlaier else if (flags & PFI_AFLAG_PEER) 687130610Smlaier pfi_address_add(ia->ifa_dstaddr, af, net2); 688130610Smlaier else 689130610Smlaier pfi_address_add(ia->ifa_addr, af, net2); 690130610Smlaier } 691130610Smlaier} 692130610Smlaier 693130610Smlaiervoid 694130610Smlaierpfi_address_add(struct sockaddr *sa, int af, int net) 695130610Smlaier{ 696130610Smlaier struct pfr_addr *p; 697130610Smlaier int i; 698130610Smlaier 699130610Smlaier if (pfi_buffer_cnt >= pfi_buffer_max) { 700130610Smlaier int new_max = pfi_buffer_max * 2; 701130610Smlaier 702130610Smlaier if (new_max > PFI_BUFFER_MAX) { 703130610Smlaier printf("pfi_address_add: address buffer full (%d/%d)\n", 704130610Smlaier pfi_buffer_cnt, PFI_BUFFER_MAX); 705130610Smlaier return; 706130610Smlaier } 707130613Smlaier#ifdef __FreeBSD__ 708130610Smlaier p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 709130613Smlaier M_NOWAIT); 710130613Smlaier#else 711130613Smlaier p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 712130610Smlaier M_DONTWAIT); 713130613Smlaier#endif 714130610Smlaier if (p == NULL) { 715130610Smlaier printf("pfi_address_add: no memory to grow buffer " 716130610Smlaier "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); 717130610Smlaier return; 718130610Smlaier } 719130610Smlaier memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer)); 720130610Smlaier /* no need to zero buffer */ 721130610Smlaier free(pfi_buffer, PFI_MTYPE); 722130610Smlaier pfi_buffer = p; 723130610Smlaier pfi_buffer_max = new_max; 724130610Smlaier } 725130610Smlaier if (af == AF_INET && net > 32) 726130610Smlaier net = 128; 727130610Smlaier p = pfi_buffer + pfi_buffer_cnt++; 728130610Smlaier bzero(p, sizeof(*p)); 729130610Smlaier p->pfra_af = af; 730130610Smlaier p->pfra_net = net; 731130610Smlaier if (af == AF_INET) 732130610Smlaier p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 733130610Smlaier if (af == AF_INET6) { 734130610Smlaier p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 735130610Smlaier if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr)) 736130610Smlaier p->pfra_ip6addr.s6_addr16[1] = 0; 737130610Smlaier } 738130610Smlaier /* mask network address bits */ 739130610Smlaier if (net < 128) 740130610Smlaier ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 741130610Smlaier for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 742130610Smlaier ((caddr_t)p)[i] = 0; 743130610Smlaier} 744130610Smlaier 745130610Smlaiervoid 746130610Smlaierpfi_dynaddr_remove(struct pf_addr_wrap *aw) 747130610Smlaier{ 748130610Smlaier int s; 749130610Smlaier 750130610Smlaier if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 751130610Smlaier aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL) 752130610Smlaier return; 753130610Smlaier 754130610Smlaier s = splsoftnet(); 755130610Smlaier hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head, 756130610Smlaier aw->p.dyn->pfid_hook_cookie); 757130610Smlaier pfi_detach_rule(aw->p.dyn->pfid_kif); 758130610Smlaier aw->p.dyn->pfid_kif = NULL; 759130610Smlaier pfr_detach_table(aw->p.dyn->pfid_kt); 760130610Smlaier aw->p.dyn->pfid_kt = NULL; 761130610Smlaier pool_put(&pfi_addr_pl, aw->p.dyn); 762130610Smlaier aw->p.dyn = NULL; 763130610Smlaier splx(s); 764130610Smlaier} 765130610Smlaier 766130610Smlaiervoid 767130610Smlaierpfi_dynaddr_copyout(struct pf_addr_wrap *aw) 768130610Smlaier{ 769130610Smlaier if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 770130610Smlaier aw->p.dyn->pfid_kif == NULL) 771130610Smlaier return; 772130610Smlaier aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 773130610Smlaier} 774130610Smlaier 775130610Smlaiervoid 776130610Smlaierpfi_kifaddr_update(void *v) 777130610Smlaier{ 778130610Smlaier int s; 779130610Smlaier 780130610Smlaier s = splsoftnet(); 781130610Smlaier pfi_update++; 782130610Smlaier pfi_dohooks(v); 783130610Smlaier splx(s); 784130610Smlaier} 785130610Smlaier 786130610Smlaierint 787130610Smlaierpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 788130610Smlaier{ 789130610Smlaier return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 790130610Smlaier} 791130610Smlaier 792130610Smlaierstruct pfi_kif * 793130610Smlaierpfi_if_create(const char *name, struct pfi_kif *q, int flags) 794130610Smlaier{ 795130610Smlaier struct pfi_kif *p; 796130610Smlaier 797130613Smlaier#ifdef __FreeBSD__ 798130613Smlaier p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT); 799130613Smlaier#else 800130610Smlaier p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT); 801130613Smlaier#endif 802130610Smlaier if (p == NULL) 803130610Smlaier return (NULL); 804130610Smlaier bzero(p, sizeof(*p)); 805130613Smlaier#ifdef __FreeBSD__ 806130610Smlaier p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, 807130613Smlaier M_NOWAIT); 808130613Smlaier#else 809130613Smlaier p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, 810130610Smlaier M_DONTWAIT); 811130613Smlaier#endif 812130610Smlaier if (p->pfik_ah_head == NULL) { 813130610Smlaier free(p, PFI_MTYPE); 814130610Smlaier return (NULL); 815130610Smlaier } 816130610Smlaier bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head)); 817130610Smlaier TAILQ_INIT(p->pfik_ah_head); 818130610Smlaier TAILQ_INIT(&p->pfik_grouphead); 819130610Smlaier strlcpy(p->pfik_name, name, sizeof(p->pfik_name)); 820130610Smlaier RB_INIT(&p->pfik_lan_ext); 821130610Smlaier RB_INIT(&p->pfik_ext_gwy); 822130610Smlaier p->pfik_flags = flags; 823130610Smlaier p->pfik_parent = q; 824130613Smlaier#ifdef __FreeBSD__ 825130613Smlaier p->pfik_tzero = time_second; 826130613Smlaier#else 827130610Smlaier p->pfik_tzero = time.tv_sec; 828130613Smlaier#endif 829130610Smlaier 830130610Smlaier RB_INSERT(pfi_ifhead, &pfi_ifs, p); 831130610Smlaier if (q != NULL) { 832130610Smlaier q->pfik_addcnt++; 833130610Smlaier TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances); 834130610Smlaier } 835130610Smlaier pfi_ifcnt++; 836130610Smlaier return (p); 837130610Smlaier} 838130610Smlaier 839130610Smlaierint 840130610Smlaierpfi_maybe_destroy(struct pfi_kif *p) 841130610Smlaier{ 842130610Smlaier int i, j, k, s; 843130610Smlaier struct pfi_kif *q = p->pfik_parent; 844130610Smlaier 845130610Smlaier if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) || 846130610Smlaier p->pfik_rules > 0 || p->pfik_states > 0) 847130613Smlaier#ifdef __FreeBSD__ 848130613Smlaier if (!(p->pfik_flags & PFI_IFLAG_PLACEHOLDER)) 849130613Smlaier#endif 850130610Smlaier return (0); 851130610Smlaier 852130610Smlaier s = splsoftnet(); 853130610Smlaier if (q != NULL) { 854130610Smlaier for (i = 0; i < 2; i++) 855130610Smlaier for (j = 0; j < 2; j++) 856130610Smlaier for (k = 0; k < 2; k++) { 857130610Smlaier q->pfik_bytes[i][j][k] += 858130610Smlaier p->pfik_bytes[i][j][k]; 859130610Smlaier q->pfik_packets[i][j][k] += 860130610Smlaier p->pfik_packets[i][j][k]; 861130613Smlaier#ifdef __FreeBSD__ 862130613Smlaier /* clear stats in case we return to the dummy group */ 863130613Smlaier p->pfik_bytes[i][j][k] = 0; 864130613Smlaier p->pfik_packets[i][j][k] = 0; 865130613Smlaier#endif 866130610Smlaier } 867130610Smlaier q->pfik_delcnt++; 868130610Smlaier TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances); 869130610Smlaier } 870130613Smlaier#ifdef __FreeBSD__ 871130613Smlaier if (p->pfik_rules > 0 || p->pfik_states > 0) { 872130613Smlaier /* move back to the dummy group */ 873130613Smlaier p->pfik_parent = pfi_dummy; 874137159Smlaier p->pfik_flags &= ~PFI_IFLAG_INSTANCE; 875130613Smlaier pfi_dummy->pfik_addcnt++; 876130613Smlaier TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p, 877130613Smlaier pfik_instances); 878130613Smlaier return (0); 879130613Smlaier } 880130613Smlaier#endif 881130610Smlaier pfi_ifcnt--; 882130610Smlaier RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 883130610Smlaier splx(s); 884130610Smlaier 885130610Smlaier free(p->pfik_ah_head, PFI_MTYPE); 886130610Smlaier free(p, PFI_MTYPE); 887130610Smlaier return (1); 888130610Smlaier} 889130610Smlaier 890130610Smlaiervoid 891130610Smlaierpfi_copy_group(char *p, const char *q, int m) 892130610Smlaier{ 893130610Smlaier while (m > 1 && *q && !(*q >= '0' && *q <= '9')) { 894130610Smlaier *p++ = *q++; 895130610Smlaier m--; 896130610Smlaier } 897130610Smlaier if (m > 0) 898130610Smlaier *p++ = '\0'; 899130610Smlaier} 900130610Smlaier 901130610Smlaiervoid 902130610Smlaierpfi_dynamic_drivers(void) 903130610Smlaier{ 904130613Smlaier#ifdef __FreeBSD__ 905130613Smlaier struct ifnet *ifp; 906130613Smlaier 907130613Smlaier/* 908130613Smlaier * For FreeBSD basically every interface is "dynamic" as we can unload 909130613Smlaier * modules e.g. 910130613Smlaier */ 911130613Smlaier 912130613Smlaier IFNET_RLOCK(); 913137159Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) 914130613Smlaier pfi_newgroup(ifp->if_dname, PFI_IFLAG_DYNAMIC); 915130613Smlaier IFNET_RUNLOCK(); 916130613Smlaier#else 917130610Smlaier char *buses[] = PFI_DYNAMIC_BUSES; 918130610Smlaier int nbuses = sizeof(buses)/sizeof(buses[0]); 919130610Smlaier int enabled[sizeof(buses)/sizeof(buses[0])]; 920130610Smlaier struct device *dev; 921130610Smlaier struct cfdata *cf; 922130610Smlaier struct cfdriver *drv; 923130610Smlaier short *p; 924130610Smlaier int i; 925130610Smlaier 926130610Smlaier bzero(enabled, sizeof(enabled)); 927130610Smlaier TAILQ_FOREACH(dev, &alldevs, dv_list) { 928130610Smlaier if (!(dev->dv_flags & DVF_ACTIVE)) 929130610Smlaier continue; 930130610Smlaier for (i = 0; i < nbuses; i++) 931130610Smlaier if (!enabled[i] && !strcmp(buses[i], 932130610Smlaier dev->dv_cfdata->cf_driver->cd_name)) 933130610Smlaier enabled[i] = 1; 934130610Smlaier } 935130610Smlaier for (cf = cfdata; cf->cf_driver; cf++) { 936130610Smlaier if (cf->cf_driver->cd_class != DV_IFNET) 937130610Smlaier continue; 938130610Smlaier for (p = cf->cf_parents; p && *p >= 0; p++) { 939130610Smlaier if ((drv = cfdata[*p].cf_driver) == NULL) 940130610Smlaier continue; 941130610Smlaier for (i = 0; i < nbuses; i++) 942130610Smlaier if (enabled[i] && 943130610Smlaier !strcmp(drv->cd_name, buses[i])) 944130610Smlaier break; 945130610Smlaier if (i < nbuses) { 946130610Smlaier pfi_newgroup(cf->cf_driver->cd_name, 947130610Smlaier PFI_IFLAG_DYNAMIC); 948130610Smlaier break; 949130610Smlaier } 950130610Smlaier } 951130610Smlaier } 952130613Smlaier#endif 953130610Smlaier} 954130610Smlaier 955130610Smlaiervoid 956130610Smlaierpfi_newgroup(const char *name, int flags) 957130610Smlaier{ 958130610Smlaier struct pfi_kif *p; 959130610Smlaier 960130610Smlaier p = pfi_lookup_if(name); 961130610Smlaier if (p == NULL) 962130610Smlaier p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP); 963130610Smlaier if (p == NULL) { 964130610Smlaier printf("pfi_newgroup: cannot allocate '%s' group", name); 965130610Smlaier return; 966130610Smlaier } 967130610Smlaier p->pfik_flags |= flags; 968130610Smlaier} 969130610Smlaier 970130610Smlaiervoid 971130610Smlaierpfi_fill_oldstatus(struct pf_status *pfs) 972130610Smlaier{ 973130610Smlaier struct pfi_kif *p, key; 974130610Smlaier int i, j, k, s; 975130610Smlaier 976130610Smlaier strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); 977130610Smlaier s = splsoftnet(); 978130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 979130610Smlaier if (p == NULL) { 980130610Smlaier splx(s); 981130610Smlaier return; 982130610Smlaier } 983130610Smlaier bzero(pfs->pcounters, sizeof(pfs->pcounters)); 984130610Smlaier bzero(pfs->bcounters, sizeof(pfs->bcounters)); 985130610Smlaier for (i = 0; i < 2; i++) 986130610Smlaier for (j = 0; j < 2; j++) 987130610Smlaier for (k = 0; k < 2; k++) { 988130610Smlaier pfs->pcounters[i][j][k] = 989130610Smlaier p->pfik_packets[i][j][k]; 990130610Smlaier pfs->bcounters[i][j] += 991130610Smlaier p->pfik_bytes[i][j][k]; 992130610Smlaier } 993130610Smlaier splx(s); 994130610Smlaier} 995130610Smlaier 996130610Smlaierint 997130610Smlaierpfi_clr_istats(const char *name, int *nzero, int flags) 998130610Smlaier{ 999130610Smlaier struct pfi_kif *p; 1000130610Smlaier int n = 0, s; 1001130613Smlaier#ifdef __FreeBSD__ 1002130613Smlaier long tzero = time_second; 1003130613Smlaier#else 1004130610Smlaier long tzero = time.tv_sec; 1005130613Smlaier#endif 1006130610Smlaier 1007130610Smlaier s = splsoftnet(); 1008130610Smlaier ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 1009130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 1010130610Smlaier if (pfi_skip_if(name, p, flags)) 1011130610Smlaier continue; 1012130610Smlaier bzero(p->pfik_packets, sizeof(p->pfik_packets)); 1013130610Smlaier bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 1014130610Smlaier p->pfik_tzero = tzero; 1015130610Smlaier n++; 1016130610Smlaier } 1017130610Smlaier splx(s); 1018130610Smlaier if (nzero != NULL) 1019130610Smlaier *nzero = n; 1020130610Smlaier return (0); 1021130610Smlaier} 1022130610Smlaier 1023130610Smlaierint 1024130610Smlaierpfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags) 1025130610Smlaier{ 1026130610Smlaier struct pfi_kif *p; 1027130610Smlaier int s, n = 0; 1028130613Smlaier#ifdef __FreeBSD__ 1029130613Smlaier int ec; 1030130613Smlaier#endif 1031130610Smlaier 1032130610Smlaier ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 1033130610Smlaier s = splsoftnet(); 1034130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 1035130610Smlaier if (pfi_skip_if(name, p, flags)) 1036130610Smlaier continue; 1037130610Smlaier if (*size > n++) { 1038130610Smlaier if (!p->pfik_tzero) 1039130610Smlaier p->pfik_tzero = boottime.tv_sec; 1040130613Smlaier#ifdef __FreeBSD__ 1041130613Smlaier PF_COPYOUT(p, buf++, sizeof(*buf), ec); 1042130613Smlaier if (ec) { 1043130613Smlaier#else 1044130610Smlaier if (copyout(p, buf++, sizeof(*buf))) { 1045130613Smlaier#endif 1046130610Smlaier splx(s); 1047130610Smlaier return (EFAULT); 1048130610Smlaier } 1049130610Smlaier } 1050130610Smlaier } 1051130610Smlaier splx(s); 1052130610Smlaier *size = n; 1053130610Smlaier return (0); 1054130610Smlaier} 1055130610Smlaier 1056130610Smlaierstruct pfi_kif * 1057130610Smlaierpfi_lookup_if(const char *name) 1058130610Smlaier{ 1059130610Smlaier struct pfi_kif *p, key; 1060130610Smlaier 1061130610Smlaier strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); 1062130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 1063130610Smlaier return (p); 1064130610Smlaier} 1065130610Smlaier 1066130610Smlaierint 1067130610Smlaierpfi_skip_if(const char *filter, struct pfi_kif *p, int f) 1068130610Smlaier{ 1069130610Smlaier int n; 1070130610Smlaier 1071130610Smlaier if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP)) 1072130610Smlaier return (1); 1073130610Smlaier if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE)) 1074130610Smlaier return (1); 1075130610Smlaier if (filter == NULL || !*filter) 1076130610Smlaier return (0); 1077130610Smlaier if (!strcmp(p->pfik_name, filter)) 1078130610Smlaier return (0); /* exact match */ 1079130610Smlaier n = strlen(filter); 1080130610Smlaier if (n < 1 || n >= IFNAMSIZ) 1081130610Smlaier return (1); /* sanity check */ 1082130610Smlaier if (filter[n-1] >= '0' && filter[n-1] <= '9') 1083130610Smlaier return (1); /* only do exact match in that case */ 1084130610Smlaier if (strncmp(p->pfik_name, filter, n)) 1085130610Smlaier return (1); /* prefix doesn't match */ 1086130610Smlaier return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 1087130610Smlaier} 1088130610Smlaier 1089130610Smlaier/* from pf_print_state.c */ 1090130610Smlaierint 1091130610Smlaierpfi_unmask(void *addr) 1092130610Smlaier{ 1093130610Smlaier struct pf_addr *m = addr; 1094130610Smlaier int i = 31, j = 0, b = 0; 1095130610Smlaier u_int32_t tmp; 1096130610Smlaier 1097130610Smlaier while (j < 4 && m->addr32[j] == 0xffffffff) { 1098130610Smlaier b += 32; 1099130610Smlaier j++; 1100130610Smlaier } 1101130610Smlaier if (j < 4) { 1102130610Smlaier tmp = ntohl(m->addr32[j]); 1103130610Smlaier for (i = 31; tmp & (1 << i); --i) 1104130610Smlaier b++; 1105130610Smlaier } 1106130610Smlaier return (b); 1107130610Smlaier} 1108130610Smlaier 1109130610Smlaiervoid 1110130610Smlaierpfi_dohooks(struct pfi_kif *p) 1111130610Smlaier{ 1112130610Smlaier for (; p != NULL; p = p->pfik_parent) 1113130610Smlaier dohooks(p->pfik_ah_head, 0); 1114130610Smlaier} 1115130610Smlaier 1116130610Smlaierint 1117130610Smlaierpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 1118130610Smlaier{ 1119130610Smlaier if (af == AF_INET) { 1120130610Smlaier switch (dyn->pfid_acnt4) { 1121130610Smlaier case 0: 1122130610Smlaier return (0); 1123130610Smlaier case 1: 1124130610Smlaier return (PF_MATCHA(0, &dyn->pfid_addr4, 1125130610Smlaier &dyn->pfid_mask4, a, AF_INET)); 1126130610Smlaier default: 1127130610Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 1128130610Smlaier } 1129130610Smlaier } else { 1130130610Smlaier switch (dyn->pfid_acnt6) { 1131130610Smlaier case 0: 1132130610Smlaier return (0); 1133130610Smlaier case 1: 1134130610Smlaier return (PF_MATCHA(0, &dyn->pfid_addr6, 1135130610Smlaier &dyn->pfid_mask6, a, AF_INET6)); 1136130610Smlaier default: 1137130610Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 1138130610Smlaier } 1139130610Smlaier } 1140130610Smlaier} 1141