patch-2.3.15 linux/net/ipv4/ipip.c

Next file: linux/net/ipv4/ipmr.c
Previous file: linux/net/ipv4/ipconfig.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
@@ -1,7 +1,7 @@
 /*
  *	Linux NET3:	IP/IP protocol decoder. 
  *
- *	Version: $Id: ipip.c,v 1.26 1999/03/25 10:04:32 davem Exp $
+ *	Version: $Id: ipip.c,v 1.28 1999/08/20 11:05:51 davem Exp $
  *
  *	Authors:
  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -133,6 +133,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 ipip_lock = RW_LOCK_UNLOCKED;
+
 static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
 {
 	unsigned h0 = HASH(remote);
@@ -182,8 +184,9 @@
 
 	for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) {
 		if (t == *tp) {
+			write_lock_bh(&ipip_lock);
 			*tp = t->next;
-			synchronize_bh();
+			write_unlock_bh(&ipip_lock);
 			break;
 		}
 	}
@@ -194,8 +197,9 @@
 	struct ip_tunnel **tp = ipip_bucket(t);
 
 	t->next = *tp;
-	wmb();
+	write_lock_bh(&ipip_lock);
 	*tp = t;
+	write_unlock_bh(&ipip_lock);
 }
 
 struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create)
@@ -234,12 +238,13 @@
 	nt->dev = dev;
 	dev->name = nt->parms.name;
 	dev->init = ipip_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, "tunl%d", i);
-			if (dev_get(dev->name) == NULL)
+			if (__dev_get_by_name(dev->name) == NULL)
 				break;
 		}
 		if (i==100)
@@ -249,6 +254,7 @@
 	if (register_netdevice(dev) < 0)
 		goto failed;
 
+	dev_hold(dev);
 	ipip_tunnel_link(nt);
 	/* Do not decrement MOD_USE_COUNT here. */
 	return nt;
@@ -259,16 +265,23 @@
 	return NULL;
 }
 
+static void ipip_tunnel_destructor(struct net_device *dev)
+{
+	if (dev != &ipip_fb_tunnel_dev) {
+		MOD_DEC_USE_COUNT;
+	}
+}
 
-static void ipip_tunnel_destroy(struct net_device *dev)
+static void ipip_tunnel_uninit(struct net_device *dev)
 {
 	if (dev == &ipip_fb_tunnel_dev) {
+		write_lock_bh(&ipip_lock);
 		tunnels_wc[0] = NULL;
-		synchronize_bh();
+		write_unlock_bh(&ipip_lock);
+		dev_put(dev);
 	} else {
 		ipip_tunnel_unlink((struct ip_tunnel*)dev->priv);
-		kfree(dev);
-		MOD_DEC_USE_COUNT;
+		dev_put(dev);
 	}
 }
 
@@ -316,17 +329,20 @@
 		break;
 	}
 
+	read_lock(&ipip_lock);
 	t = ipip_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(&ipip_lock);
 	return;
 #else
 	struct iphdr *iph = (struct iphdr*)dp;
@@ -460,6 +476,7 @@
 	skb->ip_summed = 0;
 	skb->pkt_type = PACKET_HOST;
 
+	read_lock(&ipip_lock);
 	if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
 		tunnel->stat.rx_packets++;
 		tunnel->stat.rx_bytes += skb->len;
@@ -467,8 +484,10 @@
 		dst_release(skb->dst);
 		skb->dst = NULL;
 		netif_rx(skb);
+		read_unlock(&ipip_lock);
 		return 0;
 	}
+	read_unlock(&ipip_lock);
 
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
 	kfree_skb(skb);
@@ -674,14 +693,12 @@
 					break;
 				}
 				t = (struct ip_tunnel*)dev->priv;
-				start_bh_atomic();
 				ipip_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);
 				ipip_tunnel_link(t);
-				end_bh_atomic();
 				netdev_state_change(dev);
 			}
 		}
@@ -744,7 +761,8 @@
 {
 	struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
 
-	dev->destructor		= ipip_tunnel_destroy;
+	dev->uninit		= ipip_tunnel_uninit;
+	dev->destructor		= ipip_tunnel_destructor;
 	dev->hard_start_xmit	= ipip_tunnel_xmit;
 	dev->get_stats		= ipip_tunnel_get_stats;
 	dev->do_ioctl		= ipip_tunnel_ioctl;
@@ -783,7 +801,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);
@@ -823,6 +841,7 @@
 	iph->protocol		= IPPROTO_IPIP;
 	iph->ihl		= 5;
 
+	dev_hold(dev);
 	tunnels_wc[0]		= &ipip_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)