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