1/* $FreeBSD: stable/11/sys/net/pfil.c 332513 2018-04-15 15:22:28Z kp $ */ 2/* $NetBSD: pfil.c,v 1.20 2001/11/12 23:49:46 lukem Exp $ */ 3 4/*- 5 * Copyright (c) 1996 Matthew R. Green 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/errno.h> 35#include <sys/lock.h> 36#include <sys/malloc.h> 37#include <sys/rmlock.h> 38#include <sys/socket.h> 39#include <sys/socketvar.h> 40#include <sys/systm.h> 41#include <sys/condvar.h> 42#include <sys/lock.h> 43#include <sys/mutex.h> 44#include <sys/proc.h> 45#include <sys/queue.h> 46 47#include <net/if.h> 48#include <net/if_var.h> 49#include <net/pfil.h> 50 51static struct mtx pfil_global_lock; 52 53MTX_SYSINIT(pfil_heads_lock, &pfil_global_lock, "pfil_head_list lock", 54 MTX_DEF); 55 56static struct packet_filter_hook *pfil_chain_get(int, struct pfil_head *); 57static int pfil_chain_add(pfil_chain_t *, struct packet_filter_hook *, int); 58static int pfil_chain_remove(pfil_chain_t *, void *, void *); 59static int pfil_add_hook_priv(void *, void *, int, struct pfil_head *, bool); 60 61LIST_HEAD(pfilheadhead, pfil_head); 62VNET_DEFINE(struct pfilheadhead, pfil_head_list); 63#define V_pfil_head_list VNET(pfil_head_list) 64VNET_DEFINE(struct rmlock, pfil_lock); 65 66#define PFIL_LOCK_INIT_REAL(l, t) \ 67 rm_init_flags(l, "PFil " t " rmlock", RM_RECURSE) 68#define PFIL_LOCK_DESTROY_REAL(l) \ 69 rm_destroy(l) 70#define PFIL_LOCK_INIT(p) do { \ 71 if ((p)->flags & PFIL_FLAG_PRIVATE_LOCK) { \ 72 PFIL_LOCK_INIT_REAL(&(p)->ph_lock, "private"); \ 73 (p)->ph_plock = &(p)->ph_lock; \ 74 } else \ 75 (p)->ph_plock = &V_pfil_lock; \ 76} while (0) 77#define PFIL_LOCK_DESTROY(p) do { \ 78 if ((p)->flags & PFIL_FLAG_PRIVATE_LOCK) \ 79 PFIL_LOCK_DESTROY_REAL((p)->ph_plock); \ 80} while (0) 81 82#define PFIL_TRY_RLOCK(p, t) rm_try_rlock((p)->ph_plock, (t)) 83#define PFIL_RLOCK(p, t) rm_rlock((p)->ph_plock, (t)) 84#define PFIL_WLOCK(p) rm_wlock((p)->ph_plock) 85#define PFIL_RUNLOCK(p, t) rm_runlock((p)->ph_plock, (t)) 86#define PFIL_WUNLOCK(p) rm_wunlock((p)->ph_plock) 87#define PFIL_WOWNED(p) rm_wowned((p)->ph_plock) 88 89#define PFIL_HEADLIST_LOCK() mtx_lock(&pfil_global_lock) 90#define PFIL_HEADLIST_UNLOCK() mtx_unlock(&pfil_global_lock) 91 92/* 93 * pfil_run_hooks() runs the specified packet filter hook chain. 94 */ 95int 96pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, 97 int dir, int flags, struct inpcb *inp) 98{ 99 struct rm_priotracker rmpt; 100 struct packet_filter_hook *pfh; 101 struct mbuf *m = *mp; 102 int rv = 0; 103 104 PFIL_RLOCK(ph, &rmpt); 105 KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0")); 106 for (pfh = pfil_chain_get(dir, ph); pfh != NULL; 107 pfh = TAILQ_NEXT(pfh, pfil_chain)) { 108 if (pfh->pfil_func_flags != NULL) { 109 rv = (*pfh->pfil_func_flags)(pfh->pfil_arg, &m, ifp, 110 dir, flags, inp); 111 if (rv != 0 || m == NULL) 112 break; 113 } 114 if (pfh->pfil_func != NULL) { 115 rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, 116 inp); 117 if (rv != 0 || m == NULL) 118 break; 119 } 120 } 121 PFIL_RUNLOCK(ph, &rmpt); 122 *mp = m; 123 return (rv); 124} 125 126static struct packet_filter_hook * 127pfil_chain_get(int dir, struct pfil_head *ph) 128{ 129 130 if (dir == PFIL_IN) 131 return (TAILQ_FIRST(&ph->ph_in)); 132 else if (dir == PFIL_OUT) 133 return (TAILQ_FIRST(&ph->ph_out)); 134 else 135 return (NULL); 136} 137 138/* 139 * pfil_try_rlock() acquires rm reader lock for specified head 140 * if this is immediately possible. 141 */ 142int 143pfil_try_rlock(struct pfil_head *ph, struct rm_priotracker *tracker) 144{ 145 146 return (PFIL_TRY_RLOCK(ph, tracker)); 147} 148 149/* 150 * pfil_rlock() acquires rm reader lock for specified head. 151 */ 152void 153pfil_rlock(struct pfil_head *ph, struct rm_priotracker *tracker) 154{ 155 156 PFIL_RLOCK(ph, tracker); 157} 158 159/* 160 * pfil_runlock() releases reader lock for specified head. 161 */ 162void 163pfil_runlock(struct pfil_head *ph, struct rm_priotracker *tracker) 164{ 165 166 PFIL_RUNLOCK(ph, tracker); 167} 168 169/* 170 * pfil_wlock() acquires writer lock for specified head. 171 */ 172void 173pfil_wlock(struct pfil_head *ph) 174{ 175 176 PFIL_WLOCK(ph); 177} 178 179/* 180 * pfil_wunlock() releases writer lock for specified head. 181 */ 182void 183pfil_wunlock(struct pfil_head *ph) 184{ 185 186 PFIL_WUNLOCK(ph); 187} 188 189/* 190 * pfil_wowned() returns a non-zero value if the current thread owns 191 * an exclusive lock. 192 */ 193int 194pfil_wowned(struct pfil_head *ph) 195{ 196 197 return (PFIL_WOWNED(ph)); 198} 199 200/* 201 * pfil_head_register() registers a pfil_head with the packet filter hook 202 * mechanism. 203 */ 204int 205pfil_head_register(struct pfil_head *ph) 206{ 207 struct pfil_head *lph; 208 209 PFIL_HEADLIST_LOCK(); 210 LIST_FOREACH(lph, &V_pfil_head_list, ph_list) { 211 if (ph->ph_type == lph->ph_type && 212 ph->ph_un.phu_val == lph->ph_un.phu_val) { 213 PFIL_HEADLIST_UNLOCK(); 214 return (EEXIST); 215 } 216 } 217 PFIL_LOCK_INIT(ph); 218 ph->ph_nhooks = 0; 219 TAILQ_INIT(&ph->ph_in); 220 TAILQ_INIT(&ph->ph_out); 221 LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); 222 PFIL_HEADLIST_UNLOCK(); 223 return (0); 224} 225 226/* 227 * pfil_head_unregister() removes a pfil_head from the packet filter hook 228 * mechanism. The producer of the hook promises that all outstanding 229 * invocations of the hook have completed before it unregisters the hook. 230 */ 231int 232pfil_head_unregister(struct pfil_head *ph) 233{ 234 struct packet_filter_hook *pfh, *pfnext; 235 236 PFIL_HEADLIST_LOCK(); 237 LIST_REMOVE(ph, ph_list); 238 PFIL_HEADLIST_UNLOCK(); 239 TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext) 240 free(pfh, M_IFADDR); 241 TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext) 242 free(pfh, M_IFADDR); 243 PFIL_LOCK_DESTROY(ph); 244 return (0); 245} 246 247/* 248 * pfil_head_get() returns the pfil_head for a given key/dlt. 249 */ 250struct pfil_head * 251pfil_head_get(int type, u_long val) 252{ 253 struct pfil_head *ph; 254 255 PFIL_HEADLIST_LOCK(); 256 LIST_FOREACH(ph, &V_pfil_head_list, ph_list) 257 if (ph->ph_type == type && ph->ph_un.phu_val == val) 258 break; 259 PFIL_HEADLIST_UNLOCK(); 260 return (ph); 261} 262 263/* 264 * pfil_add_hook_flags() adds a function to the packet filter hook. the 265 * flags are: 266 * PFIL_IN call me on incoming packets 267 * PFIL_OUT call me on outgoing packets 268 * PFIL_ALL call me on all of the above 269 * PFIL_WAITOK OK to call malloc with M_WAITOK. 270 */ 271int 272pfil_add_hook_flags(pfil_func_flags_t func, void *arg, int flags, 273 struct pfil_head *ph) 274{ 275 return (pfil_add_hook_priv(func, arg, flags, ph, true)); 276} 277 278/* 279 * pfil_add_hook() adds a function to the packet filter hook. the 280 * flags are: 281 * PFIL_IN call me on incoming packets 282 * PFIL_OUT call me on outgoing packets 283 * PFIL_ALL call me on all of the above 284 * PFIL_WAITOK OK to call malloc with M_WAITOK. 285 */ 286int 287pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) 288{ 289 return (pfil_add_hook_priv(func, arg, flags, ph, false)); 290} 291 292static int 293pfil_add_hook_priv(void *func, void *arg, int flags, 294 struct pfil_head *ph, bool hasflags) 295{ 296 struct packet_filter_hook *pfh1 = NULL; 297 struct packet_filter_hook *pfh2 = NULL; 298 int err; 299 300 if (flags & PFIL_IN) { 301 pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), 302 M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); 303 if (pfh1 == NULL) { 304 err = ENOMEM; 305 goto error; 306 } 307 } 308 if (flags & PFIL_OUT) { 309 pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), 310 M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); 311 if (pfh2 == NULL) { 312 err = ENOMEM; 313 goto error; 314 } 315 } 316 PFIL_WLOCK(ph); 317 if (flags & PFIL_IN) { 318 pfh1->pfil_func_flags = hasflags ? func : NULL; 319 pfh1->pfil_func = hasflags ? NULL : func; 320 pfh1->pfil_arg = arg; 321 err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); 322 if (err) 323 goto locked_error; 324 ph->ph_nhooks++; 325 } 326 if (flags & PFIL_OUT) { 327 pfh2->pfil_func_flags = hasflags ? func : NULL; 328 pfh2->pfil_func = hasflags ? NULL : func; 329 pfh2->pfil_arg = arg; 330 err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN); 331 if (err) { 332 if (flags & PFIL_IN) 333 pfil_chain_remove(&ph->ph_in, func, arg); 334 goto locked_error; 335 } 336 ph->ph_nhooks++; 337 } 338 PFIL_WUNLOCK(ph); 339 return (0); 340locked_error: 341 PFIL_WUNLOCK(ph); 342error: 343 if (pfh1 != NULL) 344 free(pfh1, M_IFADDR); 345 if (pfh2 != NULL) 346 free(pfh2, M_IFADDR); 347 return (err); 348} 349 350/* 351 * pfil_remove_hook_flags removes a specific function from the packet filter hook 352 * chain. 353 */ 354int 355pfil_remove_hook_flags(pfil_func_flags_t func, void *arg, int flags, 356 struct pfil_head *ph) 357{ 358 return (pfil_remove_hook((pfil_func_t)func, arg, flags, ph)); 359} 360 361/* 362 * pfil_remove_hook removes a specific function from the packet filter hook 363 * chain. 364 */ 365int 366pfil_remove_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) 367{ 368 int err = 0; 369 370 PFIL_WLOCK(ph); 371 if (flags & PFIL_IN) { 372 err = pfil_chain_remove(&ph->ph_in, func, arg); 373 if (err == 0) 374 ph->ph_nhooks--; 375 } 376 if ((err == 0) && (flags & PFIL_OUT)) { 377 err = pfil_chain_remove(&ph->ph_out, func, arg); 378 if (err == 0) 379 ph->ph_nhooks--; 380 } 381 PFIL_WUNLOCK(ph); 382 return (err); 383} 384 385/* 386 * Internal: Add a new pfil hook into a hook chain. 387 */ 388static int 389pfil_chain_add(pfil_chain_t *chain, struct packet_filter_hook *pfh1, int flags) 390{ 391 struct packet_filter_hook *pfh; 392 393 /* 394 * First make sure the hook is not already there. 395 */ 396 TAILQ_FOREACH(pfh, chain, pfil_chain) 397 if (((pfh->pfil_func != NULL && pfh->pfil_func == pfh1->pfil_func) || 398 (pfh->pfil_func_flags != NULL && 399 pfh->pfil_func_flags == pfh1->pfil_func_flags)) && 400 pfh->pfil_arg == pfh1->pfil_arg) 401 return (EEXIST); 402 403 /* 404 * Insert the input list in reverse order of the output list so that 405 * the same path is followed in or out of the kernel. 406 */ 407 if (flags & PFIL_IN) 408 TAILQ_INSERT_HEAD(chain, pfh1, pfil_chain); 409 else 410 TAILQ_INSERT_TAIL(chain, pfh1, pfil_chain); 411 return (0); 412} 413 414/* 415 * Internal: Remove a pfil hook from a hook chain. 416 */ 417static int 418pfil_chain_remove(pfil_chain_t *chain, void *func, void *arg) 419{ 420 struct packet_filter_hook *pfh; 421 422 TAILQ_FOREACH(pfh, chain, pfil_chain) 423 if ((pfh->pfil_func == func || pfh->pfil_func_flags == func) && 424 pfh->pfil_arg == arg) { 425 TAILQ_REMOVE(chain, pfh, pfil_chain); 426 free(pfh, M_IFADDR); 427 return (0); 428 } 429 return (ENOENT); 430} 431 432/* 433 * Stuff that must be initialized for every instance (including the first of 434 * course). 435 */ 436static void 437vnet_pfil_init(const void *unused __unused) 438{ 439 440 LIST_INIT(&V_pfil_head_list); 441 PFIL_LOCK_INIT_REAL(&V_pfil_lock, "shared"); 442} 443 444/* 445 * Called for the removal of each instance. 446 */ 447static void 448vnet_pfil_uninit(const void *unused __unused) 449{ 450 451 KASSERT(LIST_EMPTY(&V_pfil_head_list), 452 ("%s: pfil_head_list %p not empty", __func__, &V_pfil_head_list)); 453 PFIL_LOCK_DESTROY_REAL(&V_pfil_lock); 454} 455 456/* 457 * Starting up. 458 * 459 * VNET_SYSINIT is called for each existing vnet and each new vnet. 460 * Make sure the pfil bits are first before any possible subsystem which 461 * might piggyback on the SI_SUB_PROTO_PFIL. 462 */ 463VNET_SYSINIT(vnet_pfil_init, SI_SUB_PROTO_PFIL, SI_ORDER_FIRST, 464 vnet_pfil_init, NULL); 465 466/* 467 * Closing up shop. These are done in REVERSE ORDER. Not called on reboot. 468 * 469 * VNET_SYSUNINIT is called for each exiting vnet as it exits. 470 */ 471VNET_SYSUNINIT(vnet_pfil_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_FIRST, 472 vnet_pfil_uninit, NULL); 473