pfil.c revision 254774
1178825Sdfr/* $FreeBSD: head/sys/net/pfil.c 254774 2013-08-24 11:24:15Z andre $ */ 2102644Snectar/* $NetBSD: pfil.c,v 1.20 2001/11/12 23:49:46 lukem Exp $ */ 355682Smarkm 4142403Snectar/*- 5178825Sdfr * Copyright (c) 1996 Matthew R. Green 655682Smarkm * All rights reserved. 755682Smarkm * 855682Smarkm * Redistribution and use in source and binary forms, with or without 955682Smarkm * modification, are permitted provided that the following conditions 1055682Smarkm * are met: 1155682Smarkm * 1. Redistributions of source code must retain the above copyright 1255682Smarkm * notice, this list of conditions and the following disclaimer. 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1590926Snectar * documentation and/or other materials provided with the distribution. 1690926Snectar * 3. The name of the author may not be used to endorse or promote products 17178825Sdfr * derived from this software without specific prior written permission. 1890926Snectar * 19178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2090926Snectar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21178825Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2255682Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2355682Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2455682Smarkm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2555682Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2655682Smarkm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27102644Snectar * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28102644Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29102644Snectar * SUCH DAMAGE. 30127808Snectar */ 3190926Snectar 32127808Snectar#include <sys/param.h> 3355682Smarkm#include <sys/kernel.h> 3455682Smarkm#include <sys/errno.h> 3555682Smarkm#include <sys/lock.h> 3655682Smarkm#include <sys/malloc.h> 3755682Smarkm#include <sys/rmlock.h> 3855682Smarkm#include <sys/socket.h> 39178825Sdfr#include <sys/socketvar.h> 4055682Smarkm#include <sys/systm.h> 41142403Snectar#include <sys/condvar.h> 42142403Snectar#include <sys/lock.h> 43142403Snectar#include <sys/mutex.h> 44142403Snectar#include <sys/proc.h> 45142403Snectar#include <sys/queue.h> 46142403Snectar 47178825Sdfr#include <net/if.h> 48178825Sdfr#include <net/pfil.h> 49142403Snectar 50142403Snectarstatic struct mtx pfil_global_lock; 51142403Snectar 52178825SdfrMTX_SYSINIT(pfil_heads_lock, &pfil_global_lock, "pfil_head_list lock", 53142403Snectar MTX_DEF); 54142403Snectar 55142403Snectarstatic struct packet_filter_hook *pfil_chain_get(int, struct pfil_head *); 56142403Snectarstatic int pfil_chain_add(pfil_chain_t *, struct packet_filter_hook *, int); 57142403Snectarstatic int pfil_chain_remove(pfil_chain_t *, pfil_func_t, void *); 58142403Snectar 59142403SnectarLIST_HEAD(pfilheadhead, pfil_head); 60142403SnectarVNET_DEFINE(struct pfilheadhead, pfil_head_list); 61142403Snectar#define V_pfil_head_list VNET(pfil_head_list) 62142403SnectarVNET_DEFINE(struct rmlock, pfil_lock); 63142403Snectar#define V_pfil_lock VNET(pfil_lock) 64142403Snectar 65142403Snectar/* 66142403Snectar * pfil_run_hooks() runs the specified packet filter hook chain. 67142403Snectar */ 68142403Snectarint 69142403Snectarpfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, 70142403Snectar int dir, struct inpcb *inp) 71142403Snectar{ 72178825Sdfr struct rm_priotracker rmpt; 73142403Snectar struct packet_filter_hook *pfh; 74142403Snectar struct mbuf *m = *mp; 75142403Snectar int rv = 0; 76142403Snectar 77142403Snectar PFIL_RLOCK(ph, &rmpt); 78142403Snectar KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0")); 79142403Snectar for (pfh = pfil_chain_get(dir, ph); pfh != NULL; 80142403Snectar pfh = TAILQ_NEXT(pfh, pfil_chain)) { 81178825Sdfr if (pfh->pfil_func != NULL) { 82178825Sdfr rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, 83178825Sdfr inp); 84178825Sdfr if (rv != 0 || m == NULL) 85178825Sdfr break; 86178825Sdfr } 87178825Sdfr } 88178825Sdfr PFIL_RUNLOCK(ph, &rmpt); 89178825Sdfr *mp = m; 90178825Sdfr return (rv); 91178825Sdfr} 92142403Snectar 93142403Snectarstatic struct packet_filter_hook * 94178825Sdfrpfil_chain_get(int dir, struct pfil_head *ph) 95142403Snectar{ 96142403Snectar 97178825Sdfr if (dir == PFIL_IN) 98178825Sdfr return (TAILQ_FIRST(&ph->ph_in)); 99178825Sdfr else if (dir == PFIL_OUT) 100142403Snectar return (TAILQ_FIRST(&ph->ph_out)); 101142403Snectar else 102142403Snectar return (NULL); 103142403Snectar} 104142403Snectar 105142403Snectar/* 106142403Snectar * pfil_try_rlock() acquires rm reader lock for specified head 107142403Snectar * if this is immediately possible. 108142403Snectar */ 109142403Snectarint 110142403Snectarpfil_try_rlock(struct pfil_head *ph, struct rm_priotracker *tracker) 111142403Snectar{ 112142403Snectar 113142403Snectar return (PFIL_TRY_RLOCK(ph, tracker)); 114178825Sdfr} 115178825Sdfr 116142403Snectar/* 117142403Snectar * pfil_rlock() acquires rm reader lock for specified head. 118178825Sdfr */ 119178825Sdfrvoid 120178825Sdfrpfil_rlock(struct pfil_head *ph, struct rm_priotracker *tracker) 121178825Sdfr{ 122142403Snectar 123142403Snectar PFIL_RLOCK(ph, tracker); 124142403Snectar} 125142403Snectar 126142403Snectar/* 127178825Sdfr * pfil_runlock() releases reader lock for specified head. 128142403Snectar */ 129178825Sdfrvoid 130178825Sdfrpfil_runlock(struct pfil_head *ph, struct rm_priotracker *tracker) 131178825Sdfr{ 132178825Sdfr 133178825Sdfr PFIL_RUNLOCK(ph, tracker); 134178825Sdfr} 135178825Sdfr 136178825Sdfr/* 137178825Sdfr * pfil_wlock() acquires writer lock for specified head. 138178825Sdfr */ 139178825Sdfrvoid 140142403Snectarpfil_wlock(struct pfil_head *ph) 141142403Snectar{ 142142403Snectar 143142403Snectar PFIL_WLOCK(ph); 144178825Sdfr} 145178825Sdfr 146178825Sdfr/* 147142403Snectar * pfil_wunlock() releases writer lock for specified head. 148178825Sdfr */ 149178825Sdfrvoid 150178825Sdfrpfil_wunlock(struct pfil_head *ph) 151178825Sdfr{ 152178825Sdfr 153178825Sdfr PFIL_WUNLOCK(ph); 154178825Sdfr} 155178825Sdfr 156142403Snectar/* 157142403Snectar * pfil_wowned() returns a non-zero value if the current thread owns 158142403Snectar * an exclusive lock. 159142403Snectar */ 160142403Snectarint 161127808Snectarpfil_wowned(struct pfil_head *ph) 16255682Smarkm{ 16372445Sassar 164127808Snectar return (PFIL_WOWNED(ph)); 165127808Snectar} 166127808Snectar 167127808Snectar/* 16855682Smarkm * pfil_head_register() registers a pfil_head with the packet filter hook 16955682Smarkm * mechanism. 17055682Smarkm */ 17155682Smarkmint 17255682Smarkmpfil_head_register(struct pfil_head *ph) 173127808Snectar{ 17490926Snectar struct pfil_head *lph; 17572445Sassar 176127808Snectar PFIL_HEADLIST_LOCK(); 177127808Snectar LIST_FOREACH(lph, &V_pfil_head_list, ph_list) { 178127808Snectar if (ph->ph_type == lph->ph_type && 179127808Snectar ph->ph_un.phu_val == lph->ph_un.phu_val) { 180127808Snectar PFIL_HEADLIST_UNLOCK(); 18155682Smarkm return (EEXIST); 182127808Snectar } 18390926Snectar } 184178825Sdfr PFIL_LOCK_INIT(ph); 185178825Sdfr ph->ph_nhooks = 0; 18672445Sassar TAILQ_INIT(&ph->ph_in); 187102644Snectar TAILQ_INIT(&ph->ph_out); 188127808Snectar LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); 189127808Snectar PFIL_HEADLIST_UNLOCK(); 190127808Snectar return (0); 191127808Snectar} 192127808Snectar 193127808Snectar/* 194127808Snectar * pfil_head_unregister() removes a pfil_head from the packet filter hook 195178825Sdfr * mechanism. The producer of the hook promises that all outstanding 19655682Smarkm * invocations of the hook have completed before it unregisters the hook. 19772445Sassar */ 198178825Sdfrint 199127808Snectarpfil_head_unregister(struct pfil_head *ph) 200127808Snectar{ 201127808Snectar struct packet_filter_hook *pfh, *pfnext; 202127808Snectar 203178825Sdfr PFIL_HEADLIST_LOCK(); 204127808Snectar LIST_REMOVE(ph, ph_list); 205127808Snectar PFIL_HEADLIST_UNLOCK(); 206127808Snectar TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext) 20790926Snectar free(pfh, M_IFADDR); 208127808Snectar TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext) 209178825Sdfr free(pfh, M_IFADDR); 21055682Smarkm PFIL_LOCK_DESTROY(ph); 211102644Snectar return (0); 212102644Snectar} 213178825Sdfr 214127808Snectar/* 215127808Snectar * pfil_head_get() returns the pfil_head for a given key/dlt. 21655682Smarkm */ 21755682Smarkmstruct pfil_head * 21890926Snectarpfil_head_get(int type, u_long val) 219127808Snectar{ 220127808Snectar struct pfil_head *ph; 221127808Snectar 222127808Snectar PFIL_HEADLIST_LOCK(); 223127808Snectar LIST_FOREACH(ph, &V_pfil_head_list, ph_list) 22490926Snectar if (ph->ph_type == type && ph->ph_un.phu_val == val) 22590926Snectar break; 22690926Snectar PFIL_HEADLIST_UNLOCK(); 227127808Snectar return (ph); 228127808Snectar} 229127808Snectar 230127808Snectar/* 231127808Snectar * pfil_add_hook() adds a function to the packet filter hook. the 232127808Snectar * flags are: 233178825Sdfr * PFIL_IN call me on incoming packets 234127808Snectar * PFIL_OUT call me on outgoing packets 235127808Snectar * PFIL_ALL call me on all of the above 236127808Snectar * PFIL_WAITOK OK to call malloc with M_WAITOK. 237127808Snectar */ 238127808Snectarint 239127808Snectarpfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) 240127808Snectar{ 241127808Snectar struct packet_filter_hook *pfh1 = NULL; 242127808Snectar struct packet_filter_hook *pfh2 = NULL; 243178825Sdfr int err; 244178825Sdfr 245178825Sdfr if (flags & PFIL_IN) { 246178825Sdfr pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), 247127808Snectar M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); 248127808Snectar if (pfh1 == NULL) { 24955682Smarkm err = ENOMEM; 250127808Snectar goto error; 251127808Snectar } 252127808Snectar } 253127808Snectar if (flags & PFIL_OUT) { 254127808Snectar pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), 255127808Snectar M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); 25655682Smarkm if (pfh2 == NULL) { 257127808Snectar err = ENOMEM; 258127808Snectar goto error; 259178825Sdfr } 260127808Snectar } 261127808Snectar PFIL_WLOCK(ph); 26255682Smarkm if (flags & PFIL_IN) { 26355682Smarkm pfh1->pfil_func = func; 264127808Snectar pfh1->pfil_arg = arg; 265127808Snectar err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); 266127808Snectar if (err) 267127808Snectar goto locked_error; 26855682Smarkm ph->ph_nhooks++; 26955682Smarkm } 270120945Snectar if (flags & PFIL_OUT) { 271127808Snectar pfh2->pfil_func = func; 272178825Sdfr pfh2->pfil_arg = arg; 27355682Smarkm err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN); 274127808Snectar if (err) { 27555682Smarkm if (flags & PFIL_IN) 276127808Snectar pfil_chain_remove(&ph->ph_in, func, arg); 277127808Snectar goto locked_error; 278127808Snectar } 279127808Snectar ph->ph_nhooks++; 280127808Snectar } 281127808Snectar PFIL_WUNLOCK(ph); 282178825Sdfr return (0); 283178825Sdfrlocked_error: 28455682Smarkm PFIL_WUNLOCK(ph); 285127808Snectarerror: 286127808Snectar if (pfh1 != NULL) 287102644Snectar free(pfh1, M_IFADDR); 28855682Smarkm if (pfh2 != NULL) 289178825Sdfr free(pfh2, M_IFADDR); 29055682Smarkm return (err); 29155682Smarkm} 29255682Smarkm 29355682Smarkm/* 294178825Sdfr * pfil_remove_hook removes a specific function from the packet filter hook 29590926Snectar * chain. 29690926Snectar */ 29790926Snectarint 29890926Snectarpfil_remove_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) 29955682Smarkm{ 300178825Sdfr int err = 0; 301178825Sdfr 302178825Sdfr PFIL_WLOCK(ph); 303178825Sdfr if (flags & PFIL_IN) { 304178825Sdfr err = pfil_chain_remove(&ph->ph_in, func, arg); 305127808Snectar if (err == 0) 306127808Snectar ph->ph_nhooks--; 307127808Snectar } 308127808Snectar if ((err == 0) && (flags & PFIL_OUT)) { 309178825Sdfr err = pfil_chain_remove(&ph->ph_out, func, arg); 310178825Sdfr if (err == 0) 311127808Snectar ph->ph_nhooks--; 312127808Snectar } 313127808Snectar PFIL_WUNLOCK(ph); 314127808Snectar return (err); 315127808Snectar} 316127808Snectar 317178825Sdfr/* 318127808Snectar * Internal: Add a new pfil hook into a hook chain. 319178825Sdfr */ 320178825Sdfrstatic int 321102644Snectarpfil_chain_add(pfil_chain_t *chain, struct packet_filter_hook *pfh1, int flags) 322102644Snectar{ 323102644Snectar struct packet_filter_hook *pfh; 324178825Sdfr 325127808Snectar /* 326127808Snectar * First make sure the hook is not already there. 327127808Snectar */ 328127808Snectar TAILQ_FOREACH(pfh, chain, pfil_chain) 329127808Snectar if (pfh->pfil_func == pfh1->pfil_func && 330127808Snectar pfh->pfil_arg == pfh1->pfil_arg) 331178825Sdfr return (EEXIST); 332127808Snectar 333127808Snectar /* 33472445Sassar * Insert the input list in reverse order of the output list so that 335127808Snectar * the same path is followed in or out of the kernel. 336127808Snectar */ 337178825Sdfr if (flags & PFIL_IN) 338127808Snectar TAILQ_INSERT_HEAD(chain, pfh1, pfil_chain); 339127808Snectar else 340142403Snectar TAILQ_INSERT_TAIL(chain, pfh1, pfil_chain); 341127808Snectar return (0); 342178825Sdfr} 343127808Snectar 344127808Snectar/* 345178825Sdfr * Internal: Remove a pfil hook from a hook chain. 346127808Snectar */ 347127808Snectarstatic int 348178825Sdfrpfil_chain_remove(pfil_chain_t *chain, pfil_func_t func, void *arg) 349127808Snectar{ 350127808Snectar struct packet_filter_hook *pfh; 351178825Sdfr 352178825Sdfr TAILQ_FOREACH(pfh, chain, pfil_chain) 353178825Sdfr if (pfh->pfil_func == func && pfh->pfil_arg == arg) { 354178825Sdfr TAILQ_REMOVE(chain, pfh, pfil_chain); 355178825Sdfr free(pfh, M_IFADDR); 356102644Snectar return (0); 35790926Snectar } 35872445Sassar return (ENOENT); 35955682Smarkm} 36055682Smarkm 36155682Smarkm/* 36255682Smarkm * Stuff that must be initialized for every instance (including the first of 36355682Smarkm * course). 36455682Smarkm */ 36555682Smarkmstatic int 36655682Smarkmvnet_pfil_init(const void *unused) 367120945Snectar{ 36890926Snectar 36972445Sassar LIST_INIT(&V_pfil_head_list); 37055682Smarkm PFIL_LOCK_INIT_REAL(&V_pfil_lock, "shared"); 37190926Snectar return (0); 372178825Sdfr} 37390926Snectar 374178825Sdfr/* 37572445Sassar * Called for the removal of each instance. 376178825Sdfr */ 37772445Sassarstatic int 378178825Sdfrvnet_pfil_uninit(const void *unused) 379178825Sdfr{ 38072445Sassar 38172445Sassar KASSERT(LIST_EMPTY(&V_pfil_head_list), 38272445Sassar ("%s: pfil_head_list %p not empty", __func__, &V_pfil_head_list)); 38372445Sassar PFIL_LOCK_DESTROY_REAL(&V_pfil_lock); 38472445Sassar return (0); 38572445Sassar} 38672445Sassar 38772445Sassar/* Define startup order. */ 38872445Sassar#define PFIL_SYSINIT_ORDER SI_SUB_PROTO_BEGIN 38972445Sassar#define PFIL_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ 39072445Sassar#define PFIL_VNET_ORDER (PFIL_MODEVENT_ORDER + 2) /* Later still. */ 391178825Sdfr 39272445Sassar/* 393178825Sdfr * Starting up. 39472445Sassar * 39572445Sassar * VNET_SYSINIT is called for each existing vnet and each new vnet. 39655682Smarkm */ 397178825SdfrVNET_SYSINIT(vnet_pfil_init, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER, 398178825Sdfr vnet_pfil_init, NULL); 399178825Sdfr 400178825Sdfr/* 401178825Sdfr * Closing up shop. These are done in REVERSE ORDER. Not called on reboot. 40272445Sassar * 40372445Sassar * VNET_SYSUNINIT is called for each exiting vnet as it exits. 40472445Sassar */ 40572445SassarVNET_SYSUNINIT(vnet_pfil_uninit, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER, 40672445Sassar vnet_pfil_uninit, NULL); 40772445Sassar