* NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */
if (!skb->dev) {
printk("ip_local_deliver: skb->dev is NULL.\n");
- }
- else if (strcmp(skb->dev->name, "lo") == 0) {
- if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
- | (1 << NF_IP_POST_ROUTING)
- | (1 << NF_IP_PRE_ROUTING)
- | (1 << NF_IP_LOCAL_IN))) {
- printk("ip_local_deliver: bad loopback skb: ");
- debug_print_hooks_ip(skb->nf_debug);
- nf_dump_skb(PF_INET, skb);
- }
- }
- else {
+ } else {
if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
| (1<<NF_IP_LOCAL_IN))) {
- printk("ip_local_deliver: bad non-lo skb: ");
+ printk("ip_local_deliver: bad skb: ");
debug_print_hooks_ip(skb->nf_debug);
nf_dump_skb(PF_INET, skb);
}
debug_print_hooks_ip(newskb->nf_debug);
nf_dump_skb(PF_INET, newskb);
}
- /* Clear to avoid confusing input check */
- newskb->nf_debug = 0;
}
void nf_debug_ip_finish_output2(struct sk_buff *skb)
int (*okfn)(struct sk_buff *),
int hook_thresh)
{
+ unsigned int verdict;
+
/*
* The caller must not block between calls to this
* function because of risk of continuing from deleted element.
/* Optimization: we don't need to hold module
reference here, since function can't sleep. --RR */
- switch (elem->hook(hook, skb, indev, outdev, okfn)) {
- case NF_QUEUE:
- return NF_QUEUE;
-
- case NF_STOLEN:
- return NF_STOLEN;
-
- case NF_DROP:
- return NF_DROP;
-
- case NF_REPEAT:
- *i = (*i)->prev;
- break;
-
+ verdict = elem->hook(hook, skb, indev, outdev, okfn);
+ if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
- case NF_ACCEPT:
- break;
-
- default:
- NFDEBUG("Evil return from %p(%u).\n",
- elem->hook, hook);
+ if (unlikely(verdict > NF_MAX_VERDICT)) {
+ NFDEBUG("Evil return from %p(%u).\n",
+ elem->hook, hook);
+ continue;
+ }
#endif
+ if (verdict != NF_REPEAT)
+ return verdict;
+ *i = (*i)->prev;
}
}
return NF_ACCEPT;
return 1;
}
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+/* Returns 1 if okfn() needs to be executed by the caller,
+ * -EPERM for NF_DROP, 0 otherwise. */
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
rcu_read_lock();
#ifdef CONFIG_NETFILTER_DEBUG
- if (skb->nf_debug & (1 << hook)) {
+ if (unlikely((*pskb)->nf_debug & (1 << hook))) {
printk("nf_hook: hook %i already set.\n", hook);
- nf_dump_skb(pf, skb);
+ nf_dump_skb(pf, *pskb);
}
- skb->nf_debug |= (1 << hook);
+ (*pskb)->nf_debug |= (1 << hook);
#endif
elem = &nf_hooks[pf][hook];
- next_hook:
- verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
+next_hook:
+ verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
outdev, &elem, okfn, hook_thresh);
- if (verdict == NF_QUEUE) {
+ if (verdict == NF_ACCEPT || verdict == NF_STOP) {
+ ret = 1;
+ goto unlock;
+ } else if (verdict == NF_DROP) {
+ kfree_skb(*pskb);
+ ret = -EPERM;
+ } else if (verdict == NF_QUEUE) {
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
- if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
+ if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn))
goto next_hook;
}
-
- switch (verdict) {
- case NF_ACCEPT:
- ret = okfn(skb);
- break;
-
- case NF_DROP:
- kfree_skb(skb);
- ret = -EPERM;
- break;
- }
-
+unlock:
rcu_read_unlock();
return ret;
}
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
{
struct sk_buff *nskb;
- unsigned int iplen;
if (writable_len > (*pskb)->len)
return 0;
if (skb_shared(*pskb) || skb_cloned(*pskb))
goto copy_skb;
- /* Alexey says IP hdr is always modifiable and linear, so ok. */
- if (writable_len <= (*pskb)->nh.iph->ihl*4)
- return 1;
-
- iplen = writable_len - (*pskb)->nh.iph->ihl*4;
-
- /* DaveM says protocol headers are also modifiable. */
- switch ((*pskb)->nh.iph->protocol) {
- case IPPROTO_TCP: {
- struct tcphdr _hdr, *hp;
- hp = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
- sizeof(_hdr), &_hdr);
- if (hp == NULL)
- goto copy_skb;
- if (writable_len <= (*pskb)->nh.iph->ihl*4 + hp->doff*4)
- goto pull_skb;
- goto copy_skb;
- }
- case IPPROTO_UDP:
- if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
- goto pull_skb;
- goto copy_skb;
- case IPPROTO_ICMP:
- if (writable_len
- <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
- goto pull_skb;
- goto copy_skb;
- /* Insert other cases here as desired */
- }
+ return pskb_may_pull(*pskb, writable_len);
copy_skb:
nskb = skb_copy(*pskb, GFP_ATOMIC);
kfree_skb(*pskb);
*pskb = nskb;
return 1;
-
-pull_skb:
- return pskb_may_pull(*pskb, writable_len);
}
EXPORT_SYMBOL(skb_ip_make_writable);
#endif /*CONFIG_INET*/