Commit cfdfab31 authored by David S. Miller's avatar David S. Miller

netfilter: Create and use nf_hook_state.

Instead of passing a large number of arguments down into the nf_hook()
entry points, create a structure which carries this state down through
the hook processing layers.

This makes is so that if we want to change the types or signatures of
any of these pieces of state, there are less places that need to be
changed.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b81b7be6
...@@ -44,6 +44,16 @@ int netfilter_init(void); ...@@ -44,6 +44,16 @@ int netfilter_init(void);
struct sk_buff; struct sk_buff;
struct nf_hook_ops; struct nf_hook_ops;
struct nf_hook_state {
unsigned int hook;
int thresh;
u_int8_t pf;
struct net_device *in;
struct net_device *out;
int (*okfn)(struct sk_buff *);
};
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
struct sk_buff *skb, struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
...@@ -118,9 +128,7 @@ static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) ...@@ -118,9 +128,7 @@ static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
} }
#endif #endif
int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh);
/** /**
* nf_hook_thresh - call a netfilter hook * nf_hook_thresh - call a netfilter hook
...@@ -135,8 +143,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, ...@@ -135,8 +143,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
struct net_device *outdev, struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh) int (*okfn)(struct sk_buff *), int thresh)
{ {
if (nf_hooks_active(pf, hook)) if (nf_hooks_active(pf, hook)) {
return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh); struct nf_hook_state state = {
.hook = hook,
.thresh = thresh,
.pf = pf,
.in = indev,
.out = outdev,
.okfn = okfn
};
return nf_hook_slow(skb, &state);
}
return 1; return 1;
} }
......
...@@ -120,12 +120,8 @@ EXPORT_SYMBOL(nf_unregister_hooks); ...@@ -120,12 +120,8 @@ EXPORT_SYMBOL(nf_unregister_hooks);
unsigned int nf_iterate(struct list_head *head, unsigned int nf_iterate(struct list_head *head,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int hook, struct nf_hook_state *state,
const struct net_device *indev, struct nf_hook_ops **elemp)
const struct net_device *outdev,
struct nf_hook_ops **elemp,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{ {
unsigned int verdict; unsigned int verdict;
...@@ -134,19 +130,20 @@ unsigned int nf_iterate(struct list_head *head, ...@@ -134,19 +130,20 @@ unsigned int nf_iterate(struct list_head *head,
* function because of risk of continuing from deleted element. * function because of risk of continuing from deleted element.
*/ */
list_for_each_entry_continue_rcu((*elemp), head, list) { list_for_each_entry_continue_rcu((*elemp), head, list) {
if (hook_thresh > (*elemp)->priority) if (state->thresh > (*elemp)->priority)
continue; continue;
/* Optimization: we don't need to hold module /* Optimization: we don't need to hold module
reference here, since function can't sleep. --RR */ reference here, since function can't sleep. --RR */
repeat: repeat:
verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn); verdict = (*elemp)->hook(*elemp, skb, state->in, state->out,
state->okfn);
if (verdict != NF_ACCEPT) { if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
if (unlikely((verdict & NF_VERDICT_MASK) if (unlikely((verdict & NF_VERDICT_MASK)
> NF_MAX_VERDICT)) { > NF_MAX_VERDICT)) {
NFDEBUG("Evil return from %p(%u).\n", NFDEBUG("Evil return from %p(%u).\n",
(*elemp)->hook, hook); (*elemp)->hook, state->hook);
continue; continue;
} }
#endif #endif
...@@ -161,11 +158,7 @@ unsigned int nf_iterate(struct list_head *head, ...@@ -161,11 +158,7 @@ unsigned int nf_iterate(struct list_head *head,
/* Returns 1 if okfn() needs to be executed by the caller, /* Returns 1 if okfn() needs to be executed by the caller,
* -EPERM for NF_DROP, 0 otherwise. */ * -EPERM for NF_DROP, 0 otherwise. */
int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{ {
struct nf_hook_ops *elem; struct nf_hook_ops *elem;
unsigned int verdict; unsigned int verdict;
...@@ -174,10 +167,11 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, ...@@ -174,10 +167,11 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
/* We may already have this, but read-locks nest anyway */ /* We may already have this, but read-locks nest anyway */
rcu_read_lock(); rcu_read_lock();
elem = list_entry_rcu(&nf_hooks[pf][hook], struct nf_hook_ops, list); elem = list_entry_rcu(&nf_hooks[state->pf][state->hook],
struct nf_hook_ops, list);
next_hook: next_hook:
verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, verdict = nf_iterate(&nf_hooks[state->pf][state->hook], skb, state,
outdev, &elem, okfn, hook_thresh); &elem);
if (verdict == NF_ACCEPT || verdict == NF_STOP) { if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret = 1; ret = 1;
} else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) {
...@@ -186,7 +180,7 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, ...@@ -186,7 +180,7 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
if (ret == 0) if (ret == 0)
ret = -EPERM; ret = -EPERM;
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, int err = nf_queue(skb, elem, state,
verdict >> NF_VERDICT_QBITS); verdict >> NF_VERDICT_QBITS);
if (err < 0) { if (err < 0) {
if (err == -ECANCELED) if (err == -ECANCELED)
......
...@@ -14,16 +14,11 @@ ...@@ -14,16 +14,11 @@
/* core.c */ /* core.c */
unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb,
unsigned int hook, const struct net_device *indev, struct nf_hook_state *state, struct nf_hook_ops **elemp);
const struct net_device *outdev,
struct nf_hook_ops **elemp,
int (*okfn)(struct sk_buff *), int hook_thresh);
/* nf_queue.c */ /* nf_queue.c */
int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, u_int8_t pf, int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem,
unsigned int hook, struct net_device *indev, struct nf_hook_state *state, unsigned int queuenum);
struct net_device *outdev, int (*okfn)(struct sk_buff *),
unsigned int queuenum);
int __init netfilter_queue_init(void); int __init netfilter_queue_init(void);
/* nf_log.c */ /* nf_log.c */
......
...@@ -101,10 +101,7 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs); ...@@ -101,10 +101,7 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
*/ */
int nf_queue(struct sk_buff *skb, int nf_queue(struct sk_buff *skb,
struct nf_hook_ops *elem, struct nf_hook_ops *elem,
u_int8_t pf, unsigned int hook, struct nf_hook_state *state,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
unsigned int queuenum) unsigned int queuenum)
{ {
int status = -ENOENT; int status = -ENOENT;
...@@ -121,7 +118,7 @@ int nf_queue(struct sk_buff *skb, ...@@ -121,7 +118,7 @@ int nf_queue(struct sk_buff *skb,
goto err_unlock; goto err_unlock;
} }
afinfo = nf_get_afinfo(pf); afinfo = nf_get_afinfo(state->pf);
if (!afinfo) if (!afinfo)
goto err_unlock; goto err_unlock;
...@@ -134,11 +131,11 @@ int nf_queue(struct sk_buff *skb, ...@@ -134,11 +131,11 @@ int nf_queue(struct sk_buff *skb,
*entry = (struct nf_queue_entry) { *entry = (struct nf_queue_entry) {
.skb = skb, .skb = skb,
.elem = elem, .elem = elem,
.pf = pf, .pf = state->pf,
.hook = hook, .hook = state->hook,
.indev = indev, .indev = state->in,
.outdev = outdev, .outdev = state->out,
.okfn = okfn, .okfn = state->okfn,
.size = sizeof(*entry) + afinfo->route_key_size, .size = sizeof(*entry) + afinfo->route_key_size,
}; };
...@@ -171,6 +168,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) ...@@ -171,6 +168,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
struct sk_buff *skb = entry->skb; struct sk_buff *skb = entry->skb;
struct nf_hook_ops *elem = entry->elem; struct nf_hook_ops *elem = entry->elem;
const struct nf_afinfo *afinfo; const struct nf_afinfo *afinfo;
struct nf_hook_state state;
int err; int err;
rcu_read_lock(); rcu_read_lock();
...@@ -189,12 +187,17 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) ...@@ -189,12 +187,17 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
verdict = NF_DROP; verdict = NF_DROP;
} }
state.hook = entry->hook;
state.thresh = INT_MIN;
state.pf = entry->pf;
state.in = entry->indev;
state.out = entry->outdev;
state.okfn = entry->okfn;
if (verdict == NF_ACCEPT) { if (verdict == NF_ACCEPT) {
next_hook: next_hook:
verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook],
skb, entry->hook, skb, &state, &elem);
entry->indev, entry->outdev, &elem,
entry->okfn, INT_MIN);
} }
switch (verdict & NF_VERDICT_MASK) { switch (verdict & NF_VERDICT_MASK) {
...@@ -205,8 +208,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) ...@@ -205,8 +208,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
local_bh_enable(); local_bh_enable();
break; break;
case NF_QUEUE: case NF_QUEUE:
err = nf_queue(skb, elem, entry->pf, entry->hook, err = nf_queue(skb, elem, &state,
entry->indev, entry->outdev, entry->okfn,
verdict >> NF_VERDICT_QBITS); verdict >> NF_VERDICT_QBITS);
if (err < 0) { if (err < 0) {
if (err == -ECANCELED) if (err == -ECANCELED)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment