diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-30 09:13:03 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-07-30 09:13:03 +0200 |
commit | fcb06702f023a0e7b1e6ebf9746f34b610ca0508 (patch) | |
tree | db022324c4978dd9af059be38822d23455a45f55 /net/ipv4/ip_input.c | |
parent | wireless: reg: restore previous behaviour of chan->max_power calculations (diff) | |
parent | bcma: add missing iounmap on error path (diff) | |
download | linux-fcb06702f023a0e7b1e6ebf9746f34b610ca0508.tar.xz linux-fcb06702f023a0e7b1e6ebf9746f34b610ca0508.zip |
Merge remote-tracking branch 'wireless/master' into mac80211
Diffstat (limited to 'net/ipv4/ip_input.c')
-rw-r--r-- | net/ipv4/ip_input.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 8590144ca330..93134b0eab0c 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -198,14 +198,13 @@ static int ip_local_deliver_finish(struct sk_buff *skb) rcu_read_lock(); { int protocol = ip_hdr(skb)->protocol; - int hash, raw; const struct net_protocol *ipprot; + int raw; resubmit: raw = raw_local_deliver(skb, protocol); - hash = protocol & (MAX_INET_PROTOS - 1); - ipprot = rcu_dereference(inet_protos[hash]); + ipprot = rcu_dereference(inet_protos[protocol]); if (ipprot != NULL) { int ret; @@ -314,26 +313,36 @@ drop: return true; } +int sysctl_ip_early_demux __read_mostly = 1; + static int ip_rcv_finish(struct sk_buff *skb) { const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; + if (sysctl_ip_early_demux && !skb_dst(skb)) { + const struct net_protocol *ipprot; + int protocol = iph->protocol; + + rcu_read_lock(); + ipprot = rcu_dereference(inet_protos[protocol]); + if (ipprot && ipprot->early_demux) { + ipprot->early_demux(skb); + /* must reload iph, skb->head might have changed */ + iph = ip_hdr(skb); + } + rcu_read_unlock(); + } + /* * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (skb_dst(skb) == NULL) { - int err = ip_route_input_noref(skb, iph->daddr, iph->saddr, - iph->tos, skb->dev); + if (!skb_dst(skb)) { + int err = ip_route_input(skb, iph->daddr, iph->saddr, + iph->tos, skb->dev); if (unlikely(err)) { - if (err == -EHOSTUNREACH) - IP_INC_STATS_BH(dev_net(skb->dev), - IPSTATS_MIB_INADDRERRORS); - else if (err == -ENETUNREACH) - IP_INC_STATS_BH(dev_net(skb->dev), - IPSTATS_MIB_INNOROUTES); - else if (err == -EXDEV) + if (err == -EXDEV) NET_INC_STATS_BH(dev_net(skb->dev), LINUX_MIB_IPRPFILTER); goto drop; |