pf_if.c revision 133573
1130613Smlaier/* $FreeBSD: head/sys/contrib/pf/net/pf_if.c 133573 2004-08-12 13:54:50Z 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(); 160130613Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) 161130613Smlaier if (ifp->if_dunit != IF_DUNIT_NONE) { 162130613Smlaier IFNET_RUNLOCK(); 163130613Smlaier pfi_attach_ifnet(ifp); 164130613Smlaier IFNET_RLOCK(); 165130613Smlaier } 166130613Smlaier IFNET_RUNLOCK(); 167130613Smlaier PF_UNLOCK(); 168130613Smlaier pfi_dummy = pfi_if_create("notyet", pfi_self, 169130613Smlaier PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 170130613Smlaier pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, 171130613Smlaier pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 172130613Smlaier pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 173130613Smlaier pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 174130613Smlaier pfi_clone_cookie = EVENTHANDLER_REGISTER(if_clone_event, 175130613Smlaier pfi_attach_clone_event, NULL, EVENTHANDLER_PRI_ANY); 176130613Smlaier#endif 177130610Smlaier} 178130610Smlaier 179130613Smlaier#ifdef __FreeBSD__ 180130610Smlaiervoid 181130613Smlaierpfi_cleanup(void) 182130613Smlaier{ 183130613Smlaier struct pfi_kif *p, key; 184130613Smlaier struct ifnet *ifp; 185130613Smlaier 186130613Smlaier PF_ASSERT(MA_OWNED); 187132567Smlaier 188130613Smlaier PF_UNLOCK(); 189130613Smlaier EVENTHANDLER_DEREGISTER(ifnet_arrival_event, pfi_attach_cookie); 190130613Smlaier EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfi_detach_cookie); 191130613Smlaier EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie); 192132567Smlaier PF_LOCK(); 193130613Smlaier 194130613Smlaier IFNET_RLOCK(); 195130613Smlaier /* release PFI_IFLAG_INSTANCE */ 196130613Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) { 197130613Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 198130613Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 199130613Smlaier if (p != NULL) { 200132567Smlaier IFNET_RUNLOCK(); 201130613Smlaier pfi_detach_ifnet(ifp); 202132567Smlaier IFNET_RLOCK(); 203130613Smlaier } 204130613Smlaier } 205130613Smlaier IFNET_RUNLOCK(); 206130613Smlaier 207130613Smlaier /* XXX clear all other interface group */ 208130613Smlaier while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { 209130613Smlaier RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 210130613Smlaier 211130613Smlaier free(p->pfik_ah_head, PFI_MTYPE); 212130613Smlaier free(p, PFI_MTYPE); 213130613Smlaier } 214130613Smlaier free(pfi_index2kif, PFI_MTYPE); 215130613Smlaier free(pfi_buffer, PFI_MTYPE); 216130613Smlaier pfi_index2kif = NULL; 217130613Smlaier pfi_buffer = NULL; 218130613Smlaier pfi_self = NULL; 219130613Smlaier} 220130613Smlaier 221130613Smlaier/* 222130613Smlaier * Wrapper functions for FreeBSD eventhandler 223130613Smlaier */ 224130613Smlaiervoid 225130613Smlaierpfi_kifaddr_update_event(void *arg, struct ifnet *ifp) 226130613Smlaier{ 227130613Smlaier struct pfi_kif *p = arg; 228130613Smlaier 229130613Smlaier PF_LOCK(); 230130613Smlaier /* 231130613Smlaier * Check to see if it is 'our' interface as we do not have per 232130613Smlaier * interface hooks and thus get an update for every interface. 233130613Smlaier */ 234130613Smlaier if (p && p->pfik_ifp == ifp) 235130613Smlaier pfi_kifaddr_update(p); 236130613Smlaier PF_UNLOCK(); 237130613Smlaier} 238130613Smlaier 239130613Smlaiervoid 240130613Smlaierpfi_attach_clone_event(void *arg __unused, struct if_clone *ifc) 241130613Smlaier{ 242130613Smlaier PF_LOCK(); 243130613Smlaier pfi_attach_clone(ifc); 244130613Smlaier PF_UNLOCK(); 245130613Smlaier} 246130613Smlaier 247130613Smlaiervoid 248130613Smlaierpfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) 249130613Smlaier{ 250130613Smlaier PF_LOCK(); 251130613Smlaier if (ifp->if_dunit != IF_DUNIT_NONE) 252130613Smlaier pfi_attach_ifnet(ifp); 253130613Smlaier PF_UNLOCK(); 254130613Smlaier} 255130613Smlaier 256130613Smlaiervoid 257130613Smlaierpfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) 258130613Smlaier{ 259130613Smlaier PF_LOCK(); 260130613Smlaier pfi_detach_ifnet(ifp); 261130613Smlaier PF_UNLOCK(); 262130613Smlaier} 263130613Smlaier#endif /* __FreeBSD__ */ 264130613Smlaier 265130613Smlaiervoid 266130610Smlaierpfi_attach_clone(struct if_clone *ifc) 267130610Smlaier{ 268130610Smlaier pfi_initialize(); 269130610Smlaier pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE); 270130610Smlaier} 271130610Smlaier 272130610Smlaiervoid 273130610Smlaierpfi_attach_ifnet(struct ifnet *ifp) 274130610Smlaier{ 275130610Smlaier struct pfi_kif *p, *q, key; 276130610Smlaier int s; 277130613Smlaier#ifdef __FreeBSD__ 278130613Smlaier int realname; 279130613Smlaier#endif 280130610Smlaier 281130610Smlaier pfi_initialize(); 282130610Smlaier s = splsoftnet(); 283130610Smlaier pfi_update++; 284130610Smlaier if (ifp->if_index >= pfi_indexlim) { 285130610Smlaier /* 286130610Smlaier * grow pfi_index2kif, similar to ifindex2ifnet code in if.c 287130610Smlaier */ 288130610Smlaier size_t m, n, oldlim; 289130610Smlaier struct pfi_kif **mp, **np; 290130610Smlaier 291130610Smlaier oldlim = pfi_indexlim; 292130610Smlaier if (pfi_indexlim == 0) 293130610Smlaier pfi_indexlim = 64; 294130610Smlaier while (ifp->if_index >= pfi_indexlim) 295130610Smlaier pfi_indexlim <<= 1; 296130610Smlaier 297130610Smlaier m = oldlim * sizeof(struct pfi_kif *); 298130610Smlaier mp = pfi_index2kif; 299130610Smlaier n = pfi_indexlim * sizeof(struct pfi_kif *); 300130613Smlaier#ifdef __FreeBSD__ 301130613Smlaier np = malloc(n, PFI_MTYPE, M_NOWAIT); 302130613Smlaier#else 303130610Smlaier np = malloc(n, PFI_MTYPE, M_DONTWAIT); 304130613Smlaier#endif 305130610Smlaier if (np == NULL) 306130610Smlaier panic("pfi_attach_ifnet: " 307130610Smlaier "cannot allocate translation table"); 308130610Smlaier bzero(np, n); 309130610Smlaier if (mp != NULL) 310130610Smlaier bcopy(mp, np, m); 311130610Smlaier pfi_index2kif = np; 312130610Smlaier if (mp != NULL) 313130610Smlaier free(mp, PFI_MTYPE); 314130610Smlaier } 315130610Smlaier 316130610Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 317130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 318130613Smlaier#ifdef __FreeBSD__ 319130613Smlaier /* some additional trickery for placeholders */ 320130613Smlaier if ((p == NULL) || (p->pfik_parent == pfi_dummy)) { 321130613Smlaier /* are we looking at a renamed instance or not? */ 322130613Smlaier pfi_copy_group(key.pfik_name, ifp->if_xname, 323130613Smlaier sizeof(key.pfik_name)); 324130613Smlaier realname = (strncmp(key.pfik_name, ifp->if_dname, 325130613Smlaier sizeof(key.pfik_name)) == 0); 326130613Smlaier /* add group */ 327130613Smlaier /* we can change if_xname, hence use if_dname as group id */ 328130613Smlaier pfi_copy_group(key.pfik_name, ifp->if_dname, 329130613Smlaier sizeof(key.pfik_name)); 330130613Smlaier q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 331130613Smlaier if (q == NULL) 332130613Smlaier q = pfi_if_create(key.pfik_name, pfi_self, 333130613Smlaier PFI_IFLAG_GROUP|PFI_IFLAG_DYNAMIC); 334130613Smlaier else if (q->pfik_parent == pfi_dummy) { 335130613Smlaier q->pfik_parent = pfi_self; 336130613Smlaier q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 337130613Smlaier } 338130613Smlaier if (q == NULL) 339130613Smlaier panic("pfi_attach_ifnet: " 340130613Smlaier "cannot allocate '%s' group", key.pfik_name); 341130613Smlaier 342130613Smlaier /* add/modify interface */ 343130613Smlaier if (p == NULL) 344130613Smlaier p = pfi_if_create(ifp->if_xname, q, 345130613Smlaier realname?PFI_IFLAG_INSTANCE:PFI_IFLAG_PLACEHOLDER); 346130613Smlaier else { 347130613Smlaier /* remove from the dummy group */ 348130613Smlaier /* XXX: copy stats? We should not have any!!! */ 349130613Smlaier pfi_dummy->pfik_delcnt++; 350130613Smlaier TAILQ_REMOVE(&pfi_dummy->pfik_grouphead, p, 351130613Smlaier pfik_instances); 352130613Smlaier /* move to the right group */ 353130613Smlaier p->pfik_parent = q; 354130613Smlaier q->pfik_addcnt++; 355130613Smlaier TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, 356130613Smlaier pfik_instances); 357130613Smlaier if (realname) { 358130613Smlaier p->pfik_flags &= ~PFI_IFLAG_PLACEHOLDER; 359130613Smlaier p->pfik_flags |= PFI_IFLAG_INSTANCE; 360130613Smlaier } 361130613Smlaier } 362130613Smlaier if (p == NULL) 363130613Smlaier panic("pfi_attach_ifnet: " 364130613Smlaier "cannot allocate '%s' interface", ifp->if_xname); 365130613Smlaier#else 366130610Smlaier if (p == NULL) { 367130610Smlaier /* add group */ 368130610Smlaier pfi_copy_group(key.pfik_name, ifp->if_xname, 369130610Smlaier sizeof(key.pfik_name)); 370130610Smlaier q = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 371130610Smlaier if (q == NULL) 372130610Smlaier q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP); 373130613Smlaier else if (q->pfik_parent == pfi_dummy) { 374130613Smlaier q->pfik_parent = pfi_self; 375130613Smlaier q->pfik_flags = (PFI_IFLAG_GROUP | PFI_IFLAG_DYNAMIC); 376130613Smlaier } 377130610Smlaier if (q == NULL) 378130610Smlaier panic("pfi_attach_ifnet: " 379130610Smlaier "cannot allocate '%s' group", key.pfik_name); 380130610Smlaier 381130610Smlaier /* add interface */ 382130610Smlaier p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE); 383130610Smlaier if (p == NULL) 384130610Smlaier panic("pfi_attach_ifnet: " 385130610Smlaier "cannot allocate '%s' interface", ifp->if_xname); 386130613Smlaier#endif 387130610Smlaier } else 388130610Smlaier q = p->pfik_parent; 389130610Smlaier p->pfik_ifp = ifp; 390130610Smlaier p->pfik_flags |= PFI_IFLAG_ATTACHED; 391130613Smlaier#ifdef __FreeBSD__ 392130613Smlaier PF_UNLOCK(); 393130613Smlaier p->pfik_ah_cookie = EVENTHANDLER_REGISTER(ifaddr_event, 394130613Smlaier pfi_kifaddr_update_event, p, EVENTHANDLER_PRI_ANY); 395130613Smlaier PF_LOCK(); 396130613Smlaier#else 397130610Smlaier p->pfik_ah_cookie = 398130610Smlaier hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p); 399130613Smlaier#endif 400130610Smlaier pfi_index2kif[ifp->if_index] = p; 401130610Smlaier pfi_dohooks(p); 402130610Smlaier splx(s); 403130610Smlaier} 404130610Smlaier 405130610Smlaiervoid 406130610Smlaierpfi_detach_ifnet(struct ifnet *ifp) 407130610Smlaier{ 408130610Smlaier struct pfi_kif *p, *q, key; 409130610Smlaier int s; 410130610Smlaier 411130610Smlaier strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name)); 412130610Smlaier 413130610Smlaier s = splsoftnet(); 414130610Smlaier pfi_update++; 415130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 416130610Smlaier if (p == NULL) { 417130610Smlaier printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname); 418130610Smlaier splx(s); 419130610Smlaier return; 420130610Smlaier } 421130613Smlaier#ifdef __FreeBSD__ 422130613Smlaier PF_UNLOCK(); 423130613Smlaier EVENTHANDLER_DEREGISTER(ifaddr_event, p->pfik_ah_cookie); 424130613Smlaier PF_LOCK(); 425130613Smlaier#else 426130610Smlaier hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie); 427130613Smlaier#endif 428130610Smlaier q = p->pfik_parent; 429130610Smlaier p->pfik_ifp = NULL; 430130610Smlaier p->pfik_flags &= ~PFI_IFLAG_ATTACHED; 431130610Smlaier pfi_index2kif[ifp->if_index] = NULL; 432130610Smlaier pfi_dohooks(p); 433130610Smlaier pfi_maybe_destroy(p); 434130610Smlaier splx(s); 435130610Smlaier} 436130610Smlaier 437130610Smlaierstruct pfi_kif * 438130610Smlaierpfi_lookup_create(const char *name) 439130610Smlaier{ 440130610Smlaier struct pfi_kif *p, *q, key; 441130610Smlaier int s; 442130610Smlaier 443130610Smlaier s = splsoftnet(); 444130610Smlaier p = pfi_lookup_if(name); 445130610Smlaier if (p == NULL) { 446130610Smlaier pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name)); 447130610Smlaier q = pfi_lookup_if(key.pfik_name); 448130613Smlaier#ifdef __FreeBSD__ 449130613Smlaier if ((q != NULL) && (q->pfik_parent != pfi_dummy)) 450130613Smlaier p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); 451130613Smlaier else { 452130613Smlaier if (pfi_dummy == NULL) 453130613Smlaier panic("no 'notyet' dummy group"); 454130613Smlaier p = pfi_if_create(name, pfi_dummy, 455130613Smlaier PFI_IFLAG_PLACEHOLDER); 456130613Smlaier } 457130613Smlaier#else 458130610Smlaier if (q != NULL) 459130610Smlaier p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE); 460130613Smlaier#endif 461130610Smlaier } 462130610Smlaier splx(s); 463130610Smlaier return (p); 464130610Smlaier} 465130610Smlaier 466130610Smlaierstruct pfi_kif * 467130610Smlaierpfi_attach_rule(const char *name) 468130610Smlaier{ 469130610Smlaier struct pfi_kif *p; 470130610Smlaier 471130610Smlaier p = pfi_lookup_create(name); 472130610Smlaier if (p != NULL) 473130610Smlaier p->pfik_rules++; 474130610Smlaier return (p); 475130610Smlaier} 476130610Smlaier 477130610Smlaiervoid 478130610Smlaierpfi_detach_rule(struct pfi_kif *p) 479130610Smlaier{ 480130610Smlaier if (p == NULL) 481130610Smlaier return; 482130610Smlaier if (p->pfik_rules > 0) 483130610Smlaier p->pfik_rules--; 484130610Smlaier else 485130610Smlaier printf("pfi_detach_rule: reference count at 0\n"); 486130610Smlaier pfi_maybe_destroy(p); 487130610Smlaier} 488130610Smlaier 489130610Smlaiervoid 490130610Smlaierpfi_attach_state(struct pfi_kif *p) 491130610Smlaier{ 492130610Smlaier if (!p->pfik_states++) 493130610Smlaier TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states); 494130610Smlaier} 495130610Smlaier 496130610Smlaiervoid 497130610Smlaierpfi_detach_state(struct pfi_kif *p) 498130610Smlaier{ 499130610Smlaier if (p == NULL) 500130610Smlaier return; 501130610Smlaier if (p->pfik_states <= 0) { 502130610Smlaier printf("pfi_detach_state: reference count <= 0\n"); 503130610Smlaier return; 504130610Smlaier } 505130610Smlaier if (!--p->pfik_states) 506130610Smlaier TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states); 507130610Smlaier pfi_maybe_destroy(p); 508130610Smlaier} 509130610Smlaier 510130610Smlaierint 511130610Smlaierpfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) 512130610Smlaier{ 513130610Smlaier struct pfi_dynaddr *dyn; 514130610Smlaier char tblname[PF_TABLE_NAME_SIZE]; 515130610Smlaier struct pf_ruleset *ruleset = NULL; 516130610Smlaier int s, rv = 0; 517130610Smlaier 518130610Smlaier if (aw->type != PF_ADDR_DYNIFTL) 519130610Smlaier return (0); 520130610Smlaier dyn = pool_get(&pfi_addr_pl, PR_NOWAIT); 521130610Smlaier if (dyn == NULL) 522130610Smlaier return (1); 523130610Smlaier bzero(dyn, sizeof(*dyn)); 524130610Smlaier 525130610Smlaier s = splsoftnet(); 526130610Smlaier dyn->pfid_kif = pfi_attach_rule(aw->v.ifname); 527130610Smlaier if (dyn->pfid_kif == NULL) 528130610Smlaier senderr(1); 529130610Smlaier 530130610Smlaier dyn->pfid_net = pfi_unmask(&aw->v.a.mask); 531130610Smlaier if (af == AF_INET && dyn->pfid_net == 32) 532130610Smlaier dyn->pfid_net = 128; 533130610Smlaier strlcpy(tblname, aw->v.ifname, sizeof(tblname)); 534130610Smlaier if (aw->iflags & PFI_AFLAG_NETWORK) 535130610Smlaier strlcat(tblname, ":network", sizeof(tblname)); 536130610Smlaier if (aw->iflags & PFI_AFLAG_BROADCAST) 537130610Smlaier strlcat(tblname, ":broadcast", sizeof(tblname)); 538130610Smlaier if (aw->iflags & PFI_AFLAG_PEER) 539130610Smlaier strlcat(tblname, ":peer", sizeof(tblname)); 540130610Smlaier if (aw->iflags & PFI_AFLAG_NOALIAS) 541130610Smlaier strlcat(tblname, ":0", sizeof(tblname)); 542130610Smlaier if (dyn->pfid_net != 128) 543130610Smlaier snprintf(tblname + strlen(tblname), 544130610Smlaier sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net); 545130610Smlaier ruleset = pf_find_or_create_ruleset(pfi_reserved_anchor, 546130610Smlaier pfi_interface_ruleset); 547130610Smlaier if (ruleset == NULL) 548130610Smlaier senderr(1); 549130610Smlaier 550130610Smlaier dyn->pfid_kt = pfr_attach_table(ruleset, tblname); 551130610Smlaier if (dyn->pfid_kt == NULL) 552130610Smlaier senderr(1); 553130610Smlaier 554130610Smlaier dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE; 555130610Smlaier dyn->pfid_iflags = aw->iflags; 556130610Smlaier dyn->pfid_af = af; 557130610Smlaier dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1, 558130610Smlaier pfi_dynaddr_update, dyn); 559130610Smlaier if (dyn->pfid_hook_cookie == NULL) 560130610Smlaier senderr(1); 561130610Smlaier 562130610Smlaier aw->p.dyn = dyn; 563130610Smlaier pfi_dynaddr_update(aw->p.dyn); 564130610Smlaier splx(s); 565130610Smlaier return (0); 566130610Smlaier 567130610Smlaier_bad: 568130610Smlaier if (dyn->pfid_kt != NULL) 569130610Smlaier pfr_detach_table(dyn->pfid_kt); 570130610Smlaier if (ruleset != NULL) 571130610Smlaier pf_remove_if_empty_ruleset(ruleset); 572130610Smlaier if (dyn->pfid_kif != NULL) 573130610Smlaier pfi_detach_rule(dyn->pfid_kif); 574130610Smlaier pool_put(&pfi_addr_pl, dyn); 575130610Smlaier splx(s); 576130610Smlaier return (rv); 577130610Smlaier} 578130610Smlaier 579130610Smlaiervoid 580130610Smlaierpfi_dynaddr_update(void *p) 581130610Smlaier{ 582130610Smlaier struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p; 583130610Smlaier struct pfi_kif *kif = dyn->pfid_kif; 584130610Smlaier struct pfr_ktable *kt = dyn->pfid_kt; 585130610Smlaier 586130610Smlaier if (dyn == NULL || kif == NULL || kt == NULL) 587130610Smlaier panic("pfi_dynaddr_update"); 588130610Smlaier if (kt->pfrkt_larg != pfi_update) { 589130610Smlaier /* this table needs to be brought up-to-date */ 590130610Smlaier pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); 591130610Smlaier kt->pfrkt_larg = pfi_update; 592130610Smlaier } 593130610Smlaier pfr_dynaddr_update(kt, dyn); 594130610Smlaier} 595130610Smlaier 596130610Smlaiervoid 597130610Smlaierpfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) 598130610Smlaier{ 599130610Smlaier int e, size2 = 0; 600130610Smlaier struct pfi_kif *p; 601130610Smlaier struct pfr_table t; 602130610Smlaier 603130610Smlaier if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) { 604130610Smlaier pfr_clr_addrs(&kt->pfrkt_t, NULL, 0); 605130610Smlaier return; 606130610Smlaier } 607130610Smlaier pfi_buffer_cnt = 0; 608130610Smlaier if ((kif->pfik_flags & PFI_IFLAG_INSTANCE)) 609130610Smlaier pfi_instance_add(kif->pfik_ifp, net, flags); 610130610Smlaier else if (strcmp(kif->pfik_name, "self")) { 611130610Smlaier TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances) 612130610Smlaier pfi_instance_add(p->pfik_ifp, net, flags); 613130610Smlaier } else { 614130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) 615130610Smlaier if (p->pfik_flags & PFI_IFLAG_INSTANCE) 616130610Smlaier pfi_instance_add(p->pfik_ifp, net, flags); 617130610Smlaier } 618130610Smlaier t = kt->pfrkt_t; 619130610Smlaier t.pfrt_flags = 0; 620130610Smlaier if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2, 621130610Smlaier NULL, NULL, NULL, 0))) 622130610Smlaier printf("pfi_table_update: cannot set %d new addresses " 623130610Smlaier "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); 624130610Smlaier} 625130610Smlaier 626130610Smlaiervoid 627130610Smlaierpfi_instance_add(struct ifnet *ifp, int net, int flags) 628130610Smlaier{ 629130610Smlaier struct ifaddr *ia; 630130610Smlaier int got4 = 0, got6 = 0; 631130610Smlaier int net2, af; 632130610Smlaier 633130610Smlaier if (ifp == NULL) 634130610Smlaier return; 635130610Smlaier TAILQ_FOREACH(ia, &ifp->if_addrlist, ifa_list) { 636130610Smlaier if (ia->ifa_addr == NULL) 637130610Smlaier continue; 638130610Smlaier af = ia->ifa_addr->sa_family; 639130610Smlaier if (af != AF_INET && af != AF_INET6) 640130610Smlaier continue; 641133573Smlaier if (!(ia->ifa_flags & IFA_ROUTE)) 642133573Smlaier continue; 643130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6) 644130610Smlaier continue; 645130610Smlaier if ((flags & PFI_AFLAG_BROADCAST) && 646130610Smlaier !(ifp->if_flags & IFF_BROADCAST)) 647130610Smlaier continue; 648130610Smlaier if ((flags & PFI_AFLAG_PEER) && 649130610Smlaier !(ifp->if_flags & IFF_POINTOPOINT)) 650130610Smlaier continue; 651130610Smlaier if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 && 652130610Smlaier IN6_IS_ADDR_LINKLOCAL( 653130610Smlaier &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr)) 654130610Smlaier continue; 655130610Smlaier if (flags & PFI_AFLAG_NOALIAS) { 656130610Smlaier if (af == AF_INET && got4) 657130610Smlaier continue; 658130610Smlaier if (af == AF_INET6 && got6) 659130610Smlaier continue; 660130610Smlaier } 661130610Smlaier if (af == AF_INET) 662130610Smlaier got4 = 1; 663130610Smlaier else 664130610Smlaier got6 = 1; 665130610Smlaier net2 = net; 666130610Smlaier if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) { 667130610Smlaier if (af == AF_INET) { 668130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in *) 669130610Smlaier ia->ifa_netmask)->sin_addr); 670130610Smlaier } else { 671130610Smlaier net2 = pfi_unmask(&((struct sockaddr_in6 *) 672130610Smlaier ia->ifa_netmask)->sin6_addr); 673130610Smlaier } 674130610Smlaier } 675130610Smlaier if (af == AF_INET && net2 > 32) 676130610Smlaier net2 = 32; 677130610Smlaier if (flags & PFI_AFLAG_BROADCAST) 678130610Smlaier pfi_address_add(ia->ifa_broadaddr, af, net2); 679130610Smlaier else if (flags & PFI_AFLAG_PEER) 680130610Smlaier pfi_address_add(ia->ifa_dstaddr, af, net2); 681130610Smlaier else 682130610Smlaier pfi_address_add(ia->ifa_addr, af, net2); 683130610Smlaier } 684130610Smlaier} 685130610Smlaier 686130610Smlaiervoid 687130610Smlaierpfi_address_add(struct sockaddr *sa, int af, int net) 688130610Smlaier{ 689130610Smlaier struct pfr_addr *p; 690130610Smlaier int i; 691130610Smlaier 692130610Smlaier if (pfi_buffer_cnt >= pfi_buffer_max) { 693130610Smlaier int new_max = pfi_buffer_max * 2; 694130610Smlaier 695130610Smlaier if (new_max > PFI_BUFFER_MAX) { 696130610Smlaier printf("pfi_address_add: address buffer full (%d/%d)\n", 697130610Smlaier pfi_buffer_cnt, PFI_BUFFER_MAX); 698130610Smlaier return; 699130610Smlaier } 700130613Smlaier#ifdef __FreeBSD__ 701130610Smlaier p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 702130613Smlaier M_NOWAIT); 703130613Smlaier#else 704130613Smlaier p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, 705130610Smlaier M_DONTWAIT); 706130613Smlaier#endif 707130610Smlaier if (p == NULL) { 708130610Smlaier printf("pfi_address_add: no memory to grow buffer " 709130610Smlaier "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); 710130610Smlaier return; 711130610Smlaier } 712130610Smlaier memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer)); 713130610Smlaier /* no need to zero buffer */ 714130610Smlaier free(pfi_buffer, PFI_MTYPE); 715130610Smlaier pfi_buffer = p; 716130610Smlaier pfi_buffer_max = new_max; 717130610Smlaier } 718130610Smlaier if (af == AF_INET && net > 32) 719130610Smlaier net = 128; 720130610Smlaier p = pfi_buffer + pfi_buffer_cnt++; 721130610Smlaier bzero(p, sizeof(*p)); 722130610Smlaier p->pfra_af = af; 723130610Smlaier p->pfra_net = net; 724130610Smlaier if (af == AF_INET) 725130610Smlaier p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr; 726130610Smlaier if (af == AF_INET6) { 727130610Smlaier p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr; 728130610Smlaier if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr)) 729130610Smlaier p->pfra_ip6addr.s6_addr16[1] = 0; 730130610Smlaier } 731130610Smlaier /* mask network address bits */ 732130610Smlaier if (net < 128) 733130610Smlaier ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8)); 734130610Smlaier for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++) 735130610Smlaier ((caddr_t)p)[i] = 0; 736130610Smlaier} 737130610Smlaier 738130610Smlaiervoid 739130610Smlaierpfi_dynaddr_remove(struct pf_addr_wrap *aw) 740130610Smlaier{ 741130610Smlaier int s; 742130610Smlaier 743130610Smlaier if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 744130610Smlaier aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL) 745130610Smlaier return; 746130610Smlaier 747130610Smlaier s = splsoftnet(); 748130610Smlaier hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head, 749130610Smlaier aw->p.dyn->pfid_hook_cookie); 750130610Smlaier pfi_detach_rule(aw->p.dyn->pfid_kif); 751130610Smlaier aw->p.dyn->pfid_kif = NULL; 752130610Smlaier pfr_detach_table(aw->p.dyn->pfid_kt); 753130610Smlaier aw->p.dyn->pfid_kt = NULL; 754130610Smlaier pool_put(&pfi_addr_pl, aw->p.dyn); 755130610Smlaier aw->p.dyn = NULL; 756130610Smlaier splx(s); 757130610Smlaier} 758130610Smlaier 759130610Smlaiervoid 760130610Smlaierpfi_dynaddr_copyout(struct pf_addr_wrap *aw) 761130610Smlaier{ 762130610Smlaier if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL || 763130610Smlaier aw->p.dyn->pfid_kif == NULL) 764130610Smlaier return; 765130610Smlaier aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6; 766130610Smlaier} 767130610Smlaier 768130610Smlaiervoid 769130610Smlaierpfi_kifaddr_update(void *v) 770130610Smlaier{ 771130610Smlaier int s; 772130610Smlaier 773130610Smlaier s = splsoftnet(); 774130610Smlaier pfi_update++; 775130610Smlaier pfi_dohooks(v); 776130610Smlaier splx(s); 777130610Smlaier} 778130610Smlaier 779130610Smlaierint 780130610Smlaierpfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) 781130610Smlaier{ 782130610Smlaier return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ)); 783130610Smlaier} 784130610Smlaier 785130610Smlaierstruct pfi_kif * 786130610Smlaierpfi_if_create(const char *name, struct pfi_kif *q, int flags) 787130610Smlaier{ 788130610Smlaier struct pfi_kif *p; 789130610Smlaier 790130613Smlaier#ifdef __FreeBSD__ 791130613Smlaier p = malloc(sizeof(*p), PFI_MTYPE, M_NOWAIT); 792130613Smlaier#else 793130610Smlaier p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT); 794130613Smlaier#endif 795130610Smlaier if (p == NULL) 796130610Smlaier return (NULL); 797130610Smlaier bzero(p, sizeof(*p)); 798130613Smlaier#ifdef __FreeBSD__ 799130610Smlaier p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, 800130613Smlaier M_NOWAIT); 801130613Smlaier#else 802130613Smlaier p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE, 803130610Smlaier M_DONTWAIT); 804130613Smlaier#endif 805130610Smlaier if (p->pfik_ah_head == NULL) { 806130610Smlaier free(p, PFI_MTYPE); 807130610Smlaier return (NULL); 808130610Smlaier } 809130610Smlaier bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head)); 810130610Smlaier TAILQ_INIT(p->pfik_ah_head); 811130610Smlaier TAILQ_INIT(&p->pfik_grouphead); 812130610Smlaier strlcpy(p->pfik_name, name, sizeof(p->pfik_name)); 813130610Smlaier RB_INIT(&p->pfik_lan_ext); 814130610Smlaier RB_INIT(&p->pfik_ext_gwy); 815130610Smlaier p->pfik_flags = flags; 816130610Smlaier p->pfik_parent = q; 817130613Smlaier#ifdef __FreeBSD__ 818130613Smlaier p->pfik_tzero = time_second; 819130613Smlaier#else 820130610Smlaier p->pfik_tzero = time.tv_sec; 821130613Smlaier#endif 822130610Smlaier 823130610Smlaier RB_INSERT(pfi_ifhead, &pfi_ifs, p); 824130610Smlaier if (q != NULL) { 825130610Smlaier q->pfik_addcnt++; 826130610Smlaier TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances); 827130610Smlaier } 828130610Smlaier pfi_ifcnt++; 829130610Smlaier return (p); 830130610Smlaier} 831130610Smlaier 832130610Smlaierint 833130610Smlaierpfi_maybe_destroy(struct pfi_kif *p) 834130610Smlaier{ 835130610Smlaier int i, j, k, s; 836130610Smlaier struct pfi_kif *q = p->pfik_parent; 837130610Smlaier 838130610Smlaier if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) || 839130610Smlaier p->pfik_rules > 0 || p->pfik_states > 0) 840130613Smlaier#ifdef __FreeBSD__ 841130613Smlaier if (!(p->pfik_flags & PFI_IFLAG_PLACEHOLDER)) 842130613Smlaier#endif 843130610Smlaier return (0); 844130610Smlaier 845130610Smlaier s = splsoftnet(); 846130610Smlaier if (q != NULL) { 847130610Smlaier for (i = 0; i < 2; i++) 848130610Smlaier for (j = 0; j < 2; j++) 849130610Smlaier for (k = 0; k < 2; k++) { 850130610Smlaier q->pfik_bytes[i][j][k] += 851130610Smlaier p->pfik_bytes[i][j][k]; 852130610Smlaier q->pfik_packets[i][j][k] += 853130610Smlaier p->pfik_packets[i][j][k]; 854130613Smlaier#ifdef __FreeBSD__ 855130613Smlaier /* clear stats in case we return to the dummy group */ 856130613Smlaier p->pfik_bytes[i][j][k] = 0; 857130613Smlaier p->pfik_packets[i][j][k] = 0; 858130613Smlaier#endif 859130610Smlaier } 860130610Smlaier q->pfik_delcnt++; 861130610Smlaier TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances); 862130610Smlaier } 863130613Smlaier#ifdef __FreeBSD__ 864130613Smlaier if (p->pfik_rules > 0 || p->pfik_states > 0) { 865130613Smlaier /* move back to the dummy group */ 866130613Smlaier p->pfik_parent = pfi_dummy; 867130613Smlaier pfi_dummy->pfik_addcnt++; 868130613Smlaier TAILQ_INSERT_TAIL(&pfi_dummy->pfik_grouphead, p, 869130613Smlaier pfik_instances); 870130613Smlaier return (0); 871130613Smlaier } 872130613Smlaier#endif 873130610Smlaier pfi_ifcnt--; 874130610Smlaier RB_REMOVE(pfi_ifhead, &pfi_ifs, p); 875130610Smlaier splx(s); 876130610Smlaier 877130610Smlaier free(p->pfik_ah_head, PFI_MTYPE); 878130610Smlaier free(p, PFI_MTYPE); 879130610Smlaier return (1); 880130610Smlaier} 881130610Smlaier 882130610Smlaiervoid 883130610Smlaierpfi_copy_group(char *p, const char *q, int m) 884130610Smlaier{ 885130610Smlaier while (m > 1 && *q && !(*q >= '0' && *q <= '9')) { 886130610Smlaier *p++ = *q++; 887130610Smlaier m--; 888130610Smlaier } 889130610Smlaier if (m > 0) 890130610Smlaier *p++ = '\0'; 891130610Smlaier} 892130610Smlaier 893130610Smlaiervoid 894130610Smlaierpfi_dynamic_drivers(void) 895130610Smlaier{ 896130613Smlaier#ifdef __FreeBSD__ 897130613Smlaier struct ifnet *ifp; 898130613Smlaier 899130613Smlaier/* 900130613Smlaier * For FreeBSD basically every interface is "dynamic" as we can unload 901130613Smlaier * modules e.g. 902130613Smlaier */ 903130613Smlaier 904130613Smlaier IFNET_RLOCK(); 905130613Smlaier TAILQ_FOREACH(ifp, &ifnet, if_link) { 906130613Smlaier if (ifp->if_dunit == IF_DUNIT_NONE) 907130613Smlaier continue; 908130613Smlaier pfi_newgroup(ifp->if_dname, PFI_IFLAG_DYNAMIC); 909130613Smlaier } 910130613Smlaier IFNET_RUNLOCK(); 911130613Smlaier#else 912130610Smlaier char *buses[] = PFI_DYNAMIC_BUSES; 913130610Smlaier int nbuses = sizeof(buses)/sizeof(buses[0]); 914130610Smlaier int enabled[sizeof(buses)/sizeof(buses[0])]; 915130610Smlaier struct device *dev; 916130610Smlaier struct cfdata *cf; 917130610Smlaier struct cfdriver *drv; 918130610Smlaier short *p; 919130610Smlaier int i; 920130610Smlaier 921130610Smlaier bzero(enabled, sizeof(enabled)); 922130610Smlaier TAILQ_FOREACH(dev, &alldevs, dv_list) { 923130610Smlaier if (!(dev->dv_flags & DVF_ACTIVE)) 924130610Smlaier continue; 925130610Smlaier for (i = 0; i < nbuses; i++) 926130610Smlaier if (!enabled[i] && !strcmp(buses[i], 927130610Smlaier dev->dv_cfdata->cf_driver->cd_name)) 928130610Smlaier enabled[i] = 1; 929130610Smlaier } 930130610Smlaier for (cf = cfdata; cf->cf_driver; cf++) { 931130610Smlaier if (cf->cf_driver->cd_class != DV_IFNET) 932130610Smlaier continue; 933130610Smlaier for (p = cf->cf_parents; p && *p >= 0; p++) { 934130610Smlaier if ((drv = cfdata[*p].cf_driver) == NULL) 935130610Smlaier continue; 936130610Smlaier for (i = 0; i < nbuses; i++) 937130610Smlaier if (enabled[i] && 938130610Smlaier !strcmp(drv->cd_name, buses[i])) 939130610Smlaier break; 940130610Smlaier if (i < nbuses) { 941130610Smlaier pfi_newgroup(cf->cf_driver->cd_name, 942130610Smlaier PFI_IFLAG_DYNAMIC); 943130610Smlaier break; 944130610Smlaier } 945130610Smlaier } 946130610Smlaier } 947130613Smlaier#endif 948130610Smlaier} 949130610Smlaier 950130610Smlaiervoid 951130610Smlaierpfi_newgroup(const char *name, int flags) 952130610Smlaier{ 953130610Smlaier struct pfi_kif *p; 954130610Smlaier 955130610Smlaier p = pfi_lookup_if(name); 956130610Smlaier if (p == NULL) 957130610Smlaier p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP); 958130610Smlaier if (p == NULL) { 959130610Smlaier printf("pfi_newgroup: cannot allocate '%s' group", name); 960130610Smlaier return; 961130610Smlaier } 962130610Smlaier p->pfik_flags |= flags; 963130610Smlaier} 964130610Smlaier 965130610Smlaiervoid 966130610Smlaierpfi_fill_oldstatus(struct pf_status *pfs) 967130610Smlaier{ 968130610Smlaier struct pfi_kif *p, key; 969130610Smlaier int i, j, k, s; 970130610Smlaier 971130610Smlaier strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); 972130610Smlaier s = splsoftnet(); 973130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 974130610Smlaier if (p == NULL) { 975130610Smlaier splx(s); 976130610Smlaier return; 977130610Smlaier } 978130610Smlaier bzero(pfs->pcounters, sizeof(pfs->pcounters)); 979130610Smlaier bzero(pfs->bcounters, sizeof(pfs->bcounters)); 980130610Smlaier for (i = 0; i < 2; i++) 981130610Smlaier for (j = 0; j < 2; j++) 982130610Smlaier for (k = 0; k < 2; k++) { 983130610Smlaier pfs->pcounters[i][j][k] = 984130610Smlaier p->pfik_packets[i][j][k]; 985130610Smlaier pfs->bcounters[i][j] += 986130610Smlaier p->pfik_bytes[i][j][k]; 987130610Smlaier } 988130610Smlaier splx(s); 989130610Smlaier} 990130610Smlaier 991130610Smlaierint 992130610Smlaierpfi_clr_istats(const char *name, int *nzero, int flags) 993130610Smlaier{ 994130610Smlaier struct pfi_kif *p; 995130610Smlaier int n = 0, s; 996130613Smlaier#ifdef __FreeBSD__ 997130613Smlaier long tzero = time_second; 998130613Smlaier#else 999130610Smlaier long tzero = time.tv_sec; 1000130613Smlaier#endif 1001130610Smlaier 1002130610Smlaier s = splsoftnet(); 1003130610Smlaier ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 1004130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 1005130610Smlaier if (pfi_skip_if(name, p, flags)) 1006130610Smlaier continue; 1007130610Smlaier bzero(p->pfik_packets, sizeof(p->pfik_packets)); 1008130610Smlaier bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); 1009130610Smlaier p->pfik_tzero = tzero; 1010130610Smlaier n++; 1011130610Smlaier } 1012130610Smlaier splx(s); 1013130610Smlaier if (nzero != NULL) 1014130610Smlaier *nzero = n; 1015130610Smlaier return (0); 1016130610Smlaier} 1017130610Smlaier 1018130610Smlaierint 1019130610Smlaierpfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags) 1020130610Smlaier{ 1021130610Smlaier struct pfi_kif *p; 1022130610Smlaier int s, n = 0; 1023130613Smlaier#ifdef __FreeBSD__ 1024130613Smlaier int ec; 1025130613Smlaier#endif 1026130610Smlaier 1027130610Smlaier ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE); 1028130610Smlaier s = splsoftnet(); 1029130610Smlaier RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { 1030130610Smlaier if (pfi_skip_if(name, p, flags)) 1031130610Smlaier continue; 1032130610Smlaier if (*size > n++) { 1033130610Smlaier if (!p->pfik_tzero) 1034130610Smlaier p->pfik_tzero = boottime.tv_sec; 1035130613Smlaier#ifdef __FreeBSD__ 1036130613Smlaier PF_COPYOUT(p, buf++, sizeof(*buf), ec); 1037130613Smlaier if (ec) { 1038130613Smlaier#else 1039130610Smlaier if (copyout(p, buf++, sizeof(*buf))) { 1040130613Smlaier#endif 1041130610Smlaier splx(s); 1042130610Smlaier return (EFAULT); 1043130610Smlaier } 1044130610Smlaier } 1045130610Smlaier } 1046130610Smlaier splx(s); 1047130610Smlaier *size = n; 1048130610Smlaier return (0); 1049130610Smlaier} 1050130610Smlaier 1051130610Smlaierstruct pfi_kif * 1052130610Smlaierpfi_lookup_if(const char *name) 1053130610Smlaier{ 1054130610Smlaier struct pfi_kif *p, key; 1055130610Smlaier 1056130610Smlaier strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); 1057130610Smlaier p = RB_FIND(pfi_ifhead, &pfi_ifs, &key); 1058130610Smlaier return (p); 1059130610Smlaier} 1060130610Smlaier 1061130610Smlaierint 1062130610Smlaierpfi_skip_if(const char *filter, struct pfi_kif *p, int f) 1063130610Smlaier{ 1064130610Smlaier int n; 1065130610Smlaier 1066130610Smlaier if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP)) 1067130610Smlaier return (1); 1068130610Smlaier if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE)) 1069130610Smlaier return (1); 1070130610Smlaier if (filter == NULL || !*filter) 1071130610Smlaier return (0); 1072130610Smlaier if (!strcmp(p->pfik_name, filter)) 1073130610Smlaier return (0); /* exact match */ 1074130610Smlaier n = strlen(filter); 1075130610Smlaier if (n < 1 || n >= IFNAMSIZ) 1076130610Smlaier return (1); /* sanity check */ 1077130610Smlaier if (filter[n-1] >= '0' && filter[n-1] <= '9') 1078130610Smlaier return (1); /* only do exact match in that case */ 1079130610Smlaier if (strncmp(p->pfik_name, filter, n)) 1080130610Smlaier return (1); /* prefix doesn't match */ 1081130610Smlaier return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9'); 1082130610Smlaier} 1083130610Smlaier 1084130610Smlaier/* from pf_print_state.c */ 1085130610Smlaierint 1086130610Smlaierpfi_unmask(void *addr) 1087130610Smlaier{ 1088130610Smlaier struct pf_addr *m = addr; 1089130610Smlaier int i = 31, j = 0, b = 0; 1090130610Smlaier u_int32_t tmp; 1091130610Smlaier 1092130610Smlaier while (j < 4 && m->addr32[j] == 0xffffffff) { 1093130610Smlaier b += 32; 1094130610Smlaier j++; 1095130610Smlaier } 1096130610Smlaier if (j < 4) { 1097130610Smlaier tmp = ntohl(m->addr32[j]); 1098130610Smlaier for (i = 31; tmp & (1 << i); --i) 1099130610Smlaier b++; 1100130610Smlaier } 1101130610Smlaier return (b); 1102130610Smlaier} 1103130610Smlaier 1104130610Smlaiervoid 1105130610Smlaierpfi_dohooks(struct pfi_kif *p) 1106130610Smlaier{ 1107130610Smlaier for (; p != NULL; p = p->pfik_parent) 1108130610Smlaier dohooks(p->pfik_ah_head, 0); 1109130610Smlaier} 1110130610Smlaier 1111130610Smlaierint 1112130610Smlaierpfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af) 1113130610Smlaier{ 1114130610Smlaier if (af == AF_INET) { 1115130610Smlaier switch (dyn->pfid_acnt4) { 1116130610Smlaier case 0: 1117130610Smlaier return (0); 1118130610Smlaier case 1: 1119130610Smlaier return (PF_MATCHA(0, &dyn->pfid_addr4, 1120130610Smlaier &dyn->pfid_mask4, a, AF_INET)); 1121130610Smlaier default: 1122130610Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET)); 1123130610Smlaier } 1124130610Smlaier } else { 1125130610Smlaier switch (dyn->pfid_acnt6) { 1126130610Smlaier case 0: 1127130610Smlaier return (0); 1128130610Smlaier case 1: 1129130610Smlaier return (PF_MATCHA(0, &dyn->pfid_addr6, 1130130610Smlaier &dyn->pfid_mask6, a, AF_INET6)); 1131130610Smlaier default: 1132130610Smlaier return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6)); 1133130610Smlaier } 1134130610Smlaier } 1135130610Smlaier} 1136