patch-2.2.17 linux/net/appletalk/ddp.c

Next file: linux/net/bridge/br.c
Previous file: linux/net/appletalk/aarp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.16/net/appletalk/ddp.c linux/net/appletalk/ddp.c
@@ -37,6 +37,8 @@
  *                                              port assignment. we lose a 
  *                                              valid localtalk port as a 
  *                                              result.
+ *              Arnaldo Melo		:	fix minor skb handling bug
+ *              				in atalk_rcv
  *              
  *
  *		This program is free software; you can redistribute it and/or
@@ -129,18 +131,23 @@
 
 extern inline void atalk_remove_socket(struct sock *sk)
 {
+	SOCKHASH_LOCK();
 	sklist_remove_socket(&atalk_socket_list,sk);
+	SOCKHASH_UNLOCK();
 }
 
 extern inline void atalk_insert_socket(struct sock *sk)
 {
+	SOCKHASH_LOCK();
 	sklist_insert_socket(&atalk_socket_list,sk);
+	SOCKHASH_UNLOCK();
 }
 
 static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif)
 {
 	struct sock *s;
 
+	SOCKHASH_LOCK();
 	for(s = atalk_socket_list; s != NULL; s = s->next)
 	{
 		if(to->sat_port != s->protinfo.af_at.src_port)
@@ -172,6 +179,7 @@
 			break; 
 		}
 	}
+	SOCKHASH_UNLOCK();
 
 	return (s);
 }
@@ -183,6 +191,8 @@
 {
 	struct sock *s;
 
+	SOCKHASH_LOCK();
+
 	for(s = atalk_socket_list; s != NULL; s = s->next)
 	{
 		if(s->protinfo.af_at.src_net != sat->sat_addr.s_net)
@@ -203,12 +213,15 @@
 		break;
 	}
 
+	SOCKHASH_UNLOCK();
 	return (s);
 }
 
 extern inline void atalk_destroy_socket(struct sock *sk)
 {
+	SOCKHASH_LOCK();
 	sklist_destroy_socket(&atalk_socket_list, sk);
+	SOCKHASH_UNLOCK();
 	MOD_DEC_USE_COUNT;
 }
 
@@ -227,6 +240,7 @@
 	 */
 
 	len += sprintf(buffer,"Type local_addr  remote_addr tx_queue rx_queue st uid\n");
+	SOCKHASH_LOCK();
 	for(s = atalk_socket_list; s != NULL; s = s->next)
 	{
 		len += sprintf(buffer+len,"%02X   ", s->type);
@@ -256,6 +270,8 @@
 			break;
 	}
 
+	SOCKHASH_UNLOCK();
+
 	/* The data in question runs from begin to begin+len */
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);   /* Remove unwanted header data from length */
@@ -288,6 +304,7 @@
 	struct atalk_iface **iface = &atalk_iface_list;
 	struct atalk_iface *tmp;
 
+	SOCKHASH_LOCK();
 	while((tmp = *iface) != NULL)
 	{
 		if(tmp->dev == dev)
@@ -300,14 +317,13 @@
 		else
 			iface = &tmp->next;
 	}
