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

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

diff -u --recursive --new-file v2.3.14/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c
@@ -153,6 +153,8 @@
 #define tunnels_l	(tunnels[1])
 #define tunnels_wc	(tunnels[0])
 
+static rwlock_t ipgre_lock = RW_LOCK_UNLOCKED;
+
 /* Given src, dst and key, find approriate for input tunnel. */
 
 static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
@@ -212,8 +214,9 @@
 	struct ip_tunnel **tp = ipgre_bucket(t);
 
 	t->next = *tp;
-	wmb();
+	write_lock_bh(&ipgre_lock);
 	*tp = t;
+	write_unlock_bh(&ipgre_lock);
 }
 
 static void ipgre_tunnel_unlink(struct ip_tunnel *t)
@@ -222,8 +225,9 @@
 
 	for (tp = ipgre_bucket(t); *tp; tp = &(*tp)->next) {
 		if (t == *tp) {
+			write_lock_bh(&ipgre_lock);
 			*tp = t->next;
-			synchronize_bh();
+			write_unlock_bh(&ipgre_lock);
 			break;
 		}
 	}
@@ -266,12 +270,13 @@
 	nt->dev = dev;
 	dev->name = nt->parms.name;
 	dev->init = ipgre_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, "gre%d", i);
-			if (dev_get(dev->name) == NULL)
+			if (__dev_get_by_name(dev->name) == NULL)
 				break;
 		}
 		if (i==100)
@@ -281,6 +286,7 @@
 	if (register_netdevice(dev) < 0)
 		goto failed;
 
+	dev_hold(dev);
 	ipgre_tunnel_link(nt);
 	/* Do not decrement MOD_USE_COUNT here. */
 	return nt;
@@ -291,16 +297,19 @@
 	return NULL;
 }
 
-static void ipgre_tunnel_destroy(struct net_device *dev)
+static void ipgre_tunnel_destructor(struct net_device *dev)
 {
-	ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv);
-
 	if (dev != &ipgre_fb_tunnel_dev) {
-		kfree(dev);
 		MOD_DEC_USE_COUNT;
 	}
 }
 
+static void ipgre_tunnel_uninit(struct net_device *dev)
+{
+	ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv);
+	dev_put(dev);
+}
+
 
 void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len)
 {
@@ -370,18 +379,21 @@
 		break;
 	}
 
+	read_lock(&ipgre_lock);
 	t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0);
 	if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr))
-		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(&ipgre_lock);
 	return;
 #else
 	struct iphdr *iph = (struct iphdr*)dp;
@@ -533,7 +545,7 @@
 		   - We do not support routing headers.
 		 */
 		if (flags&(GRE_VERSION|GRE_ROUTING))
-			goto drop;
+			goto drop_nolock;
 
 		if (flags&GRE_CSUM) {
 			csum = ip_compute_csum(h, len);
@@ -549,6 +561,7 @@
 		}
 	}
 
+	read_lock(&ipgre_lock);
 	if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {
 		skb->mac.raw = skb->nh.raw;
 		skb->nh.raw = skb_pull(skb, h + offset - skb->data);
@@ -587,11 +600,14 @@
 		dst_release(skb->dst);
 		skb->dst = NULL;
 		netif_rx(skb);
+		read_unlock(&ipgre_lock);
 		return(0);
 	}
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
 
 drop:
+	read_unlock(&ipgre_lock);
+drop_nolock:
 	kfree_skb(skb);
 	return(0);
 }
@@ -890,7 +906,6 @@
 					err = -EINVAL;
 					break;
 				}
-				start_bh_atomic();
 				ipgre_tunnel_unlink(t);
 				t->parms.iph.saddr = p.iph.saddr;
 				t->parms.iph.daddr = p.iph.daddr;
@@ -899,7 +914,6 @@
 				memcpy(dev->dev_addr, &p.iph.saddr, 4);
 				memcpy(dev->broadcast, &p.iph.daddr, 4);
 				ipgre_tunnel_link(t);
-				end_bh_atomic();
 				netdev_state_change(dev);
 			}
 		}
@@ -1032,12 +1046,12 @@
 		}
 		dev = rt->u.dst.dev;
 		ip_rt_put(rt);
-		if (dev->ip_ptr == NULL) {
+		if (__in_dev_get(dev) == NULL) {
 			MOD_DEC_USE_COUNT;
 			return -EADDRNOTAVAIL;
 		}
 		t->mlink = dev->ifindex;
-		ip_mc_inc_group(dev->ip_ptr, t->parms.iph.daddr);
+		ip_mc_inc_group(__in_dev_get(dev), t->parms.iph.daddr);
 	}
 	return 0;
 }
@@ -1046,9 +1060,11 @@
 {
 	struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
 	if (MULTICAST(t->parms.iph.daddr) && t->mlink) {
-		dev = dev_get_by_index(t->mlink);
-		if (dev && dev->ip_ptr)
-			ip_mc_dec_group(dev->ip_ptr, t->parms.iph.daddr);
+		struct in_device *in_dev = inetdev_by_index(t->mlink);
+		if (in_dev) {
+			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
+			in_dev_put(in_dev);
+		}
 	}
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -1060,7 +1076,8 @@
 {
 	struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
 
-	dev->destructor		= ipgre_tunnel_destroy;
+	dev->uninit		= ipgre_tunnel_uninit;
+	dev->destructor		= ipgre_tunnel_destructor;
 	dev->hard_start_xmit	= ipgre_tunnel_xmit;
 	dev->get_stats		= ipgre_tunnel_get_stats;
 	dev->do_ioctl		= ipgre_tunnel_ioctl;
@@ -1116,7 +1133,7 @@
 	}
 
 	if (!tdev && tunnel->parms.link)
-		tdev = dev_get_by_index(tunnel->parms.link);
+		tdev = __dev_get_by_index(tunnel->parms.link);
 
 	if (tdev) {
 		hlen = tdev->hard_header_len;
@@ -1170,6 +1187,7 @@
 	iph->ihl		= 5;
 	tunnel->hlen		= sizeof(struct iphdr) + 4;
 
+	dev_hold(dev);
 	tunnels_wc[0]		= &ipgre_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)