Home | History | Annotate | Line # | Download | only in npf
npf_os.c revision 1.12.2.4
      1       1.1  christos /*-
      2       1.1  christos  * Copyright (c) 2009-2016 The NetBSD Foundation, Inc.
      3       1.1  christos  * All rights reserved.
      4       1.1  christos  *
      5       1.1  christos  * This material is based upon work partially supported by The
      6       1.1  christos  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
      7       1.1  christos  *
      8       1.1  christos  * Redistribution and use in source and binary forms, with or without
      9       1.1  christos  * modification, are permitted provided that the following conditions
     10       1.1  christos  * are met:
     11       1.1  christos  * 1. Redistributions of source code must retain the above copyright
     12       1.1  christos  *    notice, this list of conditions and the following disclaimer.
     13       1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     14       1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     15       1.1  christos  *    documentation and/or other materials provided with the distribution.
     16       1.1  christos  *
     17       1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18       1.1  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19       1.1  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20       1.1  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21       1.1  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22       1.1  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23       1.1  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24       1.1  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25       1.1  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26       1.1  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27       1.1  christos  * POSSIBILITY OF SUCH DAMAGE.
     28       1.1  christos  */
     29       1.1  christos 
     30       1.1  christos /*
     31       1.1  christos  * NPF main: dynamic load/initialisation and unload routines.
     32       1.1  christos  */
     33       1.1  christos 
     34       1.1  christos #ifdef _KERNEL
     35       1.1  christos #include <sys/cdefs.h>
     36  1.12.2.4    martin __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.12.2.4 2020/06/20 15:46:47 martin Exp $");
     37       1.1  christos 
     38       1.1  christos #ifdef _KERNEL_OPT
     39       1.1  christos #include "pf.h"
     40       1.1  christos #if NPF > 0
     41       1.1  christos #error "NPF and PF are mutually exclusive; please select one"
     42       1.1  christos #endif
     43       1.1  christos #endif
     44       1.1  christos 
     45       1.1  christos #include <sys/param.h>
     46       1.1  christos #include <sys/types.h>
     47       1.1  christos 
     48       1.1  christos #include <sys/conf.h>
     49       1.1  christos #include <sys/kauth.h>
     50       1.1  christos #include <sys/kmem.h>
     51       1.1  christos #include <sys/lwp.h>
     52       1.1  christos #include <sys/module.h>
     53  1.12.2.3    martin #include <sys/pserialize.h>
     54       1.1  christos #include <sys/socketvar.h>
     55       1.1  christos #include <sys/uio.h>
     56       1.4  christos 
     57       1.4  christos #include <netinet/in.h>
     58       1.4  christos #include <netinet6/in6_var.h>
     59       1.1  christos #endif
     60       1.1  christos 
     61       1.1  christos #include "npf_impl.h"
     62       1.1  christos #include "npfkern.h"
     63       1.1  christos 
     64       1.1  christos #ifdef _KERNEL
     65       1.1  christos #ifndef _MODULE
     66       1.1  christos #include "opt_modular.h"
     67       1.6       ryo #include "opt_net_mpsafe.h"
     68       1.1  christos #endif
     69       1.1  christos #include "ioconf.h"
     70       1.1  christos #endif
     71       1.1  christos 
     72       1.1  christos /*
     73       1.1  christos  * Module and device structures.
     74       1.1  christos  */
     75       1.1  christos #ifndef _MODULE
     76       1.1  christos /*
     77       1.1  christos  * Modular kernels load drivers too early, and we need percpu to be inited
     78       1.1  christos  * So we make this misc; a better way would be to have early boot and late
     79       1.1  christos  * boot drivers.
     80       1.1  christos  */
     81       1.7  pgoyette MODULE(MODULE_CLASS_MISC, npf, "bpf");
     82       1.1  christos #else
     83       1.1  christos /* This module autoloads via /dev/npf so it needs to be a driver */
     84       1.7  pgoyette MODULE(MODULE_CLASS_DRIVER, npf, "bpf");
     85       1.1  christos #endif
     86       1.1  christos 
     87  1.12.2.4    martin #define	NPF_IOCTL_DATA_LIMIT	(4 * 1024 * 1024)
     88  1.12.2.4    martin 
     89  1.12.2.3    martin static int	npf_pfil_register(bool);
     90  1.12.2.3    martin static void	npf_pfil_unregister(bool);
     91  1.12.2.3    martin 
     92       1.1  christos static int	npf_dev_open(dev_t, int, int, lwp_t *);
     93       1.1  christos static int	npf_dev_close(dev_t, int, int, lwp_t *);
     94       1.1  christos static int	npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *);
     95       1.1  christos static int	npf_dev_poll(dev_t, int, lwp_t *);
     96       1.1  christos static int	npf_dev_read(dev_t, struct uio *, int);
     97       1.1  christos 
     98       1.1  christos const struct cdevsw npf_cdevsw = {
     99       1.1  christos 	.d_open = npf_dev_open,
    100       1.1  christos 	.d_close = npf_dev_close,
    101       1.1  christos 	.d_read = npf_dev_read,
    102       1.1  christos 	.d_write = nowrite,
    103       1.1  christos 	.d_ioctl = npf_dev_ioctl,
    104       1.1  christos 	.d_stop = nostop,
    105       1.1  christos 	.d_tty = notty,
    106       1.1  christos 	.d_poll = npf_dev_poll,
    107       1.1  christos 	.d_mmap = nommap,
    108       1.1  christos 	.d_kqfilter = nokqfilter,
    109       1.1  christos 	.d_discard = nodiscard,
    110       1.1  christos 	.d_flag = D_OTHER | D_MPSAFE
    111       1.1  christos };
    112       1.1  christos 
    113  1.12.2.4    martin static const char *	npf_ifop_getname(npf_t *, ifnet_t *);
    114  1.12.2.4    martin static ifnet_t *	npf_ifop_lookup(npf_t *, const char *);
    115  1.12.2.4    martin static void		npf_ifop_flush(npf_t *, void *);
    116  1.12.2.4    martin static void *		npf_ifop_getmeta(npf_t *, const ifnet_t *);
    117  1.12.2.4    martin static void		npf_ifop_setmeta(npf_t *, ifnet_t *, void *);
    118       1.1  christos 
    119       1.1  christos static const unsigned	nworkers = 1;
    120       1.1  christos 
    121       1.1  christos static bool		pfil_registered = false;
    122       1.1  christos static pfil_head_t *	npf_ph_if = NULL;
    123       1.1  christos static pfil_head_t *	npf_ph_inet = NULL;
    124       1.1  christos static pfil_head_t *	npf_ph_inet6 = NULL;
    125       1.1  christos 
    126       1.1  christos static const npf_ifops_t kern_ifops = {
    127       1.1  christos 	.getname	= npf_ifop_getname,
    128       1.1  christos 	.lookup		= npf_ifop_lookup,
    129       1.1  christos 	.flush		= npf_ifop_flush,
    130       1.1  christos 	.getmeta	= npf_ifop_getmeta,
    131       1.1  christos 	.setmeta	= npf_ifop_setmeta,
    132       1.1  christos };
    133       1.1  christos 
    134       1.1  christos static int
    135       1.1  christos npf_fini(void)
    136       1.1  christos {
    137       1.1  christos 	npf_t *npf = npf_getkernctx();
    138       1.1  christos 
    139       1.1  christos 	/* At first, detach device and remove pfil hooks. */
    140       1.1  christos #ifdef _MODULE
    141       1.1  christos 	devsw_detach(NULL, &npf_cdevsw);
    142       1.1  christos #endif
    143       1.1  christos 	npf_pfil_unregister(true);
    144  1.12.2.1    martin 	npfk_destroy(npf);
    145  1.12.2.1    martin 	npfk_sysfini();
    146       1.1  christos 	return 0;
    147       1.1  christos }
    148       1.1  christos 
    149       1.1  christos static int
    150       1.1  christos npf_init(void)
    151       1.1  christos {
    152       1.1  christos 	npf_t *npf;
    153       1.1  christos 	int error = 0;
    154       1.1  christos 
    155  1.12.2.1    martin 	error = npfk_sysinit(nworkers);
    156       1.1  christos 	if (error)
    157       1.1  christos 		return error;
    158  1.12.2.4    martin 	npf = npfk_create(0, NULL, &kern_ifops, NULL);
    159       1.1  christos 	npf_setkernctx(npf);
    160       1.1  christos 	npf_pfil_register(true);
    161       1.1  christos 
    162       1.1  christos #ifdef _MODULE
    163       1.1  christos 	devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
    164       1.1  christos 
    165       1.1  christos 	/* Attach /dev/npf device. */
    166       1.1  christos 	error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
    167       1.1  christos 	if (error) {
    168       1.1  christos 		/* It will call devsw_detach(), which is safe. */
    169       1.1  christos 		(void)npf_fini();
    170       1.1  christos 	}
    171       1.1  christos #endif
    172       1.1  christos 	return error;
    173       1.1  christos }
    174       1.1  christos 
    175       1.1  christos 
    176       1.1  christos /*
    177       1.1  christos  * Module interface.
    178       1.1  christos  */
    179       1.1  christos static int
    180       1.1  christos npf_modcmd(modcmd_t cmd, void *arg)
    181       1.1  christos {
    182       1.1  christos 	switch (cmd) {
    183       1.1  christos 	case MODULE_CMD_INIT:
    184       1.1  christos 		return npf_init();
    185       1.1  christos 	case MODULE_CMD_FINI:
    186       1.1  christos 		return npf_fini();
    187       1.1  christos 	case MODULE_CMD_AUTOUNLOAD:
    188       1.1  christos 		if (npf_autounload_p()) {
    189       1.1  christos 			return EBUSY;
    190       1.1  christos 		}
    191       1.1  christos 		break;
    192       1.1  christos 	default:
    193       1.1  christos 		return ENOTTY;
    194       1.1  christos 	}
    195       1.1  christos 	return 0;
    196       1.1  christos }
    197       1.1  christos 
    198       1.1  christos void
    199       1.1  christos npfattach(int nunits)
    200       1.1  christos {
    201       1.1  christos 	/* Nothing */
    202       1.1  christos }
    203       1.1  christos 
    204       1.1  christos static int
    205       1.1  christos npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l)
    206       1.1  christos {
    207       1.1  christos 	/* Available only for super-user. */
    208       1.1  christos 	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
    209       1.1  christos 	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
    210       1.1  christos 		return EPERM;
    211       1.1  christos 	}
    212       1.1  christos 	return 0;
    213       1.1  christos }
    214       1.1  christos 
    215       1.1  christos static int
    216       1.1  christos npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l)
    217       1.1  christos {
    218       1.1  christos 	return 0;
    219       1.1  christos }
    220       1.1  christos 
    221       1.1  christos static int
    222       1.1  christos npf_stats_export(npf_t *npf, void *data)
    223       1.1  christos {
    224       1.1  christos 	uint64_t *fullst, *uptr = *(uint64_t **)data;
    225       1.1  christos 	int error;
    226       1.1  christos 
    227       1.1  christos 	fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP);
    228  1.12.2.1    martin 	npfk_stats(npf, fullst); /* will zero the buffer */
    229       1.1  christos 	error = copyout(fullst, uptr, NPF_STATS_SIZE);
    230       1.1  christos 	kmem_free(fullst, NPF_STATS_SIZE);
    231       1.1  christos 	return error;
    232       1.1  christos }
    233       1.1  christos 
    234  1.12.2.3    martin /*
    235  1.12.2.3    martin  * npfctl_switch: enable or disable packet inspection.
    236  1.12.2.3    martin  */
    237  1.12.2.3    martin static int
    238  1.12.2.3    martin npfctl_switch(void *data)
    239  1.12.2.3    martin {
    240  1.12.2.3    martin 	const bool onoff = *(int *)data ? true : false;
    241  1.12.2.3    martin 	int error;
    242  1.12.2.3    martin 
    243  1.12.2.3    martin 	if (onoff) {
    244  1.12.2.3    martin 		/* Enable: add pfil hooks. */
    245  1.12.2.3    martin 		error = npf_pfil_register(false);
    246  1.12.2.3    martin 	} else {
    247  1.12.2.3    martin 		/* Disable: remove pfil hooks. */
    248  1.12.2.3    martin 		npf_pfil_unregister(false);
    249  1.12.2.3    martin 		error = 0;
    250  1.12.2.3    martin 	}
    251  1.12.2.3    martin 	return error;
    252  1.12.2.3    martin }
    253  1.12.2.3    martin 
    254       1.1  christos static int
    255       1.1  christos npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
    256       1.1  christos {
    257       1.1  christos 	npf_t *npf = npf_getkernctx();
    258  1.12.2.4    martin 	nvlist_t *req, *resp;
    259       1.1  christos 	int error;
    260       1.1  christos 
    261       1.1  christos 	/* Available only for super-user. */
    262       1.1  christos 	if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL,
    263       1.1  christos 	    KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) {
    264       1.1  christos 		return EPERM;
    265       1.1  christos 	}
    266       1.1  christos 
    267       1.1  christos 	switch (cmd) {
    268       1.1  christos 	case IOC_NPF_VERSION:
    269       1.1  christos 		*(int *)data = NPF_VERSION;
    270  1.12.2.4    martin 		return 0;
    271  1.12.2.4    martin 
    272  1.12.2.4    martin 	case IOC_NPF_SWITCH:
    273  1.12.2.4    martin 		return npfctl_switch(data);
    274  1.12.2.4    martin 
    275  1.12.2.4    martin 	case IOC_NPF_TABLE:
    276  1.12.2.4    martin 		return npfctl_table(npf, data);
    277  1.12.2.4    martin 
    278  1.12.2.4    martin 	case IOC_NPF_STATS:
    279  1.12.2.4    martin 		return npf_stats_export(npf, data);
    280  1.12.2.4    martin 	}
    281  1.12.2.4    martin 
    282  1.12.2.4    martin 	error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT);
    283  1.12.2.4    martin 	if (__predict_false(error)) {
    284  1.12.2.4    martin #ifdef __NetBSD__
    285  1.12.2.4    martin 		/* Until the version bump. */
    286  1.12.2.4    martin 		if (cmd != IOC_NPF_SAVE) {
    287  1.12.2.4    martin 			return error;
    288  1.12.2.4    martin 		}
    289  1.12.2.4    martin 		req = nvlist_create(0);
    290  1.12.2.4    martin #else
    291  1.12.2.4    martin 		return error;
    292  1.12.2.4    martin #endif
    293       1.1  christos 	}
    294  1.12.2.4    martin 	resp = nvlist_create(0);
    295  1.12.2.4    martin 	npfctl_run_op(npf, cmd, req, resp);
    296  1.12.2.4    martin 	error = nvlist_copyout(data, resp);
    297  1.12.2.4    martin 	nvlist_destroy(resp);
    298  1.12.2.4    martin 	nvlist_destroy(req);
    299  1.12.2.4    martin 
    300       1.1  christos 	return error;
    301       1.1  christos }
    302       1.1  christos 
    303       1.1  christos static int
    304       1.1  christos npf_dev_poll(dev_t dev, int events, lwp_t *l)
    305       1.1  christos {
    306       1.1  christos 	return ENOTSUP;
    307       1.1  christos }
    308       1.1  christos 
    309       1.1  christos static int
    310       1.1  christos npf_dev_read(dev_t dev, struct uio *uio, int flag)
    311       1.1  christos {
    312       1.1  christos 	return ENOTSUP;
    313       1.1  christos }
    314       1.1  christos 
    315       1.1  christos bool
    316       1.1  christos npf_autounload_p(void)
    317       1.1  christos {
    318       1.1  christos 	npf_t *npf = npf_getkernctx();
    319  1.12.2.3    martin 	return !npf_active_p() && npf_default_pass(npf);
    320       1.1  christos }
    321       1.1  christos 
    322       1.1  christos /*
    323       1.1  christos  * Interface operations.
    324       1.1  christos  */
    325       1.1  christos 
    326       1.1  christos static const char *
    327  1.12.2.4    martin npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp)
    328       1.1  christos {
    329       1.1  christos 	return ifp->if_xname;
    330       1.1  christos }
    331       1.1  christos 
    332       1.1  christos static ifnet_t *
    333  1.12.2.4    martin npf_ifop_lookup(npf_t *npf __unused, const char *name)
    334       1.1  christos {
    335       1.1  christos 	return ifunit(name);
    336       1.1  christos }
    337       1.1  christos 
    338       1.1  christos static void
    339  1.12.2.4    martin npf_ifop_flush(npf_t *npf __unused, void *arg)
    340       1.1  christos {
    341       1.1  christos 	ifnet_t *ifp;
    342       1.1  christos 
    343       1.1  christos 	KERNEL_LOCK(1, NULL);
    344       1.9     ozaki 	IFNET_GLOBAL_LOCK();
    345       1.1  christos 	IFNET_WRITER_FOREACH(ifp) {
    346       1.1  christos 		ifp->if_pf_kif = arg;
    347       1.1  christos 	}
    348       1.9     ozaki 	IFNET_GLOBAL_UNLOCK();
    349       1.1  christos 	KERNEL_UNLOCK_ONE(NULL);
    350       1.1  christos }
    351       1.1  christos 
    352       1.1  christos static void *
    353  1.12.2.4    martin npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp)
    354       1.1  christos {
    355       1.1  christos 	return ifp->if_pf_kif;
    356       1.1  christos }
    357       1.1  christos 
    358       1.1  christos static void
    359  1.12.2.4    martin npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg)
    360       1.1  christos {
    361       1.1  christos 	ifp->if_pf_kif = arg;
    362       1.1  christos }
    363       1.1  christos 
    364       1.1  christos #ifdef _KERNEL
    365       1.1  christos 
    366       1.1  christos /*
    367       1.1  christos  * Wrapper of the main packet handler to pass the kernel NPF context.
    368       1.1  christos  */
    369       1.1  christos static int
    370  1.12.2.1    martin npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
    371       1.1  christos {
    372       1.1  christos 	npf_t *npf = npf_getkernctx();
    373  1.12.2.1    martin 	return npfk_packet_handler(npf, mp, ifp, di);
    374       1.1  christos }
    375       1.1  christos 
    376       1.1  christos /*
    377       1.1  christos  * npf_ifhook: hook handling interface changes.
    378       1.1  christos  */
    379       1.2     rmind static void
    380       1.2     rmind npf_ifhook(void *arg, unsigned long cmd, void *arg2)
    381       1.1  christos {
    382       1.1  christos 	npf_t *npf = npf_getkernctx();
    383       1.2     rmind 	ifnet_t *ifp = arg2;
    384       1.1  christos 
    385       1.2     rmind 	switch (cmd) {
    386       1.2     rmind 	case PFIL_IFNET_ATTACH:
    387  1.12.2.1    martin 		npfk_ifmap_attach(npf, ifp);
    388       1.3     rmind 		npf_ifaddr_sync(npf, ifp);
    389       1.2     rmind 		break;
    390       1.2     rmind 	case PFIL_IFNET_DETACH:
    391  1.12.2.1    martin 		npfk_ifmap_detach(npf, ifp);
    392       1.3     rmind 		npf_ifaddr_flush(npf, ifp);
    393       1.2     rmind 		break;
    394       1.1  christos 	}
    395       1.1  christos }
    396       1.1  christos 
    397       1.3     rmind static void
    398       1.3     rmind npf_ifaddrhook(void *arg, u_long cmd, void *arg2)
    399       1.3     rmind {
    400       1.3     rmind 	npf_t *npf = npf_getkernctx();
    401       1.3     rmind 	struct ifaddr *ifa = arg2;
    402       1.3     rmind 
    403       1.3     rmind 	switch (cmd) {
    404       1.3     rmind 	case SIOCSIFADDR:
    405       1.3     rmind 	case SIOCAIFADDR:
    406       1.3     rmind 	case SIOCDIFADDR:
    407       1.3     rmind #ifdef INET6
    408       1.3     rmind 	case SIOCSIFADDR_IN6:
    409       1.3     rmind 	case SIOCAIFADDR_IN6:
    410       1.3     rmind 	case SIOCDIFADDR_IN6:
    411       1.3     rmind #endif
    412      1.12     rmind 		KASSERT(ifa != NULL);
    413       1.3     rmind 		break;
    414       1.3     rmind 	default:
    415       1.3     rmind 		return;
    416       1.3     rmind 	}
    417       1.3     rmind 	npf_ifaddr_sync(npf, ifa->ifa_ifp);
    418       1.3     rmind }
    419       1.3     rmind 
    420       1.1  christos /*
    421       1.1  christos  * npf_pfil_register: register pfil(9) hooks.
    422       1.1  christos  */
    423  1.12.2.3    martin static int
    424       1.1  christos npf_pfil_register(bool init)
    425       1.1  christos {
    426       1.1  christos 	npf_t *npf = npf_getkernctx();
    427       1.1  christos 	int error = 0;
    428       1.1  christos 
    429       1.8     ozaki 	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
    430       1.1  christos 
    431       1.1  christos 	/* Init: interface re-config and attach/detach hook. */
    432       1.1  christos 	if (!npf_ph_if) {
    433       1.1  christos 		npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
    434       1.1  christos 		if (!npf_ph_if) {
    435       1.1  christos 			error = ENOENT;
    436       1.1  christos 			goto out;
    437       1.1  christos 		}
    438       1.3     rmind 
    439       1.3     rmind 		error = pfil_add_ihook(npf_ifhook, NULL,
    440       1.3     rmind 		    PFIL_IFNET, npf_ph_if);
    441       1.3     rmind 		KASSERT(error == 0);
    442       1.3     rmind 
    443       1.3     rmind 		error = pfil_add_ihook(npf_ifaddrhook, NULL,
    444       1.3     rmind 		    PFIL_IFADDR, npf_ph_if);
    445       1.1  christos 		KASSERT(error == 0);
    446       1.1  christos 	}
    447       1.1  christos 	if (init) {
    448       1.1  christos 		goto out;
    449       1.1  christos 	}
    450       1.1  christos 
    451       1.1  christos 	/* Check if pfil hooks are not already registered. */
    452       1.1  christos 	if (pfil_registered) {
    453       1.1  christos 		error = EEXIST;
    454       1.1  christos 		goto out;
    455       1.1  christos 	}
    456       1.1  christos 
    457       1.1  christos 	/* Capture points of the activity in the IP layer. */
    458       1.1  christos 	npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET);
    459       1.1  christos 	npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6);
    460       1.1  christos 	if (!npf_ph_inet && !npf_ph_inet6) {
    461       1.1  christos 		error = ENOENT;
    462       1.1  christos 		goto out;
    463       1.1  christos 	}
    464       1.1  christos 
    465       1.1  christos 	/* Packet IN/OUT handlers for IP layer. */
    466       1.1  christos 	if (npf_ph_inet) {
    467  1.12.2.1    martin 		error = pfil_add_hook(npfos_packet_handler, npf,
    468       1.1  christos 		    PFIL_ALL, npf_ph_inet);
    469       1.1  christos 		KASSERT(error == 0);
    470       1.1  christos 	}
    471       1.1  christos 	if (npf_ph_inet6) {
    472  1.12.2.1    martin 		error = pfil_add_hook(npfos_packet_handler, npf,
    473       1.1  christos 		    PFIL_ALL, npf_ph_inet6);
    474       1.1  christos 		KASSERT(error == 0);
    475       1.1  christos 	}
    476       1.5     rmind 
    477       1.5     rmind 	/*
    478       1.5     rmind 	 * It is necessary to re-sync all/any interface address tables,
    479       1.5     rmind 	 * since we did not listen for any changes.
    480       1.5     rmind 	 */
    481       1.5     rmind 	npf_ifaddr_syncall(npf);
    482       1.1  christos 	pfil_registered = true;
    483       1.1  christos out:
    484       1.8     ozaki 	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
    485       1.1  christos 
    486       1.1  christos 	return error;
    487       1.1  christos }
    488       1.1  christos 
    489       1.1  christos /*
    490       1.1  christos  * npf_pfil_unregister: unregister pfil(9) hooks.
    491       1.1  christos  */
    492  1.12.2.3    martin static void
    493       1.1  christos npf_pfil_unregister(bool fini)
    494       1.1  christos {
    495       1.1  christos 	npf_t *npf = npf_getkernctx();
    496       1.1  christos 
    497       1.8     ozaki 	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
    498       1.1  christos 
    499       1.1  christos 	if (fini && npf_ph_if) {
    500       1.3     rmind 		(void)pfil_remove_ihook(npf_ifhook, NULL,
    501       1.3     rmind 		    PFIL_IFNET, npf_ph_if);
    502       1.3     rmind 		(void)pfil_remove_ihook(npf_ifaddrhook, NULL,
    503       1.3     rmind 		    PFIL_IFADDR, npf_ph_if);
    504       1.1  christos 	}
    505       1.1  christos 	if (npf_ph_inet) {
    506  1.12.2.1    martin 		(void)pfil_remove_hook(npfos_packet_handler, npf,
    507       1.1  christos 		    PFIL_ALL, npf_ph_inet);
    508       1.1  christos 	}
    509       1.1  christos 	if (npf_ph_inet6) {
    510  1.12.2.1    martin 		(void)pfil_remove_hook(npfos_packet_handler, npf,
    511       1.1  christos 		    PFIL_ALL, npf_ph_inet6);
    512       1.1  christos 	}
    513       1.1  christos 	pfil_registered = false;
    514       1.1  christos 
    515       1.8     ozaki 	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
    516       1.1  christos }
    517       1.1  christos 
    518       1.1  christos bool
    519  1.12.2.3    martin npf_active_p(void)
    520       1.1  christos {
    521       1.1  christos 	return pfil_registered;
    522       1.1  christos }
    523  1.12.2.3    martin 
    524  1.12.2.3    martin #endif
    525  1.12.2.3    martin 
    526  1.12.2.3    martin #ifdef __NetBSD__
    527  1.12.2.3    martin 
    528  1.12.2.4    martin /*
    529  1.12.2.4    martin  * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the
    530  1.12.2.4    martin  * passive serialization mechanism (see pserialize(9) manual page),
    531  1.12.2.4    martin  * which provides sufficient guarantees for NPF.
    532  1.12.2.4    martin  */
    533  1.12.2.4    martin 
    534  1.12.2.3    martin ebr_t *
    535  1.12.2.3    martin npf_ebr_create(void)
    536  1.12.2.3    martin {
    537  1.12.2.3    martin 	return pserialize_create();
    538  1.12.2.3    martin }
    539  1.12.2.3    martin 
    540  1.12.2.3    martin void
    541  1.12.2.3    martin npf_ebr_destroy(ebr_t *ebr)
    542  1.12.2.3    martin {
    543  1.12.2.3    martin 	pserialize_destroy(ebr);
    544  1.12.2.3    martin }
    545  1.12.2.3    martin 
    546  1.12.2.3    martin void
    547  1.12.2.3    martin npf_ebr_register(ebr_t *ebr)
    548  1.12.2.3    martin {
    549  1.12.2.3    martin 	KASSERT(ebr != NULL); (void)ebr;
    550  1.12.2.3    martin }
    551  1.12.2.3    martin 
    552  1.12.2.3    martin void
    553  1.12.2.3    martin npf_ebr_unregister(ebr_t *ebr)
    554  1.12.2.3    martin {
    555  1.12.2.3    martin 	KASSERT(ebr != NULL); (void)ebr;
    556  1.12.2.3    martin }
    557  1.12.2.3    martin 
    558  1.12.2.3    martin int
    559  1.12.2.3    martin npf_ebr_enter(ebr_t *ebr)
    560  1.12.2.3    martin {
    561  1.12.2.3    martin 	KASSERT(ebr != NULL); (void)ebr;
    562  1.12.2.3    martin 	return pserialize_read_enter();
    563  1.12.2.3    martin }
    564  1.12.2.3    martin 
    565  1.12.2.3    martin void
    566  1.12.2.3    martin npf_ebr_exit(ebr_t *ebr, int s)
    567  1.12.2.3    martin {
    568  1.12.2.3    martin 	KASSERT(ebr != NULL); (void)ebr;
    569  1.12.2.3    martin 	pserialize_read_exit(s);
    570  1.12.2.3    martin }
    571  1.12.2.3    martin 
    572  1.12.2.3    martin void
    573  1.12.2.3    martin npf_ebr_full_sync(ebr_t *ebr)
    574  1.12.2.3    martin {
    575  1.12.2.3    martin 	pserialize_perform(ebr);
    576  1.12.2.3    martin }
    577  1.12.2.3    martin 
    578  1.12.2.3    martin bool
    579  1.12.2.3    martin npf_ebr_incrit_p(ebr_t *ebr)
    580  1.12.2.3    martin {
    581  1.12.2.3    martin 	KASSERT(ebr != NULL); (void)ebr;
    582  1.12.2.3    martin 	return pserialize_in_read_section();
    583  1.12.2.3    martin }
    584  1.12.2.3    martin 
    585       1.1  christos #endif
    586