patch-2.3.15 linux/net/ipv6/icmp.c
Next file: linux/net/ipv6/ip6_fib.c
Previous file: linux/net/ipv6/datagram.c
Back to the patch index
Back to the overall index
- Lines: 151
- Date:
Mon Aug 23 10:01:02 1999
- Orig file:
v2.3.14/linux/net/ipv6/icmp.c
- Orig date:
Wed Aug 18 11:38:49 1999
diff -u --recursive --new-file v2.3.14/linux/net/ipv6/icmp.c linux/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 @@
};
+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
@@ -267,7 +303,7 @@
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 @@
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 @@
if (len < 0) {
printk(KERN_DEBUG "icmp: len problem\n");
- return;
+ goto out;
}
msg.len = len;
@@ -351,6 +390,8 @@
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 @@
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 @@
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 @@
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);
}
/*
@@ -615,7 +662,7 @@
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);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)