xref: /freebsd/sys/net/pfil.c (revision e9c7bebf95ab5d00e3577cb76c483a369c116ed0)
1e9c7bebfSDarren Reed /*	$FreeBSD$	*/
2e9c7bebfSDarren Reed 
3e9c7bebfSDarren Reed /*
4e9c7bebfSDarren Reed  * Copyright (c) 1996 Matthew R. Green
5e9c7bebfSDarren Reed  * All rights reserved.
6e9c7bebfSDarren Reed  *
7e9c7bebfSDarren Reed  * Redistribution and use in source and binary forms, with or without
8e9c7bebfSDarren Reed  * modification, are permitted provided that the following conditions
9e9c7bebfSDarren Reed  * are met:
10e9c7bebfSDarren Reed  * 1. Redistributions of source code must retain the above copyright
11e9c7bebfSDarren Reed  *    notice, this list of conditions and the following disclaimer.
12e9c7bebfSDarren Reed  * 2. Redistributions in binary form must reproduce the above copyright
13e9c7bebfSDarren Reed  *    notice, this list of conditions and the following disclaimer in the
14e9c7bebfSDarren Reed  *    documentation and/or other materials provided with the distribution.
15e9c7bebfSDarren Reed  * 3. The name of the author may not be used to endorse or promote products
16e9c7bebfSDarren Reed  *    derived from this software without specific prior written permission.
17e9c7bebfSDarren Reed  *
18e9c7bebfSDarren Reed  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19e9c7bebfSDarren Reed  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20e9c7bebfSDarren Reed  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21e9c7bebfSDarren Reed  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22e9c7bebfSDarren Reed  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23e9c7bebfSDarren Reed  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24e9c7bebfSDarren Reed  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25e9c7bebfSDarren Reed  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26e9c7bebfSDarren Reed  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27e9c7bebfSDarren Reed  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28e9c7bebfSDarren Reed  * SUCH DAMAGE.
29e9c7bebfSDarren Reed  */
30e9c7bebfSDarren Reed 
31e9c7bebfSDarren Reed #include <sys/param.h>
32e9c7bebfSDarren Reed #include <sys/errno.h>
33e9c7bebfSDarren Reed #include <sys/malloc.h>
34e9c7bebfSDarren Reed #include <sys/socket.h>
35e9c7bebfSDarren Reed #include <sys/socketvar.h>
36e9c7bebfSDarren Reed #include <sys/systm.h>
37e9c7bebfSDarren Reed #include <sys/proc.h>
38e9c7bebfSDarren Reed #include <sys/queue.h>
39e9c7bebfSDarren Reed 
40e9c7bebfSDarren Reed #include <net/if.h>
41e9c7bebfSDarren Reed #include <net/pfil.h>
42e9c7bebfSDarren Reed 
43e9c7bebfSDarren Reed static void pfil_init __P((struct pfil_head *));
44e9c7bebfSDarren Reed static int pfil_list_add(pfil_list_t *,
45e9c7bebfSDarren Reed     int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)), int);
46e9c7bebfSDarren Reed static int pfil_list_remove(pfil_list_t *,
47e9c7bebfSDarren Reed     int (*) __P((void *, int, struct ifnet *, int, struct mbuf **)));
48e9c7bebfSDarren Reed 
49e9c7bebfSDarren Reed static void
50e9c7bebfSDarren Reed pfil_init(ph)
51e9c7bebfSDarren Reed 	 struct pfil_head *ph;
52e9c7bebfSDarren Reed {
53e9c7bebfSDarren Reed 
54e9c7bebfSDarren Reed 	TAILQ_INIT(&ph->ph_in);
55e9c7bebfSDarren Reed 	TAILQ_INIT(&ph->ph_out);
56e9c7bebfSDarren Reed 	ph->ph_init = 1;
57e9c7bebfSDarren Reed }
58e9c7bebfSDarren Reed 
59e9c7bebfSDarren Reed /*
60e9c7bebfSDarren Reed  * pfil_add_hook() adds a function to the packet filter hook.  the
61e9c7bebfSDarren Reed  * flags are:
62e9c7bebfSDarren Reed  *	PFIL_IN		call me on incoming packets
63e9c7bebfSDarren Reed  *	PFIL_OUT	call me on outgoing packets
64e9c7bebfSDarren Reed  *	PFIL_ALL	call me on all of the above
65e9c7bebfSDarren Reed  *	PFIL_WAITOK	OK to call malloc with M_WAITOK.
66e9c7bebfSDarren Reed  */
67e9c7bebfSDarren Reed int
68e9c7bebfSDarren Reed pfil_add_hook(func, flags, ph)
69e9c7bebfSDarren Reed 	int	(*func) __P((void *, int, struct ifnet *, int,
70e9c7bebfSDarren Reed 			     struct mbuf **));
71e9c7bebfSDarren Reed 	int	flags;
72e9c7bebfSDarren Reed 	struct	pfil_head	*ph;
73e9c7bebfSDarren Reed {
74e9c7bebfSDarren Reed 	int err = 0;
75e9c7bebfSDarren Reed 
76e9c7bebfSDarren Reed 	if (ph->ph_init == 0)
77e9c7bebfSDarren Reed 		pfil_init(ph);
78e9c7bebfSDarren Reed 
79e9c7bebfSDarren Reed 	if (flags & PFIL_IN)
80e9c7bebfSDarren Reed 		err = pfil_list_add(&ph->ph_in, func, flags & ~PFIL_OUT);
81e9c7bebfSDarren Reed 	if (err)
82e9c7bebfSDarren Reed 		return err;
83e9c7bebfSDarren Reed 	if (flags & PFIL_OUT)
84e9c7bebfSDarren Reed 		err = pfil_list_add(&ph->ph_out, func, flags & ~PFIL_IN);
85e9c7bebfSDarren Reed 	if (err) {
86e9c7bebfSDarren Reed 		if (flags & PFIL_IN)
87e9c7bebfSDarren Reed 			pfil_list_remove(&ph->ph_in, func);
88e9c7bebfSDarren Reed 		return err;
89e9c7bebfSDarren Reed 	}
90e9c7bebfSDarren Reed 	return 0;
91e9c7bebfSDarren Reed }
92e9c7bebfSDarren Reed 
93e9c7bebfSDarren Reed static int
94e9c7bebfSDarren Reed pfil_list_add(list, func, flags)
95e9c7bebfSDarren Reed 	pfil_list_t *list;
96e9c7bebfSDarren Reed 	int	(*func) __P((void *, int, struct ifnet *, int,
97e9c7bebfSDarren Reed 			     struct mbuf **));
98e9c7bebfSDarren Reed 	int flags;
99e9c7bebfSDarren Reed {
100e9c7bebfSDarren Reed 	struct packet_filter_hook *pfh;
101e9c7bebfSDarren Reed 
102e9c7bebfSDarren Reed 	pfh = (struct packet_filter_hook *)malloc(sizeof(*pfh), M_IFADDR,
103e9c7bebfSDarren Reed 	    flags & PFIL_WAITOK ? M_WAITOK : M_NOWAIT);
104e9c7bebfSDarren Reed 	if (pfh == NULL)
105e9c7bebfSDarren Reed 		return ENOMEM;
106e9c7bebfSDarren Reed 	pfh->pfil_func = func;
107e9c7bebfSDarren Reed 	/*
108e9c7bebfSDarren Reed 	 * insert the input list in reverse order of the output list
109e9c7bebfSDarren Reed 	 * so that the same path is followed in or out of the kernel.
110e9c7bebfSDarren Reed 	 */
111e9c7bebfSDarren Reed 
112e9c7bebfSDarren Reed 	if (flags & PFIL_IN)
113e9c7bebfSDarren Reed 		TAILQ_INSERT_HEAD(list, pfh, pfil_link);
114e9c7bebfSDarren Reed 	else
115e9c7bebfSDarren Reed 		TAILQ_INSERT_TAIL(list, pfh, pfil_link);
116e9c7bebfSDarren Reed 	return 0;
117e9c7bebfSDarren Reed }
118e9c7bebfSDarren Reed 
119e9c7bebfSDarren Reed /*
120e9c7bebfSDarren Reed  * pfil_remove_hook removes a specific function from the packet filter
121e9c7bebfSDarren Reed  * hook list.
122e9c7bebfSDarren Reed  */
123e9c7bebfSDarren Reed int
124e9c7bebfSDarren Reed pfil_remove_hook(func, flags, ph)
125e9c7bebfSDarren Reed 	int	(*func) __P((void *, int, struct ifnet *, int,
126e9c7bebfSDarren Reed 			     struct mbuf **));
127e9c7bebfSDarren Reed 	int	flags;
128e9c7bebfSDarren Reed 	struct	pfil_head	*ph;
129e9c7bebfSDarren Reed {
130e9c7bebfSDarren Reed 	int err = 0;
131e9c7bebfSDarren Reed 
132e9c7bebfSDarren Reed 	if (ph->ph_init == 0)
133e9c7bebfSDarren Reed 		pfil_init(ph);
134e9c7bebfSDarren Reed 
135e9c7bebfSDarren Reed 	if (flags & PFIL_IN)
136e9c7bebfSDarren Reed 		err = pfil_list_remove(&ph->ph_in, func);
137e9c7bebfSDarren Reed 	if ((err == 0) && (flags & PFIL_OUT))
138e9c7bebfSDarren Reed 		err = pfil_list_remove(&ph->ph_out, func);
139e9c7bebfSDarren Reed 	return err;
140e9c7bebfSDarren Reed }
141e9c7bebfSDarren Reed 
142e9c7bebfSDarren Reed /*
143e9c7bebfSDarren Reed  * pfil_list_remove is an internal function that takes a function off the
144e9c7bebfSDarren Reed  * specified list.
145e9c7bebfSDarren Reed  */
146e9c7bebfSDarren Reed static int
147e9c7bebfSDarren Reed pfil_list_remove(list, func)
148e9c7bebfSDarren Reed 	pfil_list_t *list;
149e9c7bebfSDarren Reed 	int	(*func) __P((void *, int, struct ifnet *, int,
150e9c7bebfSDarren Reed 			     struct mbuf **));
151e9c7bebfSDarren Reed {
152e9c7bebfSDarren Reed 	struct packet_filter_hook *pfh;
153e9c7bebfSDarren Reed 
154e9c7bebfSDarren Reed 	for (pfh = list->tqh_first; pfh; pfh = pfh->pfil_link.tqe_next)
155e9c7bebfSDarren Reed 		if (pfh->pfil_func == func) {
156e9c7bebfSDarren Reed 			TAILQ_REMOVE(list, pfh, pfil_link);
157e9c7bebfSDarren Reed 			free(pfh, M_IFADDR);
158e9c7bebfSDarren Reed 			return 0;
159e9c7bebfSDarren Reed 		}
160e9c7bebfSDarren Reed 	return ENOENT;
161e9c7bebfSDarren Reed }
162e9c7bebfSDarren Reed 
163e9c7bebfSDarren Reed struct packet_filter_hook *
164e9c7bebfSDarren Reed pfil_hook_get(flag, ph)
165e9c7bebfSDarren Reed 	int flag;
166e9c7bebfSDarren Reed 	struct	pfil_head	*ph;
167e9c7bebfSDarren Reed {
168e9c7bebfSDarren Reed 	if (ph->ph_init != 0)
169e9c7bebfSDarren Reed 		switch (flag) {
170e9c7bebfSDarren Reed 		case PFIL_IN:
171e9c7bebfSDarren Reed 			return (ph->ph_in.tqh_first);
172e9c7bebfSDarren Reed 		case PFIL_OUT:
173e9c7bebfSDarren Reed 			return (ph->ph_out.tqh_first);
174e9c7bebfSDarren Reed 		}
175e9c7bebfSDarren Reed 	return NULL;
176e9c7bebfSDarren Reed }
177