patch-2.4.15 linux/net/irda/irlmp.c

Next file: linux/net/irda/irlmp_event.c
Previous file: linux/net/irda/irlap_frame.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
@@ -11,6 +11,7 @@
  * 
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
+ *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -75,7 +76,7 @@
  */
 int __init irlmp_init(void)
 {
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 	/* Initialize the irlmp structure. */
 	irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
 	if (irlmp == NULL)
@@ -170,14 +171,14 @@
 #endif /* CONFIG_IRDA_ULTRA */
 	} else
 		self->dlsap_sel = LSAP_ANY;
-	self->connected = FALSE;
+	/* self->connected = FALSE; -> already NULL via memset() */
 
 	init_timer(&self->watchdog_timer);
 
 	ASSERT(notify->instance != NULL, return NULL;);
 	self->notify = *notify;
 
-	irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
+	self->lsap_state = LSAP_DISCONNECTED;
 	
 	/* Insert into queue of unconnected LSAPs */
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, 
@@ -237,6 +238,7 @@
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
 	}
+	self->lap = NULL;
 	/* Check if we found the LSAP! If not then try the unconnected lsaps */
 	if (!lsap) {
 		lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, 
@@ -281,7 +283,7 @@
 	lap->daddr = DEV_ADDR_ANY;
 	lap->lsaps = hashbin_new(HB_GLOBAL);
 
-	irlmp_next_lap_state(lap, LAP_STANDBY);
+	lap->lap_state = LAP_STANDBY;
 	
 	init_timer(&lap->idle_timer);
 
@@ -346,7 +348,7 @@
 	      "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", 
 	      self->slsap_sel, dlsap_sel, saddr, daddr);
 	
-	if (self->connected) 
+	if (test_bit(0, &self->connected))
 		return -EISCONN;
 	
 	/* Client must supply destination device address */
@@ -435,7 +437,7 @@
 
 	hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL);
 
-	self->connected = TRUE;
+	set_bit(0, &self->connected);	/* TRUE */
 	
 	/*
 	 *  User supplied qos specifications?
@@ -481,6 +483,8 @@
 		self->notify.connect_indication(self->notify.instance, self, 
 						&self->qos, max_seg_size, 
 						max_header_size, skb);
+	else
+		dev_kfree_skb(skb);
 }
 
 /*
@@ -495,7 +499,7 @@
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 	ASSERT(userdata != NULL, return -1;);
 
-	self->connected = TRUE;
+	set_bit(0, &self->connected);	/* TRUE */
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
 		   self->slsap_sel, self->dlsap_sel);
@@ -543,7 +547,8 @@
 		self->notify.connect_confirm(self->notify.instance, self,
 					     &self->qos, max_seg_size,
 					     max_header_size, skb);
-	}
+	} else
+		dev_kfree_skb(skb);
 }
 
 /*
@@ -598,16 +603,18 @@
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	ASSERT(userdata != NULL, return -1;);
 
-	/* Already disconnected? */
-	if (!self->connected) {
-		WARNING(__FUNCTION__ "(), already disconnected!\n");
+	/* Already disconnected ?
+	 * There is a race condition between irlmp_disconnect_indication()
+	 * and us that might mess up the hashbins below. This fixes it.
+	 * Jean II */
+	if (! test_and_clear_bit(0, &self->connected)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n");
+		dev_kfree_skb(userdata);
 		return -1;
 	}
 
-	ASSERT(userdata != NULL, return -1;);
-	ASSERT(self->connected == TRUE, return -1;);
-	
 	skb_push(userdata, LMP_CONTROL_HEADER);
 
 	/* 
@@ -634,7 +641,6 @@
 		       NULL);
 	
 	/* Reset some values */
-	self->connected = FALSE;
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	
@@ -651,16 +657,23 @@
 {
 	struct lsap_cb *lsap;
 
-	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);	
+	IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- 	ASSERT(self->connected == TRUE, return;); 
 
 	IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
 		   self->slsap_sel, self->dlsap_sel);
 
-	self->connected = FALSE;
-	self->dlsap_sel = LSAP_ANY;
+	/* Already disconnected ?
+	 * There is a race condition between irlmp_disconnect_request()
+	 * and us that might mess up the hashbins below. This fixes it.
+	 * Jean II */
+	if (! test_and_clear_bit(0, &self->connected)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n");
+		if (userdata)
+			dev_kfree_skb(userdata);
+		return;
+	}
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	irlmp->cache.valid = FALSE;
@@ -679,6 +692,7 @@
 	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap, 
 		       NULL);
 
+	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	
 	/*
@@ -689,7 +703,8 @@
 						   self, reason, userdata);
 	else {
 		IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
-		dev_kfree_skb(userdata);
+		if (userdata)
+			dev_kfree_skb(userdata);
 	}
 }
 
@@ -1401,7 +1416,7 @@
 	irlmp_client_t *client;
 	__u32 handle;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 	ASSERT(irlmp != NULL, return 0;);
 	
 	/* Get a unique handle for this client */
@@ -1673,14 +1688,15 @@
 
 		len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
 			       lap->saddr, lap->daddr); 
-		len += sprintf(buf+len, "refcount: %d", lap->refcount);
+		len += sprintf(buf+len, "num lsaps: %d",
+			       HASHBIN_GET_SIZE(lap->lsaps));
 		len += sprintf(buf+len, "\n");
 
-		len += sprintf(buf+len, "\nConnected LSAPs:\n");
+		len += sprintf(buf+len, "\n  Connected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
 			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
-			len += sprintf(buf+len, "lsap state: %s, ", 
+			len += sprintf(buf+len, "  lsap state: %s, ", 
 				       irlsap_state[ self->lsap_state]);
 			len += sprintf(buf+len, 
 				       "slsap_sel: %#02x, dlsap_sel: %#02x, ",

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