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

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)