Changeset View
Changeset View
Standalone View
Standalone View
sys/net/pfil.c
Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
static struct packet_filter_hook * | static struct packet_filter_hook * | ||||
pfil_chain_get(int dir, struct pfil_head *ph) | pfil_chain_get(int dir, struct pfil_head *ph) | ||||
{ | { | ||||
if (dir == PFIL_IN) | if (dir == PFIL_IN) | ||||
return (TAILQ_FIRST(&ph->ph_in)); | return (TAILQ_FIRST(&ph->ph_in)); | ||||
else if (dir == PFIL_OUT) | else if (dir == PFIL_OUT) | ||||
return (TAILQ_FIRST(&ph->ph_out)); | return (TAILQ_FIRST(&ph->ph_out)); | ||||
else if (dir == PFIL_FWD) | |||||
return (TAILQ_FIRST(&ph->ph_fwd)); | |||||
else | else | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* pfil_try_rlock() acquires rm reader lock for specified head | * pfil_try_rlock() acquires rm reader lock for specified head | ||||
* if this is immediately possible. | * if this is immediately possible. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (ph->ph_type == lph->ph_type && | ||||
PFIL_HEADLIST_UNLOCK(); | PFIL_HEADLIST_UNLOCK(); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
} | } | ||||
PFIL_LOCK_INIT(ph); | PFIL_LOCK_INIT(ph); | ||||
ph->ph_nhooks = 0; | ph->ph_nhooks = 0; | ||||
TAILQ_INIT(&ph->ph_in); | TAILQ_INIT(&ph->ph_in); | ||||
TAILQ_INIT(&ph->ph_out); | TAILQ_INIT(&ph->ph_out); | ||||
TAILQ_INIT(&ph->ph_fwd); | |||||
LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); | LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); | ||||
PFIL_HEADLIST_UNLOCK(); | PFIL_HEADLIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* pfil_head_unregister() removes a pfil_head from the packet filter hook | * pfil_head_unregister() removes a pfil_head from the packet filter hook | ||||
* mechanism. The producer of the hook promises that all outstanding | * mechanism. The producer of the hook promises that all outstanding | ||||
* invocations of the hook have completed before it unregisters the hook. | * invocations of the hook have completed before it unregisters the hook. | ||||
*/ | */ | ||||
int | int | ||||
pfil_head_unregister(struct pfil_head *ph) | pfil_head_unregister(struct pfil_head *ph) | ||||
{ | { | ||||
struct packet_filter_hook *pfh, *pfnext; | struct packet_filter_hook *pfh, *pfnext; | ||||
PFIL_HEADLIST_LOCK(); | PFIL_HEADLIST_LOCK(); | ||||
LIST_REMOVE(ph, ph_list); | LIST_REMOVE(ph, ph_list); | ||||
PFIL_HEADLIST_UNLOCK(); | PFIL_HEADLIST_UNLOCK(); | ||||
TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext) | TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext) | ||||
free(pfh, M_IFADDR); | free(pfh, M_IFADDR); | ||||
TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext) | TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext) | ||||
free(pfh, M_IFADDR); | free(pfh, M_IFADDR); | ||||
TAILQ_FOREACH_SAFE(pfh, &ph->ph_fwd, pfil_chain, pfnext) | |||||
free(pfh, M_IFADDR); | |||||
PFIL_LOCK_DESTROY(ph); | PFIL_LOCK_DESTROY(ph); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* pfil_head_get() returns the pfil_head for a given key/dlt. | * pfil_head_get() returns the pfil_head for a given key/dlt. | ||||
*/ | */ | ||||
struct pfil_head * | struct pfil_head * | ||||
Show All 9 Lines | pfil_head_get(int type, u_long val) | ||||
return (ph); | return (ph); | ||||
} | } | ||||
/* | /* | ||||
* pfil_add_hook() adds a function to the packet filter hook. the | * pfil_add_hook() adds a function to the packet filter hook. the | ||||
* flags are: | * flags are: | ||||
* PFIL_IN call me on incoming packets | * PFIL_IN call me on incoming packets | ||||
* PFIL_OUT call me on outgoing packets | * PFIL_OUT call me on outgoing packets | ||||
* PFIL_FWD call me in the forwarding path | |||||
* PFIL_ALL call me on all of the above | * PFIL_ALL call me on all of the above | ||||
* PFIL_WAITOK OK to call malloc with M_WAITOK. | * PFIL_WAITOK OK to call malloc with M_WAITOK. | ||||
*/ | */ | ||||
int | int | ||||
pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) | pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) | ||||
{ | { | ||||
struct packet_filter_hook *pfh1 = NULL; | struct packet_filter_hook *pfh1 = NULL; | ||||
struct packet_filter_hook *pfh2 = NULL; | struct packet_filter_hook *pfh2 = NULL; | ||||
struct packet_filter_hook *pfh3 = NULL; | |||||
int err; | int err; | ||||
if (flags & PFIL_IN) { | if (flags & PFIL_IN) { | ||||
pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), | pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), | ||||
M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); | M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); | ||||
if (pfh1 == NULL) { | if (pfh1 == NULL) { | ||||
err = ENOMEM; | err = ENOMEM; | ||||
goto error; | goto error; | ||||
} | } | ||||
} | } | ||||
if (flags & PFIL_OUT) { | if (flags & PFIL_OUT) { | ||||
pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), | pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), | ||||
M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); | M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); | ||||
if (pfh2 == NULL) { | if (pfh2 == NULL) { | ||||
err = ENOMEM; | err = ENOMEM; | ||||
goto error; | goto error; | ||||
} | } | ||||
} | } | ||||
if (flags & PFIL_FWD) { | |||||
pfh3 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), | |||||
M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); | |||||
if (pfh3 == NULL) { | |||||
err = ENOMEM; | |||||
goto error; | |||||
} | |||||
} | |||||
PFIL_WLOCK(ph); | PFIL_WLOCK(ph); | ||||
if (flags & PFIL_IN) { | if (flags & PFIL_IN) { | ||||
pfh1->pfil_func = func; | pfh1->pfil_func = func; | ||||
pfh1->pfil_arg = arg; | pfh1->pfil_arg = arg; | ||||
err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); | err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~(PFIL_OUT | PFIL_FWD)); | ||||
if (err) | if (err) | ||||
goto locked_error; | goto locked_error; | ||||
ph->ph_nhooks++; | ph->ph_nhooks++; | ||||
} | } | ||||
if (flags & PFIL_OUT) { | if (flags & PFIL_OUT) { | ||||
pfh2->pfil_func = func; | pfh2->pfil_func = func; | ||||
pfh2->pfil_arg = arg; | pfh2->pfil_arg = arg; | ||||
err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN); | err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~(PFIL_IN | PFIL_FWD)); | ||||
if (err) { | if (err) { | ||||
if (flags & PFIL_IN) | if (flags & PFIL_IN) | ||||
pfil_chain_remove(&ph->ph_in, func, arg); | pfil_chain_remove(&ph->ph_in, func, arg); | ||||
goto locked_error; | goto locked_error; | ||||
} | } | ||||
ph->ph_nhooks++; | ph->ph_nhooks++; | ||||
} | } | ||||
if (flags & PFIL_FWD) { | |||||
pfh3->pfil_func = func; | |||||
pfh3->pfil_arg = arg; | |||||
err = pfil_chain_add(&ph->ph_fwd, pfh3, flags & ~(PFIL_IN | PFIL_OUT)); | |||||
if (err) { | |||||
if (flags & PFIL_IN) | |||||
pfil_chain_remove(&ph->ph_in, func, arg); | |||||
if (flags & PFIL_OUT) | |||||
pfil_chain_remove(&ph->ph_out, func, arg); | |||||
goto locked_error; | |||||
} | |||||
ph->ph_nhooks++; | |||||
} | |||||
PFIL_WUNLOCK(ph); | PFIL_WUNLOCK(ph); | ||||
return (0); | return (0); | ||||
locked_error: | locked_error: | ||||
PFIL_WUNLOCK(ph); | PFIL_WUNLOCK(ph); | ||||
error: | error: | ||||
if (pfh1 != NULL) | if (pfh1 != NULL) | ||||
free(pfh1, M_IFADDR); | free(pfh1, M_IFADDR); | ||||
if (pfh2 != NULL) | if (pfh2 != NULL) | ||||
free(pfh2, M_IFADDR); | free(pfh2, M_IFADDR); | ||||
if (pfh3 != NULL) | |||||
free(pfh3, M_IFADDR); | |||||
return (err); | return (err); | ||||
} | } | ||||
/* | /* | ||||
* pfil_remove_hook removes a specific function from the packet filter hook | * pfil_remove_hook removes a specific function from the packet filter hook | ||||
* chain. | * chain. | ||||
*/ | */ | ||||
int | int | ||||
pfil_remove_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) | pfil_remove_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) | ||||
{ | { | ||||
int err = 0; | int err = 0; | ||||
PFIL_WLOCK(ph); | PFIL_WLOCK(ph); | ||||
if (flags & PFIL_IN) { | if (flags & PFIL_IN) { | ||||
err = pfil_chain_remove(&ph->ph_in, func, arg); | err = pfil_chain_remove(&ph->ph_in, func, arg); | ||||
if (err == 0) | if (err == 0) | ||||
ph->ph_nhooks--; | ph->ph_nhooks--; | ||||
} | } | ||||
if ((err == 0) && (flags & PFIL_OUT)) { | if ((err == 0) && (flags & PFIL_OUT)) { | ||||
err = pfil_chain_remove(&ph->ph_out, func, arg); | err = pfil_chain_remove(&ph->ph_out, func, arg); | ||||
if (err == 0) | |||||
ph->ph_nhooks--; | |||||
} | |||||
if ((err == 0) && (flags & PFIL_FWD)) { | |||||
err = pfil_chain_remove(&ph->ph_fwd, func, arg); | |||||
if (err == 0) | if (err == 0) | ||||
ph->ph_nhooks--; | ph->ph_nhooks--; | ||||
} | } | ||||
PFIL_WUNLOCK(ph); | PFIL_WUNLOCK(ph); | ||||
return (err); | return (err); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 84 Lines • Show Last 20 Lines |