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.23 joe __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.23 2025/07/01 18:42:37 joe 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.16 rmind #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.18 rmind #define NPF_IOCTL_DATA_LIMIT (4 * 1024 * 1024) 88 1.18 rmind 89 1.17 rmind static int npf_pfil_register(bool); 90 1.17 rmind static void npf_pfil_unregister(bool); 91 1.17 rmind 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.18 rmind static const char * npf_ifop_getname(npf_t *, ifnet_t *); 114 1.18 rmind static ifnet_t * npf_ifop_lookup(npf_t *, const char *); 115 1.18 rmind static void npf_ifop_flush(npf_t *, void *); 116 1.18 rmind static void * npf_ifop_getmeta(npf_t *, const ifnet_t *); 117 1.18 rmind 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.23 joe static pfil_head_t * npf_ph_etherlist[NPF_MAX_IFMAP]; 126 1.1 christos 127 1.1 christos static const npf_ifops_t kern_ifops = { 128 1.1 christos .getname = npf_ifop_getname, 129 1.1 christos .lookup = npf_ifop_lookup, 130 1.1 christos .flush = npf_ifop_flush, 131 1.1 christos .getmeta = npf_ifop_getmeta, 132 1.1 christos .setmeta = npf_ifop_setmeta, 133 1.1 christos }; 134 1.1 christos 135 1.1 christos static int 136 1.1 christos npf_fini(void) 137 1.1 christos { 138 1.1 christos npf_t *npf = npf_getkernctx(); 139 1.1 christos 140 1.1 christos /* At first, detach device and remove pfil hooks. */ 141 1.1 christos #ifdef _MODULE 142 1.1 christos devsw_detach(NULL, &npf_cdevsw); 143 1.1 christos #endif 144 1.1 christos npf_pfil_unregister(true); 145 1.14 rmind npfk_destroy(npf); 146 1.14 rmind npfk_sysfini(); 147 1.1 christos return 0; 148 1.1 christos } 149 1.1 christos 150 1.1 christos static int 151 1.1 christos npf_init(void) 152 1.1 christos { 153 1.1 christos npf_t *npf; 154 1.1 christos int error = 0; 155 1.1 christos 156 1.14 rmind error = npfk_sysinit(nworkers); 157 1.1 christos if (error) 158 1.1 christos return error; 159 1.18 rmind npf = npfk_create(0, NULL, &kern_ifops, NULL); 160 1.1 christos npf_setkernctx(npf); 161 1.1 christos npf_pfil_register(true); 162 1.1 christos 163 1.1 christos #ifdef _MODULE 164 1.1 christos devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 165 1.1 christos 166 1.1 christos /* Attach /dev/npf device. */ 167 1.1 christos error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); 168 1.1 christos if (error) { 169 1.1 christos /* It will call devsw_detach(), which is safe. */ 170 1.1 christos (void)npf_fini(); 171 1.1 christos } 172 1.1 christos #endif 173 1.1 christos return error; 174 1.1 christos } 175 1.1 christos 176 1.1 christos 177 1.1 christos /* 178 1.1 christos * Module interface. 179 1.1 christos */ 180 1.1 christos static int 181 1.1 christos npf_modcmd(modcmd_t cmd, void *arg) 182 1.1 christos { 183 1.1 christos switch (cmd) { 184 1.1 christos case MODULE_CMD_INIT: 185 1.1 christos return npf_init(); 186 1.1 christos case MODULE_CMD_FINI: 187 1.1 christos return npf_fini(); 188 1.1 christos case MODULE_CMD_AUTOUNLOAD: 189 1.22 pgoyette /* 190 1.22 pgoyette * XXX npf_autounload_p() is insufficient here. At least one other 191 1.22 pgoyette * XXX path leads to unloading while something tries later on to 192 1.22 pgoyette * XXX continue (perhaps closing of an open fd). For now, just 193 1.22 pgoyette * XXX disabble autounload. 194 1.22 pgoyette */ 195 1.22 pgoyette return EBUSY; 196 1.1 christos default: 197 1.1 christos return ENOTTY; 198 1.1 christos } 199 1.1 christos return 0; 200 1.1 christos } 201 1.1 christos 202 1.1 christos void 203 1.1 christos npfattach(int nunits) 204 1.1 christos { 205 1.1 christos /* Nothing */ 206 1.1 christos } 207 1.1 christos 208 1.1 christos static int 209 1.1 christos npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) 210 1.1 christos { 211 1.1 christos /* Available only for super-user. */ 212 1.1 christos if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 213 1.1 christos KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 214 1.1 christos return EPERM; 215 1.1 christos } 216 1.1 christos return 0; 217 1.1 christos } 218 1.1 christos 219 1.1 christos static int 220 1.1 christos npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) 221 1.1 christos { 222 1.1 christos return 0; 223 1.1 christos } 224 1.1 christos 225 1.1 christos static int 226 1.1 christos npf_stats_export(npf_t *npf, void *data) 227 1.1 christos { 228 1.1 christos uint64_t *fullst, *uptr = *(uint64_t **)data; 229 1.1 christos int error; 230 1.1 christos 231 1.1 christos fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); 232 1.14 rmind npfk_stats(npf, fullst); /* will zero the buffer */ 233 1.1 christos error = copyout(fullst, uptr, NPF_STATS_SIZE); 234 1.1 christos kmem_free(fullst, NPF_STATS_SIZE); 235 1.1 christos return error; 236 1.1 christos } 237 1.1 christos 238 1.17 rmind /* 239 1.17 rmind * npfctl_switch: enable or disable packet inspection. 240 1.17 rmind */ 241 1.17 rmind static int 242 1.17 rmind npfctl_switch(void *data) 243 1.17 rmind { 244 1.17 rmind const bool onoff = *(int *)data ? true : false; 245 1.17 rmind int error; 246 1.17 rmind 247 1.17 rmind if (onoff) { 248 1.17 rmind /* Enable: add pfil hooks. */ 249 1.17 rmind error = npf_pfil_register(false); 250 1.17 rmind } else { 251 1.17 rmind /* Disable: remove pfil hooks. */ 252 1.17 rmind npf_pfil_unregister(false); 253 1.17 rmind error = 0; 254 1.17 rmind } 255 1.17 rmind return error; 256 1.17 rmind } 257 1.17 rmind 258 1.1 christos static int 259 1.1 christos npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 260 1.1 christos { 261 1.1 christos npf_t *npf = npf_getkernctx(); 262 1.18 rmind nvlist_t *req, *resp; 263 1.1 christos int error; 264 1.1 christos 265 1.1 christos /* Available only for super-user. */ 266 1.1 christos if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, 267 1.1 christos KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { 268 1.1 christos return EPERM; 269 1.1 christos } 270 1.1 christos 271 1.1 christos switch (cmd) { 272 1.18 rmind case IOC_NPF_VERSION: 273 1.18 rmind *(int *)data = NPF_VERSION; 274 1.18 rmind return 0; 275 1.18 rmind case IOC_NPF_SWITCH: 276 1.18 rmind return npfctl_switch(data); 277 1.1 christos case IOC_NPF_TABLE: 278 1.18 rmind return npfctl_table(npf, data); 279 1.1 christos case IOC_NPF_STATS: 280 1.18 rmind return npf_stats_export(npf, data); 281 1.19 maxv case IOC_NPF_LOAD: 282 1.19 maxv case IOC_NPF_SAVE: 283 1.19 maxv case IOC_NPF_RULE: 284 1.19 maxv case IOC_NPF_CONN_LOOKUP: 285 1.19 maxv case IOC_NPF_TABLE_REPLACE: 286 1.19 maxv /* nvlist_ref_t argument, handled below */ 287 1.19 maxv break; 288 1.19 maxv default: 289 1.19 maxv return EINVAL; 290 1.18 rmind } 291 1.18 rmind 292 1.18 rmind error = nvlist_copyin(data, &req, NPF_IOCTL_DATA_LIMIT); 293 1.18 rmind if (__predict_false(error)) { 294 1.18 rmind #ifdef __NetBSD__ 295 1.18 rmind /* Until the version bump. */ 296 1.18 rmind if (cmd != IOC_NPF_SAVE) { 297 1.18 rmind return error; 298 1.18 rmind } 299 1.18 rmind req = nvlist_create(0); 300 1.18 rmind #else 301 1.18 rmind return error; 302 1.18 rmind #endif 303 1.1 christos } 304 1.18 rmind resp = nvlist_create(0); 305 1.21 christos 306 1.21 christos if ((error = npfctl_run_op(npf, cmd, req, resp)) == 0) { 307 1.21 christos error = nvlist_copyout(data, resp); 308 1.21 christos } 309 1.21 christos 310 1.18 rmind nvlist_destroy(resp); 311 1.18 rmind nvlist_destroy(req); 312 1.18 rmind 313 1.1 christos return error; 314 1.1 christos } 315 1.1 christos 316 1.1 christos static int 317 1.1 christos npf_dev_poll(dev_t dev, int events, lwp_t *l) 318 1.1 christos { 319 1.1 christos return ENOTSUP; 320 1.1 christos } 321 1.1 christos 322 1.1 christos static int 323 1.1 christos npf_dev_read(dev_t dev, struct uio *uio, int flag) 324 1.1 christos { 325 1.1 christos return ENOTSUP; 326 1.1 christos } 327 1.1 christos 328 1.1 christos bool 329 1.1 christos npf_autounload_p(void) 330 1.1 christos { 331 1.20 christos if (npf_active_p()) 332 1.20 christos return false; 333 1.20 christos 334 1.1 christos npf_t *npf = npf_getkernctx(); 335 1.20 christos 336 1.20 christos npf_config_enter(npf); 337 1.20 christos bool pass = npf_default_pass(npf); 338 1.20 christos npf_config_exit(npf); 339 1.20 christos 340 1.20 christos return pass; 341 1.1 christos } 342 1.1 christos 343 1.1 christos /* 344 1.1 christos * Interface operations. 345 1.1 christos */ 346 1.1 christos 347 1.1 christos static const char * 348 1.18 rmind npf_ifop_getname(npf_t *npf __unused, ifnet_t *ifp) 349 1.1 christos { 350 1.1 christos return ifp->if_xname; 351 1.1 christos } 352 1.1 christos 353 1.1 christos static ifnet_t * 354 1.18 rmind npf_ifop_lookup(npf_t *npf __unused, const char *name) 355 1.1 christos { 356 1.1 christos return ifunit(name); 357 1.1 christos } 358 1.1 christos 359 1.1 christos static void 360 1.18 rmind npf_ifop_flush(npf_t *npf __unused, void *arg) 361 1.1 christos { 362 1.1 christos ifnet_t *ifp; 363 1.1 christos 364 1.1 christos KERNEL_LOCK(1, NULL); 365 1.9 ozaki IFNET_GLOBAL_LOCK(); 366 1.1 christos IFNET_WRITER_FOREACH(ifp) { 367 1.13 rmind ifp->if_npf_private = arg; 368 1.1 christos } 369 1.9 ozaki IFNET_GLOBAL_UNLOCK(); 370 1.1 christos KERNEL_UNLOCK_ONE(NULL); 371 1.1 christos } 372 1.1 christos 373 1.1 christos static void * 374 1.18 rmind npf_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp) 375 1.1 christos { 376 1.13 rmind return ifp->if_npf_private; 377 1.1 christos } 378 1.1 christos 379 1.1 christos static void 380 1.18 rmind npf_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg) 381 1.1 christos { 382 1.13 rmind ifp->if_npf_private = arg; 383 1.1 christos } 384 1.1 christos 385 1.1 christos #ifdef _KERNEL 386 1.1 christos 387 1.1 christos /* 388 1.1 christos * Wrapper of the main packet handler to pass the kernel NPF context. 389 1.1 christos */ 390 1.1 christos static int 391 1.14 rmind npfos_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 392 1.1 christos { 393 1.1 christos npf_t *npf = npf_getkernctx(); 394 1.14 rmind return npfk_packet_handler(npf, mp, ifp, di); 395 1.1 christos } 396 1.1 christos 397 1.23 joe static int 398 1.23 joe npfos_layer2_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) 399 1.23 joe { 400 1.23 joe npf_t *npf = npf_getkernctx(); 401 1.23 joe return npfk_layer2_handler(npf, mp, ifp, di); 402 1.23 joe } 403 1.23 joe 404 1.1 christos /* 405 1.1 christos * npf_ifhook: hook handling interface changes. 406 1.1 christos */ 407 1.2 rmind static void 408 1.2 rmind npf_ifhook(void *arg, unsigned long cmd, void *arg2) 409 1.1 christos { 410 1.1 christos npf_t *npf = npf_getkernctx(); 411 1.2 rmind ifnet_t *ifp = arg2; 412 1.1 christos 413 1.2 rmind switch (cmd) { 414 1.2 rmind case PFIL_IFNET_ATTACH: 415 1.14 rmind npfk_ifmap_attach(npf, ifp); 416 1.3 rmind npf_ifaddr_sync(npf, ifp); 417 1.2 rmind break; 418 1.2 rmind case PFIL_IFNET_DETACH: 419 1.14 rmind npfk_ifmap_detach(npf, ifp); 420 1.3 rmind npf_ifaddr_flush(npf, ifp); 421 1.2 rmind break; 422 1.1 christos } 423 1.1 christos } 424 1.1 christos 425 1.3 rmind static void 426 1.3 rmind npf_ifaddrhook(void *arg, u_long cmd, void *arg2) 427 1.3 rmind { 428 1.3 rmind npf_t *npf = npf_getkernctx(); 429 1.3 rmind struct ifaddr *ifa = arg2; 430 1.3 rmind 431 1.3 rmind switch (cmd) { 432 1.3 rmind case SIOCSIFADDR: 433 1.3 rmind case SIOCAIFADDR: 434 1.3 rmind case SIOCDIFADDR: 435 1.3 rmind #ifdef INET6 436 1.3 rmind case SIOCSIFADDR_IN6: 437 1.3 rmind case SIOCAIFADDR_IN6: 438 1.3 rmind case SIOCDIFADDR_IN6: 439 1.3 rmind #endif 440 1.12 rmind KASSERT(ifa != NULL); 441 1.3 rmind break; 442 1.3 rmind default: 443 1.3 rmind return; 444 1.3 rmind } 445 1.3 rmind npf_ifaddr_sync(npf, ifa->ifa_ifp); 446 1.3 rmind } 447 1.3 rmind 448 1.23 joe static int 449 1.23 joe register_etherpfil_hook(npf_t *npf, ifnet_t *ifp, int i) 450 1.23 joe { 451 1.23 joe int error = 0; 452 1.23 joe static pfil_head_t *npf_ph_ether; 453 1.23 joe /* Capture points of activity at link layer */ 454 1.23 joe if ((npf_ph_ether = pfil_head_get(PFIL_TYPE_IFNET, ifp)) == NULL) { 455 1.23 joe error = ENOENT; 456 1.23 joe return error; 457 1.23 joe } 458 1.23 joe 459 1.23 joe if (npf_ph_ether) { 460 1.23 joe error = pfil_add_hook(npfos_layer2_handler, npf, 461 1.23 joe PFIL_ALL, npf_ph_ether); 462 1.23 joe KASSERT(error == 0); 463 1.23 joe } 464 1.23 joe npf_ph_etherlist[i] = npf_ph_ether; 465 1.23 joe 466 1.23 joe return error; 467 1.23 joe } 468 1.23 joe 469 1.23 joe static int 470 1.23 joe get_etherpfil_head(npf_t *npf) 471 1.23 joe { 472 1.23 joe int error = 0, i = 0; 473 1.23 joe ifnet_t *ifp; 474 1.23 joe 475 1.23 joe KERNEL_LOCK(1, NULL); 476 1.23 joe IFNET_GLOBAL_LOCK(); 477 1.23 joe IFNET_WRITER_FOREACH(ifp) { 478 1.23 joe error = register_etherpfil_hook(npf, ifp, i); 479 1.23 joe if (!error) 480 1.23 joe break; 481 1.23 joe i++; 482 1.23 joe } 483 1.23 joe IFNET_GLOBAL_UNLOCK(); 484 1.23 joe KERNEL_UNLOCK_ONE(NULL); 485 1.23 joe return error; 486 1.23 joe } 487 1.23 joe 488 1.23 joe static void 489 1.23 joe destroy_pfilether_hook(npf_t *npf) 490 1.23 joe { 491 1.23 joe int i = 0; 492 1.23 joe while (npf_ph_etherlist[i]) { 493 1.23 joe pfil_head_t *npf_ph_ether = npf_ph_etherlist[i]; 494 1.23 joe 495 1.23 joe if (npf_ph_ether) { 496 1.23 joe (void)pfil_remove_hook(npfos_layer2_handler, npf, 497 1.23 joe PFIL_ALL, npf_ph_ether); 498 1.23 joe } 499 1.23 joe i++; 500 1.23 joe } 501 1.23 joe } 502 1.23 joe 503 1.1 christos /* 504 1.1 christos * npf_pfil_register: register pfil(9) hooks. 505 1.1 christos */ 506 1.17 rmind static int 507 1.1 christos npf_pfil_register(bool init) 508 1.1 christos { 509 1.1 christos npf_t *npf = npf_getkernctx(); 510 1.1 christos int error = 0; 511 1.1 christos 512 1.8 ozaki SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 513 1.1 christos 514 1.1 christos /* Init: interface re-config and attach/detach hook. */ 515 1.1 christos if (!npf_ph_if) { 516 1.1 christos npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); 517 1.1 christos if (!npf_ph_if) { 518 1.1 christos error = ENOENT; 519 1.1 christos goto out; 520 1.1 christos } 521 1.3 rmind 522 1.3 rmind error = pfil_add_ihook(npf_ifhook, NULL, 523 1.3 rmind PFIL_IFNET, npf_ph_if); 524 1.3 rmind KASSERT(error == 0); 525 1.3 rmind 526 1.3 rmind error = pfil_add_ihook(npf_ifaddrhook, NULL, 527 1.3 rmind PFIL_IFADDR, npf_ph_if); 528 1.1 christos KASSERT(error == 0); 529 1.1 christos } 530 1.1 christos if (init) { 531 1.1 christos goto out; 532 1.1 christos } 533 1.1 christos 534 1.1 christos /* Check if pfil hooks are not already registered. */ 535 1.1 christos if (pfil_registered) { 536 1.1 christos error = EEXIST; 537 1.1 christos goto out; 538 1.1 christos } 539 1.1 christos 540 1.1 christos /* Capture points of the activity in the IP layer. */ 541 1.1 christos npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); 542 1.1 christos npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); 543 1.1 christos if (!npf_ph_inet && !npf_ph_inet6) { 544 1.1 christos error = ENOENT; 545 1.1 christos goto out; 546 1.1 christos } 547 1.1 christos 548 1.1 christos /* Packet IN/OUT handlers for IP layer. */ 549 1.1 christos if (npf_ph_inet) { 550 1.14 rmind error = pfil_add_hook(npfos_packet_handler, npf, 551 1.1 christos PFIL_ALL, npf_ph_inet); 552 1.1 christos KASSERT(error == 0); 553 1.1 christos } 554 1.1 christos if (npf_ph_inet6) { 555 1.14 rmind error = pfil_add_hook(npfos_packet_handler, npf, 556 1.1 christos PFIL_ALL, npf_ph_inet6); 557 1.1 christos KASSERT(error == 0); 558 1.1 christos } 559 1.5 rmind 560 1.23 joe get_etherpfil_head(npf); 561 1.23 joe 562 1.5 rmind /* 563 1.5 rmind * It is necessary to re-sync all/any interface address tables, 564 1.5 rmind * since we did not listen for any changes. 565 1.5 rmind */ 566 1.5 rmind npf_ifaddr_syncall(npf); 567 1.1 christos pfil_registered = true; 568 1.1 christos out: 569 1.8 ozaki SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 570 1.1 christos 571 1.1 christos return error; 572 1.1 christos } 573 1.1 christos 574 1.1 christos /* 575 1.1 christos * npf_pfil_unregister: unregister pfil(9) hooks. 576 1.1 christos */ 577 1.17 rmind static void 578 1.1 christos npf_pfil_unregister(bool fini) 579 1.1 christos { 580 1.1 christos npf_t *npf = npf_getkernctx(); 581 1.1 christos 582 1.8 ozaki SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 583 1.1 christos 584 1.1 christos if (fini && npf_ph_if) { 585 1.3 rmind (void)pfil_remove_ihook(npf_ifhook, NULL, 586 1.3 rmind PFIL_IFNET, npf_ph_if); 587 1.3 rmind (void)pfil_remove_ihook(npf_ifaddrhook, NULL, 588 1.3 rmind PFIL_IFADDR, npf_ph_if); 589 1.1 christos } 590 1.1 christos if (npf_ph_inet) { 591 1.14 rmind (void)pfil_remove_hook(npfos_packet_handler, npf, 592 1.1 christos PFIL_ALL, npf_ph_inet); 593 1.1 christos } 594 1.1 christos if (npf_ph_inet6) { 595 1.14 rmind (void)pfil_remove_hook(npfos_packet_handler, npf, 596 1.1 christos PFIL_ALL, npf_ph_inet6); 597 1.1 christos } 598 1.23 joe destroy_pfilether_hook(npf); 599 1.1 christos pfil_registered = false; 600 1.1 christos 601 1.8 ozaki SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 602 1.1 christos } 603 1.1 christos 604 1.1 christos bool 605 1.17 rmind npf_active_p(void) 606 1.1 christos { 607 1.1 christos return pfil_registered; 608 1.1 christos } 609 1.17 rmind 610 1.1 christos #endif 611 1.16 rmind 612 1.16 rmind #ifdef __NetBSD__ 613 1.16 rmind 614 1.18 rmind /* 615 1.18 rmind * Epoch-Based Reclamation (EBR) wrappers: in NetBSD, we rely on the 616 1.18 rmind * passive serialization mechanism (see pserialize(9) manual page), 617 1.18 rmind * which provides sufficient guarantees for NPF. 618 1.18 rmind */ 619 1.18 rmind 620 1.16 rmind ebr_t * 621 1.16 rmind npf_ebr_create(void) 622 1.16 rmind { 623 1.16 rmind return pserialize_create(); 624 1.16 rmind } 625 1.16 rmind 626 1.16 rmind void 627 1.16 rmind npf_ebr_destroy(ebr_t *ebr) 628 1.16 rmind { 629 1.16 rmind pserialize_destroy(ebr); 630 1.16 rmind } 631 1.16 rmind 632 1.16 rmind void 633 1.16 rmind npf_ebr_register(ebr_t *ebr) 634 1.16 rmind { 635 1.16 rmind KASSERT(ebr != NULL); (void)ebr; 636 1.16 rmind } 637 1.16 rmind 638 1.16 rmind void 639 1.16 rmind npf_ebr_unregister(ebr_t *ebr) 640 1.16 rmind { 641 1.16 rmind KASSERT(ebr != NULL); (void)ebr; 642 1.16 rmind } 643 1.16 rmind 644 1.16 rmind int 645 1.16 rmind npf_ebr_enter(ebr_t *ebr) 646 1.16 rmind { 647 1.16 rmind KASSERT(ebr != NULL); (void)ebr; 648 1.16 rmind return pserialize_read_enter(); 649 1.16 rmind } 650 1.16 rmind 651 1.16 rmind void 652 1.16 rmind npf_ebr_exit(ebr_t *ebr, int s) 653 1.16 rmind { 654 1.16 rmind KASSERT(ebr != NULL); (void)ebr; 655 1.16 rmind pserialize_read_exit(s); 656 1.16 rmind } 657 1.16 rmind 658 1.16 rmind void 659 1.16 rmind npf_ebr_full_sync(ebr_t *ebr) 660 1.16 rmind { 661 1.16 rmind pserialize_perform(ebr); 662 1.16 rmind } 663 1.16 rmind 664 1.16 rmind bool 665 1.16 rmind npf_ebr_incrit_p(ebr_t *ebr) 666 1.16 rmind { 667 1.16 rmind KASSERT(ebr != NULL); (void)ebr; 668 1.16 rmind return pserialize_in_read_section(); 669 1.16 rmind } 670 1.16 rmind 671 1.16 rmind #endif 672