pfil.c revision 71999
1/* $FreeBSD: head/sys/net/pfil.c 71999 2001-02-04 13:13:25Z phk $ */ 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/queue.h> 38 39#include <net/if.h> 40#include <net/pfil.h> 41 42static void pfil_init __P((struct pfil_head *)); 43static int pfil_list_add(pfil_list_t *, 44 int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)), int); 45static int pfil_list_remove(pfil_list_t *, 46 int (*) __P((void *, int, struct ifnet *, int, struct mbuf **))); 47 48static void 49pfil_init(ph) 50 struct pfil_head *ph; 51{ 52 53 TAILQ_INIT(&ph->ph_in); 54 TAILQ_INIT(&ph->ph_out); 55 ph->ph_init = 1; 56} 57 58/* 59 * pfil_add_hook() adds a function to the packet filter hook. the 60 * flags are: 61 * PFIL_IN call me on incoming packets 62 * PFIL_OUT call me on outgoing packets 63 * PFIL_ALL call me on all of the above 64 * PFIL_WAITOK OK to call malloc with M_WAITOK. 65 */ 66int 67pfil_add_hook(func, flags, ph) 68 int (*func) __P((void *, int, struct ifnet *, int, 69 struct mbuf **)); 70 int flags; 71 struct pfil_head *ph; 72{ 73 int err = 0; 74 75 if (ph->ph_init == 0) 76 pfil_init(ph); 77 78 if (flags & PFIL_IN) 79 err = pfil_list_add(&ph->ph_in, func, flags & ~PFIL_OUT); 80 if (err) 81 return err; 82 if (flags & PFIL_OUT) 83 err = pfil_list_add(&ph->ph_out, func, flags & ~PFIL_IN); 84 if (err) { 85 if (flags & PFIL_IN) 86 pfil_list_remove(&ph->ph_in, func); 87 return err; 88 } 89 return 0; 90} 91 92static int 93pfil_list_add(list, func, flags) 94 pfil_list_t *list; 95 int (*func) __P((void *, int, struct ifnet *, int, 96 struct mbuf **)); 97 int flags; 98{ 99 struct packet_filter_hook *pfh; 100 101 pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR, 102 flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT); 103 if (pfh == NULL) 104 return ENOMEM; 105 pfh->pfil_func = func; 106 /* 107 * insert the input list in reverse order of the output list 108 * so that the same path is followed in or out of the kernel. 109 */ 110 111 if (flags & PFIL_IN) 112 TAILQ_INSERT_HEAD(list, pfh, pfil_link); 113 else 114 TAILQ_INSERT_TAIL(list, pfh, pfil_link); 115 return 0; 116} 117 118/* 119 * pfil_remove_hook removes a specific function from the packet filter 120 * hook list. 121 */ 122int 123pfil_remove_hook(func, flags, ph) 124 int (*func) __P((void *, int, struct ifnet *, int, 125 struct mbuf **)); 126 int flags; 127 struct pfil_head *ph; 128{ 129 int err = 0; 130 131 if (ph->ph_init == 0) 132 pfil_init(ph); 133 134 if (flags & PFIL_IN) 135 err = pfil_list_remove(&ph->ph_in, func); 136 if ((err == 0) && (flags & PFIL_OUT)) 137 err = pfil_list_remove(&ph->ph_out, func); 138 return err; 139} 140 141/* 142 * pfil_list_remove is an internal function that takes a function off the 143 * specified list. 144 */ 145static int 146pfil_list_remove(list, func) 147 pfil_list_t *list; 148 int (*func) __P((void *, int, struct ifnet *, int, 149 struct mbuf **)); 150{ 151 struct packet_filter_hook *pfh; 152 153 TAILQ_FOREACH(pfh, list, pfil_link) 154 if (pfh->pfil_func == func) { 155 TAILQ_REMOVE(list, pfh, pfil_link); 156 free(pfh, M_IFADDR); 157 return 0; 158 } 159 return ENOENT; 160} 161 162struct packet_filter_hook * 163pfil_hook_get(flag, ph) 164 int flag; 165 struct pfil_head *ph; 166{ 167 if (ph->ph_init != 0) 168 switch (flag) { 169 case PFIL_IN: 170 return (TAILQ_FIRST(&ph->ph_in)); 171 case PFIL_OUT: 172 return (TAILQ_FIRST(&ph->ph_out)); 173 } 174 return NULL; 175} 176