pfil.c revision 1.16
1/* $NetBSD: pfil.c,v 1.16 2000/11/11 00:52:36 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1996 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/param.h> 32#include <sys/errno.h> 33#include <sys/malloc.h> 34#include <sys/socket.h> 35#include <sys/socketvar.h> 36#include <sys/systm.h> 37#include <sys/proc.h> 38#include <sys/queue.h> 39 40#include <net/if.h> 41#include <net/pfil.h> 42 43static int pfil_list_add(pfil_list_t *, 44 int (*)(void *, struct mbuf **, struct ifnet *, int), void *, int); 45 46static int pfil_list_remove(pfil_list_t *, 47 int (*)(void *, struct mbuf **, struct ifnet *, int), void *); 48 49LIST_HEAD(, pfil_head) pfil_head_list = 50 LIST_HEAD_INITIALIZER(&pfil_head_list); 51 52/* 53 * pfil_run_hooks() runs the specified packet filter hooks. 54 */ 55int 56pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, 57 int dir) 58{ 59 struct packet_filter_hook *pfh; 60 struct mbuf *m = *mp; 61 int rv = 0; 62 63 for (pfh = pfil_hook_get(dir, ph); pfh != NULL; 64 pfh = TAILQ_NEXT(pfh, pfil_link)) { 65 if (pfh->pfil_func != NULL) { 66 rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir); 67 if (rv != 0 || m == NULL) 68 break; 69 } 70 } 71 72 *mp = m; 73 return (rv); 74} 75 76/* 77 * pfil_head_register() registers a pfil_head with the packet filter 78 * hook mechanism. 79 */ 80int 81pfil_head_register(struct pfil_head *ph) 82{ 83 struct pfil_head *lph; 84 85 for (lph = LIST_FIRST(&pfil_head_list); lph != NULL; 86 lph = LIST_NEXT(lph, ph_list)) { 87 if (lph->ph_key == ph->ph_key && 88 lph->ph_dlt == ph->ph_dlt) 89 return EEXIST; 90 } 91 92 TAILQ_INIT(&ph->ph_in); 93 TAILQ_INIT(&ph->ph_out); 94 95 LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list); 96 97 return (0); 98} 99 100/* 101 * pfil_head_unregister() removes a pfil_head from the packet filter 102 * hook mechanism. 103 */ 104int 105pfil_head_unregister(struct pfil_head *pfh) 106{ 107 108 LIST_REMOVE(pfh, ph_list); 109 return (0); 110} 111 112/* 113 * pfil_head_get() returns the pfil_head for a given key/dlt. 114 */ 115struct pfil_head * 116pfil_head_get(void *key, int dlt) 117{ 118 struct pfil_head *ph; 119 120 for (ph = LIST_FIRST(&pfil_head_list); ph != NULL; 121 ph = LIST_NEXT(ph, ph_list)) { 122 if (ph->ph_key == key && ph->ph_dlt == dlt) 123 break; 124 } 125 126 return (ph); 127} 128 129/* 130 * pfil_add_hook() adds a function to the packet filter hook. the 131 * flags are: 132 * PFIL_IN call me on incoming packets 133 * PFIL_OUT call me on outgoing packets 134 * PFIL_ALL call me on all of the above 135 * PFIL_WAITOK OK to call malloc with M_WAITOK. 136 */ 137int 138pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int), 139 void *arg, int flags, struct pfil_head *ph) 140{ 141 int err = 0; 142 143 if (flags & PFIL_IN) { 144 err = pfil_list_add(&ph->ph_in, func, arg, flags & ~PFIL_OUT); 145 if (err) 146 return err; 147 } 148 if (flags & PFIL_OUT) { 149 err = pfil_list_add(&ph->ph_out, func, arg, flags & ~PFIL_IN); 150 if (err) { 151 if (flags & PFIL_IN) 152 pfil_list_remove(&ph->ph_in, func, arg); 153 return err; 154 } 155 } 156 return 0; 157} 158 159static int 160pfil_list_add(pfil_list_t *list, 161 int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg, 162 int flags) 163{ 164 struct packet_filter_hook *pfh; 165 166 /* 167 * First make sure the hook is not already there. 168 */ 169 for (pfh = TAILQ_FIRST(list); pfh != NULL; 170 pfh = TAILQ_NEXT(pfh, pfil_link)) { 171 if (pfh->pfil_func == func && 172 pfh->pfil_arg == arg) 173 return EEXIST; 174 } 175 176 pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR, 177 (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); 178 if (pfh == NULL) 179 return ENOMEM; 180 181 pfh->pfil_func = func; 182 pfh->pfil_arg = arg; 183 184 /* 185 * insert the input list in reverse order of the output list 186 * so that the same path is followed in or out of the kernel. 187 */ 188 if (flags & PFIL_IN) 189 TAILQ_INSERT_HEAD(list, pfh, pfil_link); 190 else 191 TAILQ_INSERT_TAIL(list, pfh, pfil_link); 192 193 return 0; 194} 195 196/* 197 * pfil_remove_hook removes a specific function from the packet filter 198 * hook list. 199 */ 200int 201pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int), 202 void *arg, int flags, struct pfil_head *ph) 203{ 204 int err = 0; 205 206 if (flags & PFIL_IN) 207 err = pfil_list_remove(&ph->ph_in, func, arg); 208 if ((err == 0) && (flags & PFIL_OUT)) 209 err = pfil_list_remove(&ph->ph_out, func, arg); 210 return err; 211} 212 213/* 214 * pfil_list_remove is an internal function that takes a function off the 215 * specified list. 216 */ 217static int 218pfil_list_remove(pfil_list_t *list, 219 int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg) 220{ 221 struct packet_filter_hook *pfh; 222 223 for (pfh = TAILQ_FIRST(list); pfh != NULL; 224 pfh = TAILQ_NEXT(pfh, pfil_link)) { 225 if (pfh->pfil_func == func && pfh->pfil_arg == arg) { 226 TAILQ_REMOVE(list, pfh, pfil_link); 227 free(pfh, M_IFADDR); 228 return 0; 229 } 230 } 231 return ENOENT; 232} 233