-
+	SOCKHASH_UNLOCK();
 }
 
 static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa)
 {
 	struct atalk_iface *iface = (struct atalk_iface *)
 		kmalloc(sizeof(*iface), GFP_KERNEL);
-	unsigned long flags;
 
 	if(iface==NULL)
 		return (NULL);
@@ -316,11 +332,11 @@
 	dev->atalk_ptr=iface;
 	iface->address= *sa;
 	iface->status=0;
-	save_flags(flags);
-	cli();
+
+	SOCKHASH_LOCK();
 	iface->next=atalk_iface_list;
 	atalk_iface_list=iface;
-	restore_flags(flags);
+	SOCKHASH_UNLOCK();
 
 	MOD_INC_USE_COUNT;
 
@@ -487,20 +503,29 @@
 	 * Return a point-to-point interface only if
 	 * there is no non-ptp interface available.
 	 */
+	SOCKHASH_LOCK();
 	for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
 	{
 		if(!fiface && !(iface->dev->flags & IFF_LOOPBACK))
 			fiface=iface;
-		if(!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
+		if(!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+			SOCKHASH_UNLOCK();
 			return (&iface->address);
+		}
 	}
 
-	if(fiface)
+	if(fiface) {
+		SOCKHASH_UNLOCK();
 		return (&fiface->address);
-	if(atalk_iface_list != NULL)
+	}
+	if(atalk_iface_list != NULL) {
+		SOCKHASH_UNLOCK();
 		return (&atalk_iface_list->address);
-	else
+	}
+	else {
+		SOCKHASH_UNLOCK();
 		return (NULL);
+	}
 }
 
 /*
@@ -527,21 +552,27 @@
 {
 	struct atalk_iface *iface;
 
+	SOCKHASH_LOCK();
 	for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
 	{
 		if((node==ATADDR_BCAST || node==ATADDR_ANYNODE 
 			|| iface->address.s_node==node)
 			&& iface->address.s_net==net 
-			&& !(iface->status & ATIF_PROBE))
+			&& !(iface->status & ATIF_PROBE)) {
+			SOCKHASH_UNLOCK();
 			return (iface);
+		}
 
 		/* XXXX.0 -- net.0 returns the iface associated with net */
 		if ((node==ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
 		    (ntohs(iface->nets.nr_firstnet) <= ntohs(net)) &&
-		    (ntohs(net) <= ntohs(iface->nets.nr_lastnet)))
+		    (ntohs(net) <= ntohs(iface->nets.nr_lastnet))) {
+			SOCKHASH_UNLOCK();
 		        return (iface);
+		}
 	}
 
+	SOCKHASH_UNLOCK();
 	return (NULL);
 }
 
@@ -561,6 +592,7 @@
 	struct atalk_route *r;
 	struct atalk_route *net_route = NULL;
 	
+	SOCKHASH_LOCK();
 	for(r=atalk_router_list; r != NULL; r=r->next)
 	{
 		if(!(r->flags & RTF_UP))
@@ -573,8 +605,10 @@
 				 * if this host route is for the target,
 				 * the we're done
 				 */
-				if (r->target.s_node == target->s_node)
+				if (r->target.s_node == target->s_node) {
+					SOCKHASH_UNLOCK();
 					return (r);
+				}
 			}
 			else
 			{
@@ -591,12 +625,17 @@
 	 * if we found a network route but not a direct host
 	 * route, then return it
 	 */
-	if (net_route != NULL)
+	if (net_route != NULL) {
+		SOCKHASH_UNLOCK();
 		return (net_route);
+	}
 
-	if(atrtr_default.dev)
+	if(atrtr_default.dev) {
+		SOCKHASH_UNLOCK();
 		return (&atrtr_default);
+	}
 
+	SOCKHASH_UNLOCK();
 	return (NULL);
 }
 
@@ -637,9 +676,6 @@
 	struct sockaddr_at *ga=(struct sockaddr_at *)&r->rt_gateway;
 	struct atalk_route *rt;
 	struct atalk_iface *iface, *riface;
-	unsigned long flags;
-
-	save_flags(flags);
 
 	/*
 	 * Fixme: Raise/Lower a routing change semaphore for these
@@ -657,6 +693,7 @@
 	/*
 	 * Now walk the routing table and make our decisions.
 	 */
+	SOCKHASH_LOCK();
 	for(rt=atalk_router_list; rt!=NULL; rt=rt->next)
 	{
 		if(r->rt_flags != rt->flags)
@@ -685,17 +722,21 @@
 				riface = iface;
 		}
 
-		if(riface == NULL)
+		if(riface == NULL) {
+			SOCKHASH_UNLOCK();
 			return (-ENETUNREACH);
+		}
 		devhint = riface->dev;
 	}
 
 	if(rt == NULL)
 	{
-		rt = (struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_KERNEL);
-		if(rt == NULL)
+		rt = (struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_ATOMIC);
+		if(rt == NULL) {
+			SOCKHASH_UNLOCK();
 			return (-ENOBUFS);
-		cli();
+		}
+
 		rt->next = atalk_router_list;
 		atalk_router_list = rt;
 	}
@@ -708,8 +749,7 @@
 	rt->flags   = r->rt_flags;
 	rt->gateway = ga->sat_addr;
 
-	restore_flags(flags);
-
+	SOCKHASH_UNLOCK();
 	return (0);
 }
 
@@ -720,7 +760,8 @@
 {
 	struct atalk_route **r = &atalk_router_list;
 	struct atalk_route *tmp;
-
+	
+	SOCKHASH_LOCK();
 	while((tmp = *r) != NULL)
 	{
 		if(tmp->target.s_net == addr->s_net
@@ -729,11 +770,13 @@
 		{
 			*r = tmp->next;
 			kfree_s(tmp, sizeof(struct atalk_route));
+			SOCKHASH_UNLOCK();
 			return (0);
 		}
 		r = &tmp->next;
 	}
-
+	
+	SOCKHASH_UNLOCK();
 	return (-ENOENT);
 }
 
@@ -746,6 +789,7 @@
 	struct atalk_route **r = &atalk_router_list;
 	struct atalk_route *tmp;
 
+	SOCKHASH_LOCK();
 	while((tmp = *r) != NULL)
 	{
 		if(tmp->dev == dev)
@@ -756,6 +800,7 @@
 		else
 			r = &tmp->next;
 	}
+	SOCKHASH_UNLOCK();
 
 	if(atrtr_default.dev == dev)
 		atrtr_set_default(NULL);
@@ -1061,6 +1106,7 @@
 	off_t begin=0;
 
 	len += sprintf(buffer,"Interface	  Address   Networks   Status\n");
+	SOCKHASH_LOCK();
 	for(iface = atalk_iface_list; iface != NULL; iface = iface->next)
 	{
 		len += sprintf(buffer+len,"%-16s %04X:%02X  %04X-%04X  %d\n",
@@ -1076,6 +1122,8 @@
 		if(pos > offset + length)
 			break;
 	}
+	SOCKHASH_UNLOCK();
+
 	*start = buffer + (offset - begin);
 	len -= (offset - begin);
 	if(len > length)
@@ -1102,6 +1150,7 @@
 			rt->dev->name);
 	}
 
+	SOCKHASH_LOCK();
 	for(rt = atalk_router_list; rt != NULL; rt = rt->next)
 	{
 		len += sprintf(buffer+len,"%04X:%02X     %04X:%02X  %-4d  %s\n",
@@ -1117,6 +1166,7 @@
 		if(pos > offset + length)
 			break;
 	}
+	SOCKHASH_UNLOCK();
 
 	*start = buffer + (offset - begin);
 	len -= (offset - begin);
@@ -1238,12 +1288,16 @@
  */
 static int atalk_pick_port(struct sockaddr_at *sat)
 {
+	SOCKHASH_LOCK();
 	for(sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++)
 	{
 		if(atalk_find_socket(sat) == NULL)
+		{
+			SOCKHASH_UNLOCK();
 			return sat->sat_port;
+		}
 	}
-
+	SOCKHASH_UNLOCK();
 	return (-EBUSY);
 }
 
@@ -1583,8 +1637,14 @@
 		 * Note. ddp-> becomes invalid at the realloc.
 		 */
 		if(skb_headroom(skb) < 22)
+		{
 			/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
-			skb = skb_realloc_headroom(skb, 32);
+			struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
+			kfree_skb(skb);
+			if (!nskb)
+				return 0;
+			skb=nskb;
+		}
 		else
 			skb = skb_unshare(skb, GFP_ATOMIC);
 		

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