summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_input.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /net/ipv6/ip6_input.c
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'net/ipv6/ip6_input.c')
-rw-r--r--net/ipv6/ip6_input.c89
1 files changed, 19 insertions, 70 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6d7359aef..d8ec7bd95 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.11 1998/08/26 12:04:59 davem Exp $
+ * $Id: ip6_input.c,v 1.14 1999/08/30 12:14:56 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
@@ -38,7 +38,7 @@
#include <net/addrconf.h>
-int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct ipv6hdr *hdr;
u32 pkt_len;
@@ -48,6 +48,9 @@ int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
ipv6_statistics.Ip6InReceives++;
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ goto out;
+
/* Store incoming device index. When the packet will
be queued, we cannot refer to skb->dev anymore.
*/
@@ -86,76 +89,11 @@ err:
ipv6_statistics.Ip6InHdrErrors++;
drop:
kfree_skb(skb);
+out:
return 0;
}
/*
- * 0 - deliver
- * 1 - block
- */
-static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
-{
- struct icmp6hdr *icmph;
- struct raw6_opt *opt;
-
- opt = &sk->tp_pinfo.tp_raw;
- icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1);
- return test_bit(icmph->icmp6_type, &opt->filter);
-}
-
-/*
- * demultiplex raw sockets.
- * (should consider queueing the skb in the sock receive_queue
- * without calling rawv6.c)
- */
-static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
- int nexthdr, unsigned long len)
-{
- struct in6_addr *saddr;
- struct in6_addr *daddr;
- struct sock *sk, *sk2;
- __u8 hash;
-
- saddr = &skb->nh.ipv6h->saddr;
- daddr = saddr + 1;
-
- hash = nexthdr & (MAX_INET_PROTOS - 1);
-
- sk = raw_v6_htable[hash];
-
- /*
- * The first socket found will be delivered after
- * delivery to transport protocols.
- */
-
- if (sk == NULL)
- return NULL;
-
- sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
-
- if (sk) {
- sk2 = sk;
-
- while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
- struct sk_buff *buff;
-
- if (nexthdr == IPPROTO_ICMPV6 &&
- icmpv6_filter(sk2, skb))
- continue;
-
- buff = skb_clone(skb, GFP_ATOMIC);
- if (buff)
- rawv6_rcv(sk2, buff, len);
- }
- }
-
- if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
- sk = NULL;
-
- return sk;
-}
-
-/*
* Deliver the packet to the host
*/
@@ -199,9 +137,17 @@ int ip6_input(struct sk_buff *skb)
}
len = skb->tail - skb->h.raw;
- raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
+ if (skb->rx_dev) {
+ dev_put(skb->rx_dev);
+ skb->rx_dev = NULL;
+ }
+
+ raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
+ if (raw_sk)
+ raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
hash = nexthdr & (MAX_INET_PROTOS - 1);
+ read_lock(&inet6_protocol_lock);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot = (struct inet6_protocol *) ipprot->next) {
@@ -213,12 +159,15 @@ int ip6_input(struct sk_buff *skb)
if (ipprot->copy || raw_sk)
buff = skb_clone(skb, GFP_ATOMIC);
- ipprot->handler(buff, len);
+ if (buff)
+ ipprot->handler(buff, len);
found = 1;
}
+ read_unlock(&inet6_protocol_lock);
if (raw_sk) {
rawv6_rcv(raw_sk, skb, len);
+ sock_put(raw_sk);
found = 1;
}