diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /net/ipv6/icmp.c | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'net/ipv6/icmp.c')
-rw-r--r-- | net/ipv6/icmp.c | 79 |
1 files changed, 63 insertions, 16 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 1abc87541..211db2544 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.22 1999/05/19 22:06:39 davem Exp $ + * $Id: icmp.c,v 1.24 1999/08/20 11:06:18 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -88,6 +88,42 @@ struct icmpv6_msg { }; +static int icmpv6_xmit_holder = -1; + +static int icmpv6_xmit_lock_bh(void) +{ + if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) { + if (icmpv6_xmit_holder == smp_processor_id()) + return -EAGAIN; + spin_lock(&icmpv6_socket->sk->lock.slock); + } + icmpv6_xmit_holder = smp_processor_id(); + return 0; +} + +static __inline__ int icmpv6_xmit_lock(void) +{ + int ret; + local_bh_disable(); + ret = icmpv6_xmit_lock_bh(); + if (ret) + local_bh_enable(); + return ret; +} + +static void icmpv6_xmit_unlock_bh(void) +{ + icmpv6_xmit_holder = -1; + spin_unlock(&icmpv6_socket->sk->lock.slock); +} + +static __inline__ void icmpv6_xmit_unlock(void) +{ + icmpv6_xmit_unlock_bh(); + local_bh_enable(); +} + + /* * getfrag callback @@ -237,7 +273,7 @@ static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) */ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, - struct device *dev) + struct net_device *dev) { struct ipv6hdr *hdr = skb->nh.ipv6h; struct sock *sk = icmpv6_socket->sk; @@ -267,7 +303,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, addr_type = ipv6_addr_type(&hdr->daddr); - if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0)) + if (ipv6_chk_addr(&hdr->daddr, skb->dev)) saddr = &hdr->daddr; /* @@ -319,8 +355,11 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, fl.uli_u.icmpt.type = type; fl.uli_u.icmpt.code = code; - if (!icmpv6_xrlim_allow(sk, type, &fl)) - return; + if (icmpv6_xmit_lock()) + return; + + if (!icmpv6_xrlim_allow(sk, type, &fl)) + goto out; /* * ok. kick it. checksum will be provided by the @@ -341,7 +380,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (len < 0) { printk(KERN_DEBUG "icmp: len problem\n"); - return; + goto out; } msg.len = len; @@ -351,6 +390,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) (&icmpv6_statistics.Icmp6OutDestUnreachs)[type-1]++; icmpv6_statistics.Icmp6OutMsgs++; +out: + icmpv6_xmit_unlock(); } static void icmpv6_echo_reply(struct sk_buff *skb) @@ -393,10 +434,15 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY; fl.uli_u.icmpt.code = 0; + if (icmpv6_xmit_lock_bh()) + return; + ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); icmpv6_statistics.Icmp6OutEchoReplies++; icmpv6_statistics.Icmp6OutMsgs++; + + icmpv6_xmit_unlock_bh(); } static void icmpv6_notify(struct sk_buff *skb, @@ -431,6 +477,7 @@ static void icmpv6_notify(struct sk_buff *skb, 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) { @@ -440,16 +487,16 @@ static void icmpv6_notify(struct sk_buff *skb, if (ipprot->err_handler) ipprot->err_handler(skb, hdr, NULL, type, code, pb, info); } + read_unlock(&inet6_protocol_lock); - sk = raw_v6_htable[hash]; - - if (sk == NULL) - return; - - while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) { - rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); - sk = sk->next; + read_lock(&raw_v6_lock); + if ((sk = raw_v6_htable[hash]) != NULL) { + while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { + rawv6_err(sk, skb, hdr, NULL, type, code, pb, info); + sk = sk->next; + } } + read_unlock(&raw_v6_lock); } /* @@ -458,7 +505,7 @@ static void icmpv6_notify(struct sk_buff *skb, int icmpv6_rcv(struct sk_buff *skb, unsigned long len) { - struct device *dev = skb->dev; + struct net_device *dev = skb->dev; struct in6_addr *saddr = &skb->nh.ipv6h->saddr; struct in6_addr *daddr = &skb->nh.ipv6h->daddr; struct ipv6hdr *orig_hdr; @@ -615,7 +662,7 @@ int __init icmpv6_init(struct net_proto_family *ops) sk = icmpv6_socket->sk; sk->allocation = GFP_ATOMIC; - sk->num = 256; /* Don't receive any data */ + sk->prot->unhash(sk); inet6_add_protocol(&icmpv6_protocol); |