patch-2.3.15 linux/net/ipv6/sit.c

Next file: linux/net/ipv6/tcp_ipv6.c
Previous file: linux/net/ipv6/route.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: sit.c,v 1.31 1999/03/25 10:04:55 davem Exp $
+ *	$Id: sit.c,v 1.33 1999/08/20 11:06:29 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -70,6 +70,8 @@
 static struct ip_tunnel *tunnels_wc[1];
 static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
 
+static rwlock_t ipip6_lock = RW_LOCK_UNLOCKED;
+
 static struct ip_tunnel * ipip6_tunnel_lookup(u32 remote, u32 local)
 {
 	unsigned h0 = HASH(remote);
@@ -118,8 +120,9 @@
 
 	for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) {
 		if (t == *tp) {
+			write_lock_bh(&ipip6_lock);
 			*tp = t->next;
-			synchronize_bh();
+			write_unlock_bh(&ipip6_lock);
 			break;
 		}
 	}
@@ -129,8 +132,9 @@
 {
 	struct ip_tunnel **tp = ipip6_bucket(t);
 
+	write_lock_bh(&ipip6_lock);
 	t->next = *tp;
-	wmb();
+	write_unlock_bh(&ipip6_lock);
 	*tp = t;
 }
 
@@ -170,12 +174,13 @@
 	nt->dev = dev;
 	dev->name = nt->parms.name;
 	dev->init = ipip6_tunnel_init;
+	dev->new_style = 1;
 	memcpy(&nt->parms, parms, sizeof(*parms));
 	if (dev->name[0] == 0) {
 		int i;
 		for (i=1; i<100; i++) {
 			sprintf(dev->name, "sit%d", i);
-			if (dev_get(dev->name) == NULL)
+			if (__dev_get_by_name(dev->name) == NULL)
 				break;
 		}
 		if (i==100)
@@ -185,6 +190,7 @@
 	if (register_netdevice(dev) < 0)
 		goto failed;
 
+	dev_hold(dev);
 	ipip6_tunnel_link(nt);
 	/* Do not decrement MOD_USE_COUNT here. */
 	return nt;
@@ -195,19 +201,27 @@
 	return NULL;
 }
 
-static void ipip6_tunnel_destroy(struct net_device *dev)
+static void ipip6_tunnel_destructor(struct net_device *dev)
+{
+	if (dev != &ipip6_fb_tunnel_dev) {
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+static void ipip6_tunnel_uninit(struct net_device *dev)
 {
 	if (dev == &ipip6_fb_tunnel_dev) {
+		write_lock_bh(&ipip6_lock);
 		tunnels_wc[0] = NULL;
-		synchronize_bh();
-		return;
+		write_unlock_bh(&ipip6_lock);
+		dev_put(dev);
 	} else {
 		ipip6_tunnel_unlink((struct ip_tunnel*)dev->priv);
-		kfree(dev);
-		MOD_DEC_USE_COUNT;
+		dev_put(dev);
 	}
 }
 
+
 void ipip6_err(struct sk_buff *skb, unsigned char *dp, int len)
 {
 #ifndef I_WISH_WORLD_WERE_PERFECT
@@ -252,17 +266,20 @@
 		break;
 	}
 
+	read_lock(&ipip6_lock);
 	t = ipip6_tunnel_lookup(iph->daddr, iph->saddr);
 	if (t == NULL || t->parms.iph.daddr == 0)
-		return;
+		goto out;
 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
-		return;
+		goto out;
 
 	if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
 		t->err_count++;
 	else
 		t->err_count = 1;
 	t->err_time = jiffies;
+out:
+	read_unlock(&ipip6_lock);
 	return;
 #else
 	struct iphdr *iph = (struct iphdr*)dp;
@@ -358,6 +375,7 @@
 
 	iph = skb->nh.iph;
 
+	read_lock(&ipip6_lock);
 	if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
 		skb->mac.raw = skb->nh.raw;
 		skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data);
@@ -371,11 +389,13 @@
 		dst_release(skb->dst);
 		skb->dst = NULL;
 		netif_rx(skb);
+		read_unlock(&ipip6_lock);
 		return 0;
 	}
 
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
 	kfree_skb(skb);
+	read_unlock(&ipip6_lock);
 	return 0;
 }
 
@@ -602,14 +622,12 @@
 					break;
 				}
 				t = (struct ip_tunnel*)dev->priv;
-				start_bh_atomic();
 				ipip6_tunnel_unlink(t);
 				t->parms.iph.saddr = p.iph.saddr;
 				t->parms.iph.daddr = p.iph.daddr;
 				memcpy(dev->dev_addr, &p.iph.saddr, 4);
 				memcpy(dev->broadcast, &p.iph.daddr, 4);
 				ipip6_tunnel_link(t);
-				end_bh_atomic();
 				netdev_state_change(dev);
 			}
 		}
@@ -671,7 +689,8 @@
 {
 	struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
 
-	dev->destructor		= ipip6_tunnel_destroy;
+	dev->destructor		= ipip6_tunnel_destructor;
+	dev->uninit		= ipip6_tunnel_uninit;
 	dev->hard_start_xmit	= ipip6_tunnel_xmit;
 	dev->get_stats		= ipip6_tunnel_get_stats;
 	dev->do_ioctl		= ipip6_tunnel_ioctl;
@@ -710,7 +729,7 @@
 	}
 
 	if (!tdev && tunnel->parms.link)
-		tdev = dev_get_by_index(tunnel->parms.link);
+		tdev = __dev_get_by_index(tunnel->parms.link);
 
 	if (tdev) {
 		dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
@@ -753,6 +772,7 @@
 	iph->ihl		= 5;
 	iph->ttl		= 64;
 
+	dev_hold(dev);
 	tunnels_wc[0]		= &ipip6_fb_tunnel;
 	return 0;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)