10473fe8bSchristos /*- 20473fe8bSchristos * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. 30473fe8bSchristos * All rights reserved. 40473fe8bSchristos * 50473fe8bSchristos * This material is based upon work partially supported by The 60473fe8bSchristos * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 70473fe8bSchristos * 80473fe8bSchristos * Redistribution and use in source and binary forms, with or without 90473fe8bSchristos * modification, are permitted provided that the following conditions 100473fe8bSchristos * are met: 110473fe8bSchristos * 1. Redistributions of source code must retain the above copyright 120473fe8bSchristos * notice, this list of conditions and the following disclaimer. 130473fe8bSchristos * 2. Redistributions in binary form must reproduce the above copyright 140473fe8bSchristos * notice, this list of conditions and the following disclaimer in the 150473fe8bSchristos * documentation and/or other materials provided with the distribution. 160473fe8bSchristos * 170473fe8bSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 180473fe8bSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 190473fe8bSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 200473fe8bSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 210473fe8bSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 220473fe8bSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 230473fe8bSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 240473fe8bSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 250473fe8bSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 260473fe8bSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 270473fe8bSchristos * POSSIBILITY OF SUCH DAMAGE. 280473fe8bSchristos */ 290473fe8bSchristos 300473fe8bSchristos /* 310473fe8bSchristos * NPF main: dynamic load/initialisation and unload routines. 320473fe8bSchristos */ 330473fe8bSchristos 340473fe8bSchristos #ifdef _KERNEL 350473fe8bSchristos #include <sys/cdefs.h> 36*d6939920Srmind __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.18 2020/05/30 14:16:56 rmind Exp $"); 370473fe8bSchristos 380473fe8bSchristos #ifdef _KERNEL_OPT 390473fe8bSchristos #include "pf.h" 400473fe8bSchristos #if NPF > 0 410473fe8bSchristos #error "NPF and PF are mutually exclusive; please select one" 420473fe8bSchristos #endif 430473fe8bSchristos #endif 440473fe8bSchristos 450473fe8bSchristos #include <sys/param.h> 460473fe8bSchristos #include <sys/types.h> 470473fe8bSchristos 480473fe8bSchristos #include <sys/conf.h> 490473fe8bSchristos #include <sys/kauth.h> 500473fe8bSchristos #include <sys/kmem.h> 510473fe8bSchristos #include <sys/lwp.h> 520473fe8bSchristos #include <sys/module.h> 5389fcc909Srmind #include <sys/pserialize.h> 540473fe8bSchristos #include <sys/socketvar.h> 550473fe8bSchristos #include <sys/uio.h> 563f49435dSchristos 573f49435dSchristos #include <netinet/in.h> 583f49435dSchristos #include <netinet6/in6_var.h> 590473fe8bSchristos #endif 600473fe8bSchristos 610473fe8bSchristos #include "npf_impl.h" 620473fe8bSchristos #include "npfkern.h" 630473fe8bSchristos 640473fe8bSchristos #ifdef _KERNEL 650473fe8bSchristos #ifndef _MODULE 660473fe8bSchristos #include "opt_modular.h" 673e90dadaSryo #include "opt_net_mpsafe.h" 680473fe8bSchristos #endif 690473fe8bSchristos #include "ioconf.h" 700473fe8bSchristos #endif 710473fe8bSchristos 720473fe8bSchristos /* 730473fe8bSchristos * Module and device structures. 740473fe8bSchristos */ 750473fe8bSchristos #ifndef _MODULE 760473fe8bSchristos /* 770473fe8bSchristos * Modular kernels load drivers too early, and we need percpu to be inited 780473fe8bSchristos * So we make this misc; a better way would be to have early boot and late 790473fe8bSchristos * boot drivers. 800473fe8bSchristos */ 81d96b1b21Spgoyette MODULE(MODULE_CLASS_MISC, npf, "bpf"); 820473fe8bSchristos #else 830473fe8bSchristos /* This module autoloads via /dev/npf so it needs to be a driver */ 84d96b1b21Spgoyette MODULE(MODULE_CLASS_DRIVER, npf, "bpf"); 850473fe8bSchristos #endif 860473fe8bSchristos 87*d6939920Srmind #define NPF_IOCTL_DATA_LIMIT (4 * 1024 * 1024) 88*d6939920Srmind 895fe51d8bSrmind static int npf_pfil_register(bool); 905fe51d8bSrmind static void npf_pfil_unregister(bool); 915fe51d8bSrmind 920473fe8bSchristos static int npf_dev_open(dev_t, int, int, lwp_t *); 930473fe8bSchristos static int npf_dev_close(dev_t, int, int, lwp_t *); 940473fe8bSchristos static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); 950473fe8bSchristos static int npf_dev_poll(dev_t, int, lwp_t *); 960473fe8bSchristos static int npf_dev_read(dev_t, struct uio *, int); 970473fe8bSchristos 980473fe8bSchristos const struct cdevsw npf_cdevsw = { 990473fe8bSchristos .d_open = npf_dev_open, 1000473fe8bSchristos .d_close = npf_dev_close, 1010473fe8bSchristos .d_read = npf_dev_read, 1020473fe8bSchristos .d_write = nowrite, 1030473fe8bSchristos .d_ioctl = npf_dev_ioctl, 1040473fe8bSchristos .d_stop = nostop, 1050473fe8bSchristos .d_tty = notty, 1060473fe8bSchristos .d_poll = npf_dev_poll, 1070473fe8bSchristos .d_mmap = nommap, 1080473fe8bSchristos .d_kqfilter = nokqfilter, 1090473fe8bSchristos .d_discard = nodiscard, 1100473fe8bSchristos .d_flag = D_OTHER | D_MPSAFE 1110473fe8bSchristos }; 1120473fe8bSchristos 113*d6939920Srmind static const char * npf_ifop_getname(npf_t *, ifnet_t *); 114*d6939920Srmind static ifnet_t * npf_ifop_lookup(npf_t *, const char *); 115*d6939920Srmind static void npf_ifop_flush(npf_t *, void *); 116*d6939920Srmind static void * npf_ifop_getmeta(npf_t *, const ifnet_t *); 117*d6939920Srmind static void npf_ifop_setmeta(npf_t *, ifnet_t *, void *); 1180473fe8bSchristos 1190473fe8bSchristos static const unsigned nworkers = 1; 1200473fe8bSchristos 1210473fe8bSchristos static bool pfil_registered = false; 1220473fe8bSchristos static pfil_head_t * npf_ph_if = NULL; 1230473fe8bSchristos static pfil_head_t * npf_ph_inet = NULL; 1240473fe8bSchristos static pfil_head_t * npf_ph_inet6 = NULL; 1250473fe8bSchristos 1260473fe8bSchristos static const npf_ifops_t kern_ifops = { 1270473fe8bSchristos .getname = npf_ifop_getname, 1280473fe8bSchristos .lookup = npf_ifop_lookup, 1290473fe8bSchristos .flush = npf_ifop_flush, 1300473fe8bSchristos .getmeta = npf_ifop_getmeta, 1310473fe8bSchristos .setmeta = npf_ifop_setmeta, 1320473fe8bSchristos }; 1330473fe8bSchristos 1340473fe8bSchristos static int 1350473fe8bSchristos npf_fini(void) 1360473fe8bSchristos { 1370473fe8bSchristos npf_t *npf = npf_getkernctx(); 1380473fe8bSchristos 1390473fe8bSchristos /* At first, detach device and remove pfil hooks. */ 1400473fe8bSchristos #ifdef _MODULE 1410473fe8bSchristos devsw_detach(NULL, &npf_cdevsw); 1420473fe8bSchristos #endif 1430473fe8bSchristos npf_pfil_unregister(true); 14404394ddeSrmind npfk_destroy(npf); 14504394ddeSrmind npfk_sysfini(); 1460473fe8bSchristos return 0; 1470473fe8bSchristos } 1480473fe8bSchristos 1490473fe8bSchristos static int 1500473fe8bSchristos npf_init(void) 1510473fe8bSchristos { 1520473fe8bSchristos npf_t *npf; 1530473fe8bSchristos int error = 0; 1540473fe8bSchristos 15504394ddeSrmind error = npfk_sysinit(nworkers); 1560473fe8bSchristos if (error) 1570473fe8bSchristos return error; 158*d6939920Srmind npf = npfk_create(0, NULL, &kern_ifops, NULL); 1590473fe8bSchristos npf_setkernctx(npf); 1600473fe8bSchristos npf_pfil_register(true); 1610473fe8bSchristos 1620473fe8bSchristos #ifdef _MODULE 1630473fe8bSchristos devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 1640473fe8bSchristos 1650473fe8bSchristos /* Attach /dev/npf device. */ 1660473fe8bSchristos error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 1670473fe8bSchristos if (error) { 1680473fe8bSchristos /* It will call devsw_detach(), which is safe. */ 1690473fe8bSchristos (void)npf_fini(); 1700473fe8bSchristos } 1710473fe8bSchristos #endif 1720473fe8bSchristos return error; 1730473fe8bSchristos } 1740473fe8bSchristos 1750473fe8bSchristos 1760473fe8bSchristos /* 1770473fe8bSchristos * Module interface. 1780473fe8bSchristos */ 1790473fe8bSchristos static int 1800473fe8bSchristos npf_modcmd(modcmd_t cmd, void *arg) 1810473fe8bSchristos { 1820473fe8bSchristos switch (cmd) { 1830473fe8bSchristos case MODULE_CMD_INIT: 1840473fe8bSchristos return npf_init(); 1850473fe8bSchristos case MODULE_CMD_FINI: 1860473fe8bSchristos return npf_fini(); 1870473fe8bSchristos case MODULE_CMD_AUTOUNLOAD: 1880473fe8bSchristos if (npf_autounload_p()) { 1890473fe8bSchristos return EBUSY; 1900473fe8bSchristos } 1910473fe8bSchristos break; 1920473fe8bSchristos default: 1930473fe8bSchristos return ENOTTY; 1940473fe8bSchristos } 1950473fe8bSchristos return 0; 1960473fe8bSchristos } 1970473fe8bSchristos 1980473fe8bSchristos void 1990473fe8bSchristos npfattach(int nunits) 2000473fe8bSchristos { 2010473fe8bSchristos /* Nothing */ 2020473fe8bSchristos } 2030473fe8bSchristos 2040473fe8bSchristos static int 2050473fe8bSchristos npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 2060473fe8bSchristos { 2070473fe8bSchristos /* Available only for super-user. */ 2080473fe8bSchristos if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 2090473fe8bSchristos KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 2100473fe8bSchristos return EPERM; 2110473fe8bSchristos } 2120473fe8bSchristos return 0; 2130473fe8bSchristos } 2140473fe8bSchristos 2150473fe8bSchristos static int 2160473fe8bSchristos npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 2170473fe8bSchristos { 2180473fe8bSchristos return 0; 2190473fe8bSchristos } 2200473fe8bSchristos 2210473fe8bSchristos static int 2220473fe8bSchristos npf_stats_export(npf_t *npf, void *data) 2230473fe8bSchristos { 2240473fe8bSchristos uint64_t *fullst, *uptr = *(uint64_t **)data; 2250473fe8bSchristos int error; 2260473fe8bSchristos 2270473fe8bSchristos fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); 22804394ddeSrmind npfk_stats(npf, fullst); /* will zero the buffer */ 2290473fe8bSchristos error = copyout(fullst, uptr, NPF_STATS_SIZE); 2300473fe8bSchristos kmem_free(fullst, NPF_STATS_SIZE); 2310473fe8bSchristos return error; 2320473fe8bSchristos } 2330473fe8bSchristos 2345fe51d8bSrmind /* 2355fe51d8bSrmind * npfctl_switch: enable or disable packet inspection. 2365fe51d8bSrmind */ 2375fe51d8bSrmind static int 2385fe51d8bSrmind npfctl_switch(void *data) 2395fe51d8bSrmind { 2405fe51d8bSrmind const bool onoff = *(int *)data ? true : false; 2415fe51d8bSrmind int error; 2425fe51d8bSrmind 2435fe51d8bSrmind if (onoff) { 2445fe51d8bSrmind /* Enable: add pfil hooks. */ 2455fe51d8bSrmind error = npf_pfil_register(false); 2465fe51d8bSrmind } else { 2475fe51d8bSrmind /* Disable: remove pfil hooks. */ 2485fe51d8bSrmind npf_pfil_unregister(false); 2495fe51d8bSrmind error = 0; 2505fe51d8bSrmind } 2515fe51d8bSrmind return error; 2525fe51d8bSrmind } 2535fe51d8bSrmind 2540473fe8bSchristos static int 2550473fe8bSchristos npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 2560473fe8bSchristos { 2570473fe8bSchristos npf_t *npf = npf_getkernctx(); 258*d6939920Srmind nvlist_t *req, *resp; 2590473fe8bSchristos int error; 2600473fe8bSchristos 2610473fe8bSchristos /* Available only for super-user. */ 2620473fe8bSchristos if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 2630473fe8bSchristos KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 2640473fe8bSchristos return EPERM; 2650473fe8bSchristos } 2660473fe8bSchristos 2670473fe8bSchristos switch (cmd) { 2680473fe8bSchristos case IOC_NPF_VERSION: 2690473fe8bSchristos *(int *)data = NPF_VERSION; 270*d6939920Srmind return 0; 271*d6939920Srmind 272*d6939920Srmind case IOC_NPF_SWITCH: 273*d6939920Srmind return npfctl_switch(data); 274*d6939920Srmind 275*d6939920Srmind case IOC_NPF_TABLE: 276*d6939920Srmind return npfctl_table(npf, data); 277*d6939920Srmind 278*d6939920Srmind case IOC_NPF_STATS: 279*d6939920Srmind return npf_stats_export(npf, data); 2800473fe8bSchristos } 281*d6939920Srmind 282*d6939920Srmind error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT); 283*d6939920Srmind if (__predict_false(error)) { 284*d6939920Srmind #ifdef __NetBSD__ 285*d6939920Srmind /* Until the version bump. */ 286*d6939920Srmind if (cmd != IOC_NPF_SAVE) { 287*d6939920Srmind return error; 288*d6939920Srmind } 289*d6939920Srmind req = nvlist_create(0); 290*d6939920Srmind #else 291*d6939920Srmind return error; 292*d6939920Srmind #endif 293*d6939920Srmind } 294*d6939920Srmind resp = nvlist_create(0); 295*d6939920Srmind npfctl_run_op(npf, cmd, req, resp); 296*d6939920Srmind error = nvlist_copyout(data, resp); 297*d6939920Srmind nvlist_destroy(resp); 298*d6939920Srmind nvlist_destroy(req); 299*d6939920Srmind 3000473fe8bSchristos return error; 3010473fe8bSchristos } 3020473fe8bSchristos 3030473fe8bSchristos static int 3040473fe8bSchristos npf_dev_poll(dev_t dev, int events, lwp_t *l) 3050473fe8bSchristos { 3060473fe8bSchristos return ENOTSUP; 3070473fe8bSchristos } 3080473fe8bSchristos 3090473fe8bSchristos static int 3100473fe8bSchristos npf_dev_read(dev_t dev, struct uio *uio, int flag) 3110473fe8bSchristos { 3120473fe8bSchristos return ENOTSUP; 3130473fe8bSchristos } 3140473fe8bSchristos 3150473fe8bSchristos bool 3160473fe8bSchristos npf_autounload_p(void) 3170473fe8bSchristos { 3180473fe8bSchristos npf_t *npf = npf_getkernctx(); 3195fe51d8bSrmind return !npf_active_p() && npf_default_pass(npf); 3200473fe8bSchristos } 3210473fe8bSchristos 3220473fe8bSchristos /* 3230473fe8bSchristos * Interface operations. 3240473fe8bSchristos */ 3250473fe8bSchristos 3260473fe8bSchristos static const char * 327*d6939920Srmind npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp) 3280473fe8bSchristos { 3290473fe8bSchristos return ifp->if_xname; 3300473fe8bSchristos } 3310473fe8bSchristos 3320473fe8bSchristos static ifnet_t * 333*d6939920Srmind npf_ifop_lookup(npf_t *npf __unused, const char *name) 3340473fe8bSchristos { 3350473fe8bSchristos return ifunit(name); 3360473fe8bSchristos } 3370473fe8bSchristos 3380473fe8bSchristos static void 339*d6939920Srmind npf_ifop_flush(npf_t *npf __unused, void *arg) 3400473fe8bSchristos { 3410473fe8bSchristos ifnet_t *ifp; 3420473fe8bSchristos 3430473fe8bSchristos KERNEL_LOCK(1, NULL); 344cd7839aaSozaki-r IFNET_GLOBAL_LOCK(); 3450473fe8bSchristos IFNET_WRITER_FOREACH(ifp) { 3460181d9c1Srmind ifp->if_npf_private = arg; 3470473fe8bSchristos } 348cd7839aaSozaki-r IFNET_GLOBAL_UNLOCK(); 3490473fe8bSchristos KERNEL_UNLOCK_ONE(NULL); 3500473fe8bSchristos } 3510473fe8bSchristos 3520473fe8bSchristos static void * 353*d6939920Srmind npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp) 3540473fe8bSchristos { 3550181d9c1Srmind return ifp->if_npf_private; 3560473fe8bSchristos } 3570473fe8bSchristos 3580473fe8bSchristos static void 359*d6939920Srmind npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg) 3600473fe8bSchristos { 3610181d9c1Srmind ifp->if_npf_private = arg; 3620473fe8bSchristos } 3630473fe8bSchristos 3640473fe8bSchristos #ifdef _KERNEL 3650473fe8bSchristos 3660473fe8bSchristos /* 3670473fe8bSchristos * Wrapper of the main packet handler to pass the kernel NPF context. 3680473fe8bSchristos */ 3690473fe8bSchristos static int 37004394ddeSrmind npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 3710473fe8bSchristos { 3720473fe8bSchristos npf_t *npf = npf_getkernctx(); 37304394ddeSrmind return npfk_packet_handler(npf, mp, ifp, di); 3740473fe8bSchristos } 3750473fe8bSchristos 3760473fe8bSchristos /* 3770473fe8bSchristos * npf_ifhook: hook handling interface changes. 3780473fe8bSchristos */ 379dd73807fSrmind static void 380dd73807fSrmind npf_ifhook(void *arg, unsigned long cmd, void *arg2) 3810473fe8bSchristos { 3820473fe8bSchristos npf_t *npf = npf_getkernctx(); 383dd73807fSrmind ifnet_t *ifp = arg2; 3840473fe8bSchristos 3850473fe8bSchristos switch (cmd) { 3860473fe8bSchristos case PFIL_IFNET_ATTACH: 38704394ddeSrmind npfk_ifmap_attach(npf, ifp); 388739852eaSrmind npf_ifaddr_sync(npf, ifp); 3890473fe8bSchristos break; 3900473fe8bSchristos case PFIL_IFNET_DETACH: 39104394ddeSrmind npfk_ifmap_detach(npf, ifp); 392739852eaSrmind npf_ifaddr_flush(npf, ifp); 3930473fe8bSchristos break; 3940473fe8bSchristos } 3950473fe8bSchristos } 3960473fe8bSchristos 397739852eaSrmind static void 398739852eaSrmind npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 399739852eaSrmind { 400739852eaSrmind npf_t *npf = npf_getkernctx(); 401739852eaSrmind struct ifaddr *ifa = arg2; 402739852eaSrmind 403739852eaSrmind switch (cmd) { 404739852eaSrmind case SIOCSIFADDR: 405739852eaSrmind case SIOCAIFADDR: 406739852eaSrmind case SIOCDIFADDR: 407739852eaSrmind #ifdef INET6 408739852eaSrmind case SIOCSIFADDR_IN6: 409739852eaSrmind case SIOCAIFADDR_IN6: 410739852eaSrmind case SIOCDIFADDR_IN6: 411739852eaSrmind #endif 4127e3fb338Srmind KASSERT(ifa != NULL); 413739852eaSrmind break; 414739852eaSrmind default: 415739852eaSrmind return; 416739852eaSrmind } 417739852eaSrmind npf_ifaddr_sync(npf, ifa->ifa_ifp); 418739852eaSrmind } 419739852eaSrmind 4200473fe8bSchristos /* 4210473fe8bSchristos * npf_pfil_register: register pfil(9) hooks. 4220473fe8bSchristos */ 4235fe51d8bSrmind static int 4240473fe8bSchristos npf_pfil_register(bool init) 4250473fe8bSchristos { 4260473fe8bSchristos npf_t *npf = npf_getkernctx(); 4270473fe8bSchristos int error = 0; 4280473fe8bSchristos 429a5d1c1f4Sozaki-r SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 4300473fe8bSchristos 4310473fe8bSchristos /* Init: interface re-config and attach/detach hook. */ 4320473fe8bSchristos if (!npf_ph_if) { 4330473fe8bSchristos npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 4340473fe8bSchristos if (!npf_ph_if) { 4350473fe8bSchristos error = ENOENT; 4360473fe8bSchristos goto out; 4370473fe8bSchristos } 438739852eaSrmind 439739852eaSrmind error = pfil_add_ihook(npf_ifhook, NULL, 440739852eaSrmind PFIL_IFNET, npf_ph_if); 441739852eaSrmind KASSERT(error == 0); 442739852eaSrmind 443739852eaSrmind error = pfil_add_ihook(npf_ifaddrhook, NULL, 444739852eaSrmind PFIL_IFADDR, npf_ph_if); 4450473fe8bSchristos KASSERT(error == 0); 4460473fe8bSchristos } 4470473fe8bSchristos if (init) { 4480473fe8bSchristos goto out; 4490473fe8bSchristos } 4500473fe8bSchristos 4510473fe8bSchristos /* Check if pfil hooks are not already registered. */ 4520473fe8bSchristos if (pfil_registered) { 4530473fe8bSchristos error = EEXIST; 4540473fe8bSchristos goto out; 4550473fe8bSchristos } 4560473fe8bSchristos 4570473fe8bSchristos /* Capture points of the activity in the IP layer. */ 4580473fe8bSchristos npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 4590473fe8bSchristos npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 4600473fe8bSchristos if (!npf_ph_inet && !npf_ph_inet6) { 4610473fe8bSchristos error = ENOENT; 4620473fe8bSchristos goto out; 4630473fe8bSchristos } 4640473fe8bSchristos 4650473fe8bSchristos /* Packet IN/OUT handlers for IP layer. */ 4660473fe8bSchristos if (npf_ph_inet) { 46704394ddeSrmind error = pfil_add_hook(npfos_packet_handler, npf, 4680473fe8bSchristos PFIL_ALL, npf_ph_inet); 4690473fe8bSchristos KASSERT(error == 0); 4700473fe8bSchristos } 4710473fe8bSchristos if (npf_ph_inet6) { 47204394ddeSrmind error = pfil_add_hook(npfos_packet_handler, npf, 4730473fe8bSchristos PFIL_ALL, npf_ph_inet6); 4740473fe8bSchristos KASSERT(error == 0); 4750473fe8bSchristos } 47677408edbSrmind 47777408edbSrmind /* 47877408edbSrmind * It is necessary to re-sync all/any interface address tables, 47977408edbSrmind * since we did not listen for any changes. 48077408edbSrmind */ 48177408edbSrmind npf_ifaddr_syncall(npf); 4820473fe8bSchristos pfil_registered = true; 4830473fe8bSchristos out: 484a5d1c1f4Sozaki-r SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 4850473fe8bSchristos 4860473fe8bSchristos return error; 4870473fe8bSchristos } 4880473fe8bSchristos 4890473fe8bSchristos /* 4900473fe8bSchristos * npf_pfil_unregister: unregister pfil(9) hooks. 4910473fe8bSchristos */ 4925fe51d8bSrmind static void 4930473fe8bSchristos npf_pfil_unregister(bool fini) 4940473fe8bSchristos { 4950473fe8bSchristos npf_t *npf = npf_getkernctx(); 4960473fe8bSchristos 497a5d1c1f4Sozaki-r SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 4980473fe8bSchristos 4990473fe8bSchristos if (fini && npf_ph_if) { 500739852eaSrmind (void)pfil_remove_ihook(npf_ifhook, NULL, 501739852eaSrmind PFIL_IFNET, npf_ph_if); 502739852eaSrmind (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 503739852eaSrmind PFIL_IFADDR, npf_ph_if); 5040473fe8bSchristos } 5050473fe8bSchristos if (npf_ph_inet) { 50604394ddeSrmind (void)pfil_remove_hook(npfos_packet_handler, npf, 5070473fe8bSchristos PFIL_ALL, npf_ph_inet); 5080473fe8bSchristos } 5090473fe8bSchristos if (npf_ph_inet6) { 51004394ddeSrmind (void)pfil_remove_hook(npfos_packet_handler, npf, 5110473fe8bSchristos PFIL_ALL, npf_ph_inet6); 5120473fe8bSchristos } 5130473fe8bSchristos pfil_registered = false; 5140473fe8bSchristos 515a5d1c1f4Sozaki-r SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 5160473fe8bSchristos } 5170473fe8bSchristos 5180473fe8bSchristos bool 5195fe51d8bSrmind npf_active_p(void) 5200473fe8bSchristos { 5210473fe8bSchristos return pfil_registered; 5220473fe8bSchristos } 5235fe51d8bSrmind 5240473fe8bSchristos #endif 52589fcc909Srmind 52689fcc909Srmind #ifdef __NetBSD__ 52789fcc909Srmind 528*d6939920Srmind /* 529*d6939920Srmind * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the 530*d6939920Srmind * passive serialization mechanism (see pserialize(9) manual page), 531*d6939920Srmind * which provides sufficient guarantees for NPF. 532*d6939920Srmind */ 533*d6939920Srmind 53489fcc909Srmind ebr_t * 53589fcc909Srmind npf_ebr_create(void) 53689fcc909Srmind { 53789fcc909Srmind return pserialize_create(); 53889fcc909Srmind } 53989fcc909Srmind 54089fcc909Srmind void 54189fcc909Srmind npf_ebr_destroy(ebr_t *ebr) 54289fcc909Srmind { 54389fcc909Srmind pserialize_destroy(ebr); 54489fcc909Srmind } 54589fcc909Srmind 54689fcc909Srmind void 54789fcc909Srmind npf_ebr_register(ebr_t *ebr) 54889fcc909Srmind { 54989fcc909Srmind KASSERT(ebr != NULL); (void)ebr; 55089fcc909Srmind } 55189fcc909Srmind 55289fcc909Srmind void 55389fcc909Srmind npf_ebr_unregister(ebr_t *ebr) 55489fcc909Srmind { 55589fcc909Srmind KASSERT(ebr != NULL); (void)ebr; 55689fcc909Srmind } 55789fcc909Srmind 55889fcc909Srmind int 55989fcc909Srmind npf_ebr_enter(ebr_t *ebr) 56089fcc909Srmind { 56189fcc909Srmind KASSERT(ebr != NULL); (void)ebr; 56289fcc909Srmind return pserialize_read_enter(); 56389fcc909Srmind } 56489fcc909Srmind 56589fcc909Srmind void 56689fcc909Srmind npf_ebr_exit(ebr_t *ebr, int s) 56789fcc909Srmind { 56889fcc909Srmind KASSERT(ebr != NULL); (void)ebr; 56989fcc909Srmind pserialize_read_exit(s); 57089fcc909Srmind } 57189fcc909Srmind 57289fcc909Srmind void 57389fcc909Srmind npf_ebr_full_sync(ebr_t *ebr) 57489fcc909Srmind { 57589fcc909Srmind pserialize_perform(ebr); 57689fcc909Srmind } 57789fcc909Srmind 57889fcc909Srmind bool 57989fcc909Srmind npf_ebr_incrit_p(ebr_t *ebr) 58089fcc909Srmind { 58189fcc909Srmind KASSERT(ebr != NULL); (void)ebr; 58289fcc909Srmind return pserialize_in_read_section(); 58389fcc909Srmind } 58489fcc909Srmind 58589fcc909Srmind #endif 586