xref: /netbsd/sys/net/npf/npf_os.c (revision d6939920)
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