struct net_device *out;
struct sock *sk;
struct net *net;
- struct nf_hook_entry __rcu *hook_entries;
int (*okfn)(struct net *, struct sock *, struct sk_buff *);
};
};
static inline void nf_hook_state_init(struct nf_hook_state *p,
- struct nf_hook_entry *hook_entry,
unsigned int hook,
u_int8_t pf,
struct net_device *indev,
p->out = outdev;
p->sk = sk;
p->net = net;
- RCU_INIT_POINTER(p->hook_entries, hook_entry);
p->okfn = okfn;
}
extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
#endif
-int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
+int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
+ struct nf_hook_entry *entry);
/**
* nf_hook - call a netfilter hook
if (hook_head) {
struct nf_hook_state state;
- nf_hook_state_init(&state, hook_head, hook, pf, indev, outdev,
+ nf_hook_state_init(&state, hook, pf, indev, outdev,
sk, net, okfn);
- ret = nf_hook_slow(skb, &state);
+ ret = nf_hook_slow(skb, &state, hook_head);
}
rcu_read_unlock();
if (unlikely(!e))
return 0;
- nf_hook_state_init(&state, e, NF_NETDEV_INGRESS,
+ nf_hook_state_init(&state, NF_NETDEV_INGRESS,
NFPROTO_NETDEV, skb->dev, NULL, NULL,
dev_net(skb->dev), NULL);
- return nf_hook_slow(skb, &state);
+ return nf_hook_slow(skb, &state, e);
}
static inline void nf_hook_ingress_init(struct net_device *dev)
unsigned int id;
struct nf_hook_state state;
+ struct nf_hook_entry *hook;
u16 size; /* sizeof(entry) + saved route keys */
/* extra space to store route keys */
/* We may already have this, but read-locks nest anyway */
rcu_read_lock();
- nf_hook_state_init(&state, elem, hook, NFPROTO_BRIDGE, indev, outdev,
+ nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
sk, net, okfn);
- ret = nf_hook_slow(skb, &state);
+ ret = nf_hook_slow(skb, &state, elem);
rcu_read_unlock();
if (ret == 1)
ret = okfn(net, sk, skb);
struct nf_hook_state state;
int ret;
- nf_hook_state_init(&state, NULL, NF_BR_BROUTING,
+ nf_hook_state_init(&state, NF_BR_BROUTING,
NFPROTO_BRIDGE, skb->dev, NULL, NULL,
dev_net(skb->dev), NULL);
{
unsigned int verdict;
- while (*entryp) {
+ do {
repeat:
verdict = (*entryp)->ops.hook((*entryp)->ops.priv, skb, state);
if (verdict != NF_ACCEPT) {
goto repeat;
}
*entryp = rcu_dereference((*entryp)->next);
- }
+ } while (*entryp);
return NF_ACCEPT;
}
/* Returns 1 if okfn() needs to be executed by the caller,
* -EPERM for NF_DROP, 0 otherwise. Caller must hold rcu_read_lock. */
-int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
+int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
+ struct nf_hook_entry *entry)
{
- struct nf_hook_entry *entry;
unsigned int verdict;
int ret;
- entry = rcu_dereference(state->hook_entries);
next_hook:
verdict = nf_iterate(skb, state, &entry);
switch (verdict & NF_VERDICT_MASK) {
}
static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
- unsigned int queuenum)
+ struct nf_hook_entry *hook_entry, unsigned int queuenum)
{
int status = -ENOENT;
struct nf_queue_entry *entry = NULL;
*entry = (struct nf_queue_entry) {
.skb = skb,
.state = *state,
+ .hook = hook_entry,
.size = sizeof(*entry) + afinfo->route_key_size,
};
struct nf_hook_entry *entry = *entryp;
int ret;
- RCU_INIT_POINTER(state->hook_entries, entry);
- ret = __nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
+ ret = __nf_queue(skb, state, entry, verdict >> NF_VERDICT_QBITS);
if (ret < 0) {
if (ret == -ESRCH &&
(verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) {
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
{
- struct nf_hook_entry *hook_entry;
+ struct nf_hook_entry *hook_entry = entry->hook;
+ struct nf_hook_ops *elem = &hook_entry->ops;
struct sk_buff *skb = entry->skb;
const struct nf_afinfo *afinfo;
- struct nf_hook_ops *elem;
int err;
- hook_entry = rcu_dereference(entry->state.hook_entries);
- elem = &hook_entry->ops;
-
nf_queue_entry_release_refs(entry);
/* Continue traversal iff userspace said ok... */
static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long entry_ptr)
{
- return rcu_access_pointer(entry->state.hook_entries) ==
+ return rcu_access_pointer(entry->hook) ==
(struct nf_hook_entry *)entry_ptr;
}