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