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