pfil.c revision 254774
1178825Sdfr/*	$FreeBSD: head/sys/net/pfil.c 254774 2013-08-24 11:24:15Z andre $ */
2102644Snectar/*	$NetBSD: pfil.c,v 1.20 2001/11/12 23:49:46 lukem Exp $	*/
355682Smarkm
4142403Snectar/*-
5178825Sdfr * Copyright (c) 1996 Matthew R. Green
655682Smarkm * All rights reserved.
755682Smarkm *
855682Smarkm * Redistribution and use in source and binary forms, with or without
955682Smarkm * modification, are permitted provided that the following conditions
1055682Smarkm * are met:
1155682Smarkm * 1. Redistributions of source code must retain the above copyright
1255682Smarkm *    notice, this list of conditions and the following disclaimer.
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1590926Snectar *    documentation and/or other materials provided with the distribution.
1690926Snectar * 3. The name of the author may not be used to endorse or promote products
17178825Sdfr *    derived from this software without specific prior written permission.
1890926Snectar *
19178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2090926Snectar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21178825Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2255682Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2355682Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2455682Smarkm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2555682Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2655682Smarkm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27102644Snectar * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28102644Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29102644Snectar * SUCH DAMAGE.
30127808Snectar */
3190926Snectar
32127808Snectar#include <sys/param.h>
3355682Smarkm#include <sys/kernel.h>
3455682Smarkm#include <sys/errno.h>
3555682Smarkm#include <sys/lock.h>
3655682Smarkm#include <sys/malloc.h>
3755682Smarkm#include <sys/rmlock.h>
3855682Smarkm#include <sys/socket.h>
39178825Sdfr#include <sys/socketvar.h>
4055682Smarkm#include <sys/systm.h>
41142403Snectar#include <sys/condvar.h>
42142403Snectar#include <sys/lock.h>
43142403Snectar#include <sys/mutex.h>
44142403Snectar#include <sys/proc.h>
45142403Snectar#include <sys/queue.h>
46142403Snectar
47178825Sdfr#include <net/if.h>
48178825Sdfr#include <net/pfil.h>
49142403Snectar
50142403Snectarstatic struct mtx pfil_global_lock;
51142403Snectar
52178825SdfrMTX_SYSINIT(pfil_heads_lock, &pfil_global_lock, "pfil_head_list lock",
53142403Snectar  MTX_DEF);
54142403Snectar
55142403Snectarstatic struct packet_filter_hook *pfil_chain_get(int, struct pfil_head *);
56142403Snectarstatic int pfil_chain_add(pfil_chain_t *, struct packet_filter_hook *, int);
57142403Snectarstatic int pfil_chain_remove(pfil_chain_t *, pfil_func_t, void *);
58142403Snectar
59142403SnectarLIST_HEAD(pfilheadhead, pfil_head);
60142403SnectarVNET_DEFINE(struct pfilheadhead, pfil_head_list);
61142403Snectar#define	V_pfil_head_list	VNET(pfil_head_list)
62142403SnectarVNET_DEFINE(struct rmlock, pfil_lock);
63142403Snectar#define	V_pfil_lock	VNET(pfil_lock)
64142403Snectar
65142403Snectar/*
66142403Snectar * pfil_run_hooks() runs the specified packet filter hook chain.
67142403Snectar */
68142403Snectarint
69142403Snectarpfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
70142403Snectar    int dir, struct inpcb *inp)
71142403Snectar{
72178825Sdfr	struct rm_priotracker rmpt;
73142403Snectar	struct packet_filter_hook *pfh;
74142403Snectar	struct mbuf *m = *mp;
75142403Snectar	int rv = 0;
76142403Snectar
77142403Snectar	PFIL_RLOCK(ph, &rmpt);
78142403Snectar	KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0"));
79142403Snectar	for (pfh = pfil_chain_get(dir, ph); pfh != NULL;
80142403Snectar	     pfh = TAILQ_NEXT(pfh, pfil_chain)) {
81178825Sdfr		if (pfh->pfil_func != NULL) {
82178825Sdfr			rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir,
83178825Sdfr			    inp);
84178825Sdfr			if (rv != 0 || m == NULL)
85178825Sdfr				break;
86178825Sdfr		}
87178825Sdfr	}
88178825Sdfr	PFIL_RUNLOCK(ph, &rmpt);
89178825Sdfr	*mp = m;
90178825Sdfr	return (rv);
91178825Sdfr}
92142403Snectar
93142403Snectarstatic struct packet_filter_hook *
94178825Sdfrpfil_chain_get(int dir, struct pfil_head *ph)
95142403Snectar{
96142403Snectar
97178825Sdfr	if (dir == PFIL_IN)
98178825Sdfr		return (TAILQ_FIRST(&ph->ph_in));
99178825Sdfr	else if (dir == PFIL_OUT)
100142403Snectar		return (TAILQ_FIRST(&ph->ph_out));
101142403Snectar	else
102142403Snectar		return (NULL);
103142403Snectar}
104142403Snectar
105142403Snectar/*
106142403Snectar * pfil_try_rlock() acquires rm reader lock for specified head
107142403Snectar * if this is immediately possible.
108142403Snectar */
109142403Snectarint
110142403Snectarpfil_try_rlock(struct pfil_head *ph, struct rm_priotracker *tracker)
111142403Snectar{
112142403Snectar
113142403Snectar	return (PFIL_TRY_RLOCK(ph, tracker));
114178825Sdfr}
115178825Sdfr
116142403Snectar/*
117142403Snectar * pfil_rlock() acquires rm reader lock for specified head.
118178825Sdfr */
119178825Sdfrvoid
120178825Sdfrpfil_rlock(struct pfil_head *ph, struct rm_priotracker *tracker)
121178825Sdfr{
122142403Snectar
123142403Snectar	PFIL_RLOCK(ph, tracker);
124142403Snectar}
125142403Snectar
126142403Snectar/*
127178825Sdfr * pfil_runlock() releases reader lock for specified head.
128142403Snectar */
129178825Sdfrvoid
130178825Sdfrpfil_runlock(struct pfil_head *ph, struct rm_priotracker *tracker)
131178825Sdfr{
132178825Sdfr
133178825Sdfr	PFIL_RUNLOCK(ph, tracker);
134178825Sdfr}
135178825Sdfr
136178825Sdfr/*
137178825Sdfr * pfil_wlock() acquires writer lock for specified head.
138178825Sdfr */
139178825Sdfrvoid
140142403Snectarpfil_wlock(struct pfil_head *ph)
141142403Snectar{
142142403Snectar
143142403Snectar	PFIL_WLOCK(ph);
144178825Sdfr}
145178825Sdfr
146178825Sdfr/*
147142403Snectar * pfil_wunlock() releases writer lock for specified head.
148178825Sdfr */
149178825Sdfrvoid
150178825Sdfrpfil_wunlock(struct pfil_head *ph)
151178825Sdfr{
152178825Sdfr
153178825Sdfr	PFIL_WUNLOCK(ph);
154178825Sdfr}
155178825Sdfr
156142403Snectar/*
157142403Snectar * pfil_wowned() returns a non-zero value if the current thread owns
158142403Snectar * an exclusive lock.
159142403Snectar */
160142403Snectarint
161127808Snectarpfil_wowned(struct pfil_head *ph)
16255682Smarkm{
16372445Sassar
164127808Snectar	return (PFIL_WOWNED(ph));
165127808Snectar}
166127808Snectar
167127808Snectar/*
16855682Smarkm * pfil_head_register() registers a pfil_head with the packet filter hook
16955682Smarkm * mechanism.
17055682Smarkm */
17155682Smarkmint
17255682Smarkmpfil_head_register(struct pfil_head *ph)
173127808Snectar{
17490926Snectar	struct pfil_head *lph;
17572445Sassar
176127808Snectar	PFIL_HEADLIST_LOCK();
177127808Snectar	LIST_FOREACH(lph, &V_pfil_head_list, ph_list) {
178127808Snectar		if (ph->ph_type == lph->ph_type &&
179127808Snectar		    ph->ph_un.phu_val == lph->ph_un.phu_val) {
180127808Snectar			PFIL_HEADLIST_UNLOCK();
18155682Smarkm			return (EEXIST);
182127808Snectar		}
18390926Snectar	}
184178825Sdfr	PFIL_LOCK_INIT(ph);
185178825Sdfr	ph->ph_nhooks = 0;
18672445Sassar	TAILQ_INIT(&ph->ph_in);
187102644Snectar	TAILQ_INIT(&ph->ph_out);
188127808Snectar	LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list);
189127808Snectar	PFIL_HEADLIST_UNLOCK();
190127808Snectar	return (0);
191127808Snectar}
192127808Snectar
193127808Snectar/*
194127808Snectar * pfil_head_unregister() removes a pfil_head from the packet filter hook
195178825Sdfr * mechanism.  The producer of the hook promises that all outstanding
19655682Smarkm * invocations of the hook have completed before it unregisters the hook.
19772445Sassar */
198178825Sdfrint
199127808Snectarpfil_head_unregister(struct pfil_head *ph)
200127808Snectar{
201127808Snectar	struct packet_filter_hook *pfh, *pfnext;
202127808Snectar
203178825Sdfr	PFIL_HEADLIST_LOCK();
204127808Snectar	LIST_REMOVE(ph, ph_list);
205127808Snectar	PFIL_HEADLIST_UNLOCK();
206127808Snectar	TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext)
20790926Snectar		free(pfh, M_IFADDR);
208127808Snectar	TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext)
209178825Sdfr		free(pfh, M_IFADDR);
21055682Smarkm	PFIL_LOCK_DESTROY(ph);
211102644Snectar	return (0);
212102644Snectar}
213178825Sdfr
214127808Snectar/*
215127808Snectar * pfil_head_get() returns the pfil_head for a given key/dlt.
21655682Smarkm */
21755682Smarkmstruct pfil_head *
21890926Snectarpfil_head_get(int type, u_long val)
219127808Snectar{
220127808Snectar	struct pfil_head *ph;
221127808Snectar
222127808Snectar	PFIL_HEADLIST_LOCK();
223127808Snectar	LIST_FOREACH(ph, &V_pfil_head_list, ph_list)
22490926Snectar		if (ph->ph_type == type && ph->ph_un.phu_val == val)
22590926Snectar			break;
22690926Snectar	PFIL_HEADLIST_UNLOCK();
227127808Snectar	return (ph);
228127808Snectar}
229127808Snectar
230127808Snectar/*
231127808Snectar * pfil_add_hook() adds a function to the packet filter hook.  the
232127808Snectar * flags are:
233178825Sdfr *	PFIL_IN		call me on incoming packets
234127808Snectar *	PFIL_OUT	call me on outgoing packets
235127808Snectar *	PFIL_ALL	call me on all of the above
236127808Snectar *	PFIL_WAITOK	OK to call malloc with M_WAITOK.
237127808Snectar */
238127808Snectarint
239127808Snectarpfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph)
240127808Snectar{
241127808Snectar	struct packet_filter_hook *pfh1 = NULL;
242127808Snectar	struct packet_filter_hook *pfh2 = NULL;
243178825Sdfr	int err;
244178825Sdfr
245178825Sdfr	if (flags & PFIL_IN) {
246178825Sdfr		pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
247127808Snectar		    M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
248127808Snectar		if (pfh1 == NULL) {
24955682Smarkm			err = ENOMEM;
250127808Snectar			goto error;
251127808Snectar		}
252127808Snectar	}
253127808Snectar	if (flags & PFIL_OUT) {
254127808Snectar		pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
255127808Snectar		    M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
25655682Smarkm		if (pfh2 == NULL) {
257127808Snectar			err = ENOMEM;
258127808Snectar			goto error;
259178825Sdfr		}
260127808Snectar	}
261127808Snectar	PFIL_WLOCK(ph);
26255682Smarkm	if (flags & PFIL_IN) {
26355682Smarkm		pfh1->pfil_func = func;
264127808Snectar		pfh1->pfil_arg = arg;
265127808Snectar		err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT);
266127808Snectar		if (err)
267127808Snectar			goto locked_error;
26855682Smarkm		ph->ph_nhooks++;
26955682Smarkm	}
270120945Snectar	if (flags & PFIL_OUT) {
271127808Snectar		pfh2->pfil_func = func;
272178825Sdfr		pfh2->pfil_arg = arg;
27355682Smarkm		err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN);
274127808Snectar		if (err) {
27555682Smarkm			if (flags & PFIL_IN)
276127808Snectar				pfil_chain_remove(&ph->ph_in, func, arg);
277127808Snectar			goto locked_error;
278127808Snectar		}
279127808Snectar		ph->ph_nhooks++;
280127808Snectar	}
281127808Snectar	PFIL_WUNLOCK(ph);
282178825Sdfr	return (0);
283178825Sdfrlocked_error:
28455682Smarkm	PFIL_WUNLOCK(ph);
285127808Snectarerror:
286127808Snectar	if (pfh1 != NULL)
287102644Snectar		free(pfh1, M_IFADDR);
28855682Smarkm	if (pfh2 != NULL)
289178825Sdfr		free(pfh2, M_IFADDR);
29055682Smarkm	return (err);
29155682Smarkm}
29255682Smarkm
29355682Smarkm/*
294178825Sdfr * pfil_remove_hook removes a specific function from the packet filter hook
29590926Snectar * chain.
29690926Snectar */
29790926Snectarint
29890926Snectarpfil_remove_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph)
29955682Smarkm{
300178825Sdfr	int err = 0;
301178825Sdfr
302178825Sdfr	PFIL_WLOCK(ph);
303178825Sdfr	if (flags & PFIL_IN) {
304178825Sdfr		err = pfil_chain_remove(&ph->ph_in, func, arg);
305127808Snectar		if (err == 0)
306127808Snectar			ph->ph_nhooks--;
307127808Snectar	}
308127808Snectar	if ((err == 0) && (flags & PFIL_OUT)) {
309178825Sdfr		err = pfil_chain_remove(&ph->ph_out, func, arg);
310178825Sdfr		if (err == 0)
311127808Snectar			ph->ph_nhooks--;
312127808Snectar	}
313127808Snectar	PFIL_WUNLOCK(ph);
314127808Snectar	return (err);
315127808Snectar}
316127808Snectar
317178825Sdfr/*
318127808Snectar * Internal: Add a new pfil hook into a hook chain.
319178825Sdfr */
320178825Sdfrstatic int
321102644Snectarpfil_chain_add(pfil_chain_t *chain, struct packet_filter_hook *pfh1, int flags)
322102644Snectar{
323102644Snectar	struct packet_filter_hook *pfh;
324178825Sdfr
325127808Snectar	/*
326127808Snectar	 * First make sure the hook is not already there.
327127808Snectar	 */
328127808Snectar	TAILQ_FOREACH(pfh, chain, pfil_chain)
329127808Snectar		if (pfh->pfil_func == pfh1->pfil_func &&
330127808Snectar		    pfh->pfil_arg == pfh1->pfil_arg)
331178825Sdfr			return (EEXIST);
332127808Snectar
333127808Snectar	/*
33472445Sassar	 * Insert the input list in reverse order of the output list so that
335127808Snectar	 * the same path is followed in or out of the kernel.
336127808Snectar	 */
337178825Sdfr	if (flags & PFIL_IN)
338127808Snectar		TAILQ_INSERT_HEAD(chain, pfh1, pfil_chain);
339127808Snectar	else
340142403Snectar		TAILQ_INSERT_TAIL(chain, pfh1, pfil_chain);
341127808Snectar	return (0);
342178825Sdfr}
343127808Snectar
344127808Snectar/*
345178825Sdfr * Internal: Remove a pfil hook from a hook chain.
346127808Snectar */
347127808Snectarstatic int
348178825Sdfrpfil_chain_remove(pfil_chain_t *chain, pfil_func_t func, void *arg)
349127808Snectar{
350127808Snectar	struct packet_filter_hook *pfh;
351178825Sdfr
352178825Sdfr	TAILQ_FOREACH(pfh, chain, pfil_chain)
353178825Sdfr		if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
354178825Sdfr			TAILQ_REMOVE(chain, pfh, pfil_chain);
355178825Sdfr			free(pfh, M_IFADDR);
356102644Snectar			return (0);
35790926Snectar		}
35872445Sassar	return (ENOENT);
35955682Smarkm}
36055682Smarkm
36155682Smarkm/*
36255682Smarkm * Stuff that must be initialized for every instance (including the first of
36355682Smarkm * course).
36455682Smarkm */
36555682Smarkmstatic int
36655682Smarkmvnet_pfil_init(const void *unused)
367120945Snectar{
36890926Snectar
36972445Sassar	LIST_INIT(&V_pfil_head_list);
37055682Smarkm	PFIL_LOCK_INIT_REAL(&V_pfil_lock, "shared");
37190926Snectar	return (0);
372178825Sdfr}
37390926Snectar
374178825Sdfr/*
37572445Sassar * Called for the removal of each instance.
376178825Sdfr */
37772445Sassarstatic int
378178825Sdfrvnet_pfil_uninit(const void *unused)
379178825Sdfr{
38072445Sassar
38172445Sassar	KASSERT(LIST_EMPTY(&V_pfil_head_list),
38272445Sassar	    ("%s: pfil_head_list %p not empty", __func__, &V_pfil_head_list));
38372445Sassar	PFIL_LOCK_DESTROY_REAL(&V_pfil_lock);
38472445Sassar	return (0);
38572445Sassar}
38672445Sassar
38772445Sassar/* Define startup order. */
38872445Sassar#define	PFIL_SYSINIT_ORDER	SI_SUB_PROTO_BEGIN
38972445Sassar#define	PFIL_MODEVENT_ORDER	(SI_ORDER_FIRST) /* On boot slot in here. */
39072445Sassar#define	PFIL_VNET_ORDER		(PFIL_MODEVENT_ORDER + 2) /* Later still. */
391178825Sdfr
39272445Sassar/*
393178825Sdfr * Starting up.
39472445Sassar *
39572445Sassar * VNET_SYSINIT is called for each existing vnet and each new vnet.
39655682Smarkm */
397178825SdfrVNET_SYSINIT(vnet_pfil_init, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER,
398178825Sdfr    vnet_pfil_init, NULL);
399178825Sdfr
400178825Sdfr/*
401178825Sdfr * Closing up shop.  These are done in REVERSE ORDER.  Not called on reboot.
40272445Sassar *
40372445Sassar * VNET_SYSUNINIT is called for each exiting vnet as it exits.
40472445Sassar */
40572445SassarVNET_SYSUNINIT(vnet_pfil_uninit, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER,
40672445Sassar    vnet_pfil_uninit, NULL);
40772445Sassar