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*1c8452ddSchristos __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.21 2021/01/27 17:39:13 christos 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
87d6939920Srmind #define NPF_IOCTL_DATA_LIMIT (4 * 1024 * 1024)
88d6939920Srmind
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
113d6939920Srmind static const char * npf_ifop_getname(npf_t *, ifnet_t *);
114d6939920Srmind static ifnet_t * npf_ifop_lookup(npf_t *, const char *);
115d6939920Srmind static void npf_ifop_flush(npf_t *, void *);
116d6939920Srmind static void * npf_ifop_getmeta(npf_t *, const ifnet_t *);
117d6939920Srmind 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
npf_fini(void)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
npf_init(void)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;
158d6939920Srmind 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
npf_modcmd(modcmd_t cmd,void * arg)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
npfattach(int nunits)1990473fe8bSchristos npfattach(int nunits)
2000473fe8bSchristos {
2010473fe8bSchristos /* Nothing */
2020473fe8bSchristos }
2030473fe8bSchristos
2040473fe8bSchristos static int
npf_dev_open(dev_t dev,int flag,int mode,lwp_t * l)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
npf_dev_close(dev_t dev,int flag,int mode,lwp_t * l)2160473fe8bSchristos npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l)
2170473fe8bSchristos {
2180473fe8bSchristos return 0;
2190473fe8bSchristos }
2200473fe8bSchristos
2210473fe8bSchristos static int
npf_stats_export(npf_t * npf,void * data)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
npfctl_switch(void * data)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
npf_dev_ioctl(dev_t dev,u_long cmd,void * data,int flag,lwp_t * l)2550473fe8bSchristos npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
2560473fe8bSchristos {
2570473fe8bSchristos npf_t *npf = npf_getkernctx();
258d6939920Srmind 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;
270d6939920Srmind return 0;
271d6939920Srmind case IOC_NPF_SWITCH:
272d6939920Srmind return npfctl_switch(data);
273d6939920Srmind case IOC_NPF_TABLE:
274d6939920Srmind return npfctl_table(npf, data);
275d6939920Srmind case IOC_NPF_STATS:
276d6939920Srmind return npf_stats_export(npf, data);
2776982a35fSmaxv case IOC_NPF_LOAD:
2786982a35fSmaxv case IOC_NPF_SAVE:
2796982a35fSmaxv case IOC_NPF_RULE:
2806982a35fSmaxv case IOC_NPF_CONN_LOOKUP:
2816982a35fSmaxv case IOC_NPF_TABLE_REPLACE:
2826982a35fSmaxv /* nvlist_ref_t argument, handled below */
2836982a35fSmaxv break;
2846982a35fSmaxv default:
2856982a35fSmaxv return EINVAL;
2860473fe8bSchristos }
287d6939920Srmind
288d6939920Srmind error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT);
289d6939920Srmind if (__predict_false(error)) {
290d6939920Srmind #ifdef __NetBSD__
291d6939920Srmind /* Until the version bump. */
292d6939920Srmind if (cmd != IOC_NPF_SAVE) {
293d6939920Srmind return error;
294d6939920Srmind }
295d6939920Srmind req = nvlist_create(0);
296d6939920Srmind #else
297d6939920Srmind return error;
298d6939920Srmind #endif
299d6939920Srmind }
300d6939920Srmind resp = nvlist_create(0);
301*1c8452ddSchristos
302*1c8452ddSchristos if ((error = npfctl_run_op(npf, cmd, req, resp)) == 0) {
303d6939920Srmind error = nvlist_copyout(data, resp);
304*1c8452ddSchristos }
305*1c8452ddSchristos
306d6939920Srmind nvlist_destroy(resp);
307d6939920Srmind nvlist_destroy(req);
308d6939920Srmind
3090473fe8bSchristos return error;
3100473fe8bSchristos }
3110473fe8bSchristos
3120473fe8bSchristos static int
npf_dev_poll(dev_t dev,int events,lwp_t * l)3130473fe8bSchristos npf_dev_poll(dev_t dev, int events, lwp_t *l)
3140473fe8bSchristos {
3150473fe8bSchristos return ENOTSUP;
3160473fe8bSchristos }
3170473fe8bSchristos
3180473fe8bSchristos static int
npf_dev_read(dev_t dev,struct uio * uio,int flag)3190473fe8bSchristos npf_dev_read(dev_t dev, struct uio *uio, int flag)
3200473fe8bSchristos {
3210473fe8bSchristos return ENOTSUP;
3220473fe8bSchristos }
3230473fe8bSchristos
3240473fe8bSchristos bool
npf_autounload_p(void)3250473fe8bSchristos npf_autounload_p(void)
3260473fe8bSchristos {
32736b68e28Schristos if (npf_active_p())
32836b68e28Schristos return false;
32936b68e28Schristos
3300473fe8bSchristos npf_t *npf = npf_getkernctx();
33136b68e28Schristos
33236b68e28Schristos npf_config_enter(npf);
33336b68e28Schristos bool pass = npf_default_pass(npf);
33436b68e28Schristos npf_config_exit(npf);
33536b68e28Schristos
33636b68e28Schristos return pass;
3370473fe8bSchristos }
3380473fe8bSchristos
3390473fe8bSchristos /*
3400473fe8bSchristos * Interface operations.
3410473fe8bSchristos */
3420473fe8bSchristos
3430473fe8bSchristos static const char *
npf_ifop_getname(npf_t * npf __unused,ifnet_t * ifp)344d6939920Srmind npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp)
3450473fe8bSchristos {
3460473fe8bSchristos return ifp->if_xname;
3470473fe8bSchristos }
3480473fe8bSchristos
3490473fe8bSchristos static ifnet_t *
npf_ifop_lookup(npf_t * npf __unused,const char * name)350d6939920Srmind npf_ifop_lookup(npf_t *npf __unused, const char *name)
3510473fe8bSchristos {
3520473fe8bSchristos return ifunit(name);
3530473fe8bSchristos }
3540473fe8bSchristos
3550473fe8bSchristos static void
npf_ifop_flush(npf_t * npf __unused,void * arg)356d6939920Srmind npf_ifop_flush(npf_t *npf __unused, void *arg)
3570473fe8bSchristos {
3580473fe8bSchristos ifnet_t *ifp;
3590473fe8bSchristos
3600473fe8bSchristos KERNEL_LOCK(1, NULL);
361cd7839aaSozaki-r IFNET_GLOBAL_LOCK();
3620473fe8bSchristos IFNET_WRITER_FOREACH(ifp) {
3630181d9c1Srmind ifp->if_npf_private = arg;
3640473fe8bSchristos }
365cd7839aaSozaki-r IFNET_GLOBAL_UNLOCK();
3660473fe8bSchristos KERNEL_UNLOCK_ONE(NULL);
3670473fe8bSchristos }
3680473fe8bSchristos
3690473fe8bSchristos static void *
npf_ifop_getmeta(npf_t * npf __unused,const ifnet_t * ifp)370d6939920Srmind npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp)
3710473fe8bSchristos {
3720181d9c1Srmind return ifp->if_npf_private;
3730473fe8bSchristos }
3740473fe8bSchristos
3750473fe8bSchristos static void
npf_ifop_setmeta(npf_t * npf __unused,ifnet_t * ifp,void * arg)376d6939920Srmind npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg)
3770473fe8bSchristos {
3780181d9c1Srmind ifp->if_npf_private = arg;
3790473fe8bSchristos }
3800473fe8bSchristos
3810473fe8bSchristos #ifdef _KERNEL
3820473fe8bSchristos
3830473fe8bSchristos /*
3840473fe8bSchristos * Wrapper of the main packet handler to pass the kernel NPF context.
3850473fe8bSchristos */
3860473fe8bSchristos static int
npfos_packet_handler(void * arg,struct mbuf ** mp,ifnet_t * ifp,int di)38704394ddeSrmind npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
3880473fe8bSchristos {
3890473fe8bSchristos npf_t *npf = npf_getkernctx();
39004394ddeSrmind return npfk_packet_handler(npf, mp, ifp, di);
3910473fe8bSchristos }
3920473fe8bSchristos
3930473fe8bSchristos /*
3940473fe8bSchristos * npf_ifhook: hook handling interface changes.
3950473fe8bSchristos */
396dd73807fSrmind static void
npf_ifhook(void * arg,unsigned long cmd,void * arg2)397dd73807fSrmind npf_ifhook(void *arg, unsigned long cmd, void *arg2)
3980473fe8bSchristos {
3990473fe8bSchristos npf_t *npf = npf_getkernctx();
400dd73807fSrmind ifnet_t *ifp = arg2;
4010473fe8bSchristos
4020473fe8bSchristos switch (cmd) {
4030473fe8bSchristos case PFIL_IFNET_ATTACH:
40404394ddeSrmind npfk_ifmap_attach(npf, ifp);
405739852eaSrmind npf_ifaddr_sync(npf, ifp);
4060473fe8bSchristos break;
4070473fe8bSchristos case PFIL_IFNET_DETACH:
40804394ddeSrmind npfk_ifmap_detach(npf, ifp);
409739852eaSrmind npf_ifaddr_flush(npf, ifp);
4100473fe8bSchristos break;
4110473fe8bSchristos }
4120473fe8bSchristos }
4130473fe8bSchristos
414739852eaSrmind static void
npf_ifaddrhook(void * arg,u_long cmd,void * arg2)415739852eaSrmind npf_ifaddrhook(void *arg, u_long cmd, void *arg2)
416739852eaSrmind {
417739852eaSrmind npf_t *npf = npf_getkernctx();
418739852eaSrmind struct ifaddr *ifa = arg2;
419739852eaSrmind
420739852eaSrmind switch (cmd) {
421739852eaSrmind case SIOCSIFADDR:
422739852eaSrmind case SIOCAIFADDR:
423739852eaSrmind case SIOCDIFADDR:
424739852eaSrmind #ifdef INET6
425739852eaSrmind case SIOCSIFADDR_IN6:
426739852eaSrmind case SIOCAIFADDR_IN6:
427739852eaSrmind case SIOCDIFADDR_IN6:
428739852eaSrmind #endif
4297e3fb338Srmind KASSERT(ifa != NULL);
430739852eaSrmind break;
431739852eaSrmind default:
432739852eaSrmind return;
433739852eaSrmind }
434739852eaSrmind npf_ifaddr_sync(npf, ifa->ifa_ifp);
435739852eaSrmind }
436739852eaSrmind
4370473fe8bSchristos /*
4380473fe8bSchristos * npf_pfil_register: register pfil(9) hooks.
4390473fe8bSchristos */
4405fe51d8bSrmind static int
npf_pfil_register(bool init)4410473fe8bSchristos npf_pfil_register(bool init)
4420473fe8bSchristos {
4430473fe8bSchristos npf_t *npf = npf_getkernctx();
4440473fe8bSchristos int error = 0;
4450473fe8bSchristos
446a5d1c1f4Sozaki-r SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
4470473fe8bSchristos
4480473fe8bSchristos /* Init: interface re-config and attach/detach hook. */
4490473fe8bSchristos if (!npf_ph_if) {
4500473fe8bSchristos npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
4510473fe8bSchristos if (!npf_ph_if) {
4520473fe8bSchristos error = ENOENT;
4530473fe8bSchristos goto out;
4540473fe8bSchristos }
455739852eaSrmind
456739852eaSrmind error = pfil_add_ihook(npf_ifhook, NULL,
457739852eaSrmind PFIL_IFNET, npf_ph_if);
458739852eaSrmind KASSERT(error == 0);
459739852eaSrmind
460739852eaSrmind error = pfil_add_ihook(npf_ifaddrhook, NULL,
461739852eaSrmind PFIL_IFADDR, npf_ph_if);
4620473fe8bSchristos KASSERT(error == 0);
4630473fe8bSchristos }
4640473fe8bSchristos if (init) {
4650473fe8bSchristos goto out;
4660473fe8bSchristos }
4670473fe8bSchristos
4680473fe8bSchristos /* Check if pfil hooks are not already registered. */
4690473fe8bSchristos if (pfil_registered) {
4700473fe8bSchristos error = EEXIST;
4710473fe8bSchristos goto out;
4720473fe8bSchristos }
4730473fe8bSchristos
4740473fe8bSchristos /* Capture points of the activity in the IP layer. */
4750473fe8bSchristos npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
4760473fe8bSchristos npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
4770473fe8bSchristos if (!npf_ph_inet && !npf_ph_inet6) {
4780473fe8bSchristos error = ENOENT;
4790473fe8bSchristos goto out;
4800473fe8bSchristos }
4810473fe8bSchristos
4820473fe8bSchristos /* Packet IN/OUT handlers for IP layer. */
4830473fe8bSchristos if (npf_ph_inet) {
48404394ddeSrmind error = pfil_add_hook(npfos_packet_handler, npf,
4850473fe8bSchristos PFIL_ALL, npf_ph_inet);
4860473fe8bSchristos KASSERT(error == 0);
4870473fe8bSchristos }
4880473fe8bSchristos if (npf_ph_inet6) {
48904394ddeSrmind error = pfil_add_hook(npfos_packet_handler, npf,
4900473fe8bSchristos PFIL_ALL, npf_ph_inet6);
4910473fe8bSchristos KASSERT(error == 0);
4920473fe8bSchristos }
49377408edbSrmind
49477408edbSrmind /*
49577408edbSrmind * It is necessary to re-sync all/any interface address tables,
49677408edbSrmind * since we did not listen for any changes.
49777408edbSrmind */
49877408edbSrmind npf_ifaddr_syncall(npf);
4990473fe8bSchristos pfil_registered = true;
5000473fe8bSchristos out:
501a5d1c1f4Sozaki-r SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
5020473fe8bSchristos
5030473fe8bSchristos return error;
5040473fe8bSchristos }
5050473fe8bSchristos
5060473fe8bSchristos /*
5070473fe8bSchristos * npf_pfil_unregister: unregister pfil(9) hooks.
5080473fe8bSchristos */
5095fe51d8bSrmind static void
npf_pfil_unregister(bool fini)5100473fe8bSchristos npf_pfil_unregister(bool fini)
5110473fe8bSchristos {
5120473fe8bSchristos npf_t *npf = npf_getkernctx();
5130473fe8bSchristos
514a5d1c1f4Sozaki-r SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
5150473fe8bSchristos
5160473fe8bSchristos if (fini && npf_ph_if) {
517739852eaSrmind (void)pfil_remove_ihook(npf_ifhook, NULL,
518739852eaSrmind PFIL_IFNET, npf_ph_if);
519739852eaSrmind (void)pfil_remove_ihook(npf_ifaddrhook, NULL,
520739852eaSrmind PFIL_IFADDR, npf_ph_if);
5210473fe8bSchristos }
5220473fe8bSchristos if (npf_ph_inet) {
52304394ddeSrmind (void)pfil_remove_hook(npfos_packet_handler, npf,
5240473fe8bSchristos PFIL_ALL, npf_ph_inet);
5250473fe8bSchristos }
5260473fe8bSchristos if (npf_ph_inet6) {
52704394ddeSrmind (void)pfil_remove_hook(npfos_packet_handler, npf,
5280473fe8bSchristos PFIL_ALL, npf_ph_inet6);
5290473fe8bSchristos }
5300473fe8bSchristos pfil_registered = false;
5310473fe8bSchristos
532a5d1c1f4Sozaki-r SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
5330473fe8bSchristos }
5340473fe8bSchristos
5350473fe8bSchristos bool
npf_active_p(void)5365fe51d8bSrmind npf_active_p(void)
5370473fe8bSchristos {
5380473fe8bSchristos return pfil_registered;
5390473fe8bSchristos }
5405fe51d8bSrmind
5410473fe8bSchristos #endif
54289fcc909Srmind
54389fcc909Srmind #ifdef __NetBSD__
54489fcc909Srmind
545d6939920Srmind /*
546d6939920Srmind * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the
547d6939920Srmind * passive serialization mechanism (see pserialize(9) manual page),
548d6939920Srmind * which provides sufficient guarantees for NPF.
549d6939920Srmind */
550d6939920Srmind
55189fcc909Srmind ebr_t *
npf_ebr_create(void)55289fcc909Srmind npf_ebr_create(void)
55389fcc909Srmind {
55489fcc909Srmind return pserialize_create();
55589fcc909Srmind }
55689fcc909Srmind
55789fcc909Srmind void
npf_ebr_destroy(ebr_t * ebr)55889fcc909Srmind npf_ebr_destroy(ebr_t *ebr)
55989fcc909Srmind {
56089fcc909Srmind pserialize_destroy(ebr);
56189fcc909Srmind }
56289fcc909Srmind
56389fcc909Srmind void
npf_ebr_register(ebr_t * ebr)56489fcc909Srmind npf_ebr_register(ebr_t *ebr)
56589fcc909Srmind {
56689fcc909Srmind KASSERT(ebr != NULL); (void)ebr;
56789fcc909Srmind }
56889fcc909Srmind
56989fcc909Srmind void
npf_ebr_unregister(ebr_t * ebr)57089fcc909Srmind npf_ebr_unregister(ebr_t *ebr)
57189fcc909Srmind {
57289fcc909Srmind KASSERT(ebr != NULL); (void)ebr;
57389fcc909Srmind }
57489fcc909Srmind
57589fcc909Srmind int
npf_ebr_enter(ebr_t * ebr)57689fcc909Srmind npf_ebr_enter(ebr_t *ebr)
57789fcc909Srmind {
57889fcc909Srmind KASSERT(ebr != NULL); (void)ebr;
57989fcc909Srmind return pserialize_read_enter();
58089fcc909Srmind }
58189fcc909Srmind
58289fcc909Srmind void
npf_ebr_exit(ebr_t * ebr,int s)58389fcc909Srmind npf_ebr_exit(ebr_t *ebr, int s)
58489fcc909Srmind {
58589fcc909Srmind KASSERT(ebr != NULL); (void)ebr;
58689fcc909Srmind pserialize_read_exit(s);
58789fcc909Srmind }
58889fcc909Srmind
58989fcc909Srmind void
npf_ebr_full_sync(ebr_t * ebr)59089fcc909Srmind npf_ebr_full_sync(ebr_t *ebr)
59189fcc909Srmind {
59289fcc909Srmind pserialize_perform(ebr);
59389fcc909Srmind }
59489fcc909Srmind
59589fcc909Srmind bool
npf_ebr_incrit_p(ebr_t * ebr)59689fcc909Srmind npf_ebr_incrit_p(ebr_t *ebr)
59789fcc909Srmind {
59889fcc909Srmind KASSERT(ebr != NULL); (void)ebr;
59989fcc909Srmind return pserialize_in_read_section();
60089fcc909Srmind }
60189fcc909Srmind
60289fcc909Srmind #endif
603