<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">ChangeSet 1.985.10.4, 2003/03/25 11:34:04-08:00, baldrick@wanadoo.fr

[PATCH] USB speedtouch: per vcc data cleanups

Use struct list_head rather than a singly linked list in udsl_vcc_data.  Reject
attempts to open multiple vccs with the same vpi/vci pair.  Some cleanups too.


 drivers/usb/misc/speedtch.c |  204 +++++++++++++++++++++-----------------------
 1 files changed, 98 insertions(+), 106 deletions(-)


diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c
--- a/drivers/usb/misc/speedtch.c	Tue Mar 25 16:46:46 2003
+++ b/drivers/usb/misc/speedtch.c	Tue Mar 25 16:46:46 2003
@@ -150,10 +150,9 @@
 
 struct udsl_vcc_data {
 	/* vpi/vci lookup */
-	struct udsl_vcc_data *next;
-	unsigned int vpi;
-	unsigned int vci;
-	unsigned long atmHeader;
+	struct list_head list;
+	short vpi;
+	int vci;
 	struct atm_vcc *vcc;
 
 	/* raw cell reassembly */
@@ -175,7 +174,7 @@
 
 	/* atm device part */
 	struct atm_dev *atm_dev;
-	struct udsl_vcc_data *vcc_list;
+	struct list_head vcc_list;
 
 	/* receiving */
 	struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS];
@@ -247,11 +246,19 @@
 **  decode  **
 *************/
 
-#define ATM_HDR_VPVC_MASK		(ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
+static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *instance, short vpi, int vci)
+{
+	struct udsl_vcc_data *vcc;
 
-static struct sk_buff *udsl_decode_rawcell (struct udsl_vcc_data *list, struct sk_buff *skb, struct udsl_vcc_data **ctx)
+	list_for_each_entry (vcc, &amp;instance-&gt;vcc_list, list)
+		if ((vcc-&gt;vpi == vpi) &amp;&amp; (vcc-&gt;vci == vci))
+			return vcc;
+	return NULL;
+}
+
+static struct sk_buff *udsl_decode_rawcell (struct udsl_instance_data *instance, struct sk_buff *skb, struct udsl_vcc_data **ctx)
 {
-	if (!list || !skb || !ctx)
+	if (!instance || !skb || !ctx)
 		return NULL;
 	if (!skb-&gt;data || !skb-&gt;tail)
 		return NULL;
@@ -259,68 +266,66 @@
 	while (skb-&gt;len) {
 		unsigned char *cell = skb-&gt;data;
 		unsigned char *cell_payload;
-		struct udsl_vcc_data *vcc = list;
-		unsigned long atmHeader =
-		    ((unsigned long) (cell[0]) &lt;&lt; 24) | ((unsigned long) (cell[1]) &lt;&lt; 16) |
-		    ((unsigned long) (cell[2]) &lt;&lt; 8) | (cell[3] &amp; 0xff);
+		struct udsl_vcc_data *vcc;
+		short vpi;
+		int vci;
+
+		vpi = ((cell[0] &amp; 0x0f) &lt;&lt; 4) | (cell[1] &gt;&gt; 4);
+		vci = ((cell[1] &amp; 0x0f) &lt;&lt; 12) | (cell[2] &lt;&lt; 4) | (cell[3] &gt;&gt; 4);
 
-		dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx);
+		dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx);
 		dbg ("udsl_decode_rawcell skb-&gt;data %p, skb-&gt;tail %p", skb-&gt;data, skb-&gt;tail);
 
 		/* here should the header CRC check be... */
 
-		/* look up correct vcc */
-		for (;
-		     vcc
-		     &amp;&amp; ((vcc-&gt;atmHeader &amp; ATM_HDR_VPVC_MASK) != (atmHeader &amp; ATM_HDR_VPVC_MASK));
-		     vcc = vcc-&gt;next);
-
-		dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc,
-			(int) ((atmHeader &amp; ATM_HDR_VPI_MASK) &gt;&gt; ATM_HDR_VPI_SHIFT),
-			(int) ((atmHeader &amp; ATM_HDR_VCI_MASK) &gt;&gt; ATM_HDR_VCI_SHIFT));
-
-		if (vcc &amp;&amp; (skb-&gt;len &gt;= 53)) {
-			cell_payload = cell + 5;
-
-			if (!vcc-&gt;reasBuffer)
-				vcc-&gt;reasBuffer = dev_alloc_skb (vcc-&gt;mtu);
-
-			/* if alloc fails, we just drop the cell. it is possible that we can still
-			 * receive cells on other vcc's
-			 */
-			if (vcc-&gt;reasBuffer) {
-				/* if (buffer overrun) discard received cells until now */
-				if ((vcc-&gt;reasBuffer-&gt;len) &gt; (vcc-&gt;mtu - 48))
-					skb_trim (vcc-&gt;reasBuffer, 0);
-
-				/* copy data */
-				memcpy (vcc-&gt;reasBuffer-&gt;tail, cell_payload, 48);
-				skb_put (vcc-&gt;reasBuffer, 48);
-
-				/* check for end of buffer */
-				if (cell[3] &amp; 0x2) {
-					struct sk_buff *tmp;
-
-					/* the aal5 buffer ends here, cut the buffer. */
-					/* buffer will always have at least one whole cell, so */
-					/* don't need to check return from skb_pull */
-					skb_pull (skb, 53);
-					*ctx = vcc;
-					tmp = vcc-&gt;reasBuffer;
-					vcc-&gt;reasBuffer = NULL;
+		if (!(vcc = udsl_find_vcc (instance, vpi, vci)))
+			dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d", vpi, vci);
+		else {
+			dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci);
+
+			if (skb-&gt;len &gt;= 53) {
+				cell_payload = cell + 5;
+
+				if (!vcc-&gt;reasBuffer)
+					vcc-&gt;reasBuffer = dev_alloc_skb (vcc-&gt;mtu);
+
+				/* if alloc fails, we just drop the cell. it is possible that we can still
+				 * receive cells on other vcc's
+				 */
+				if (vcc-&gt;reasBuffer) {
+					/* if (buffer overrun) discard received cells until now */
+					if ((vcc-&gt;reasBuffer-&gt;len) &gt; (vcc-&gt;mtu - 48))
+						skb_trim (vcc-&gt;reasBuffer, 0);
+
+					/* copy data */
+					memcpy (vcc-&gt;reasBuffer-&gt;tail, cell_payload, 48);
+					skb_put (vcc-&gt;reasBuffer, 48);
+
+					/* check for end of buffer */
+					if (cell[3] &amp; 0x2) {
+						struct sk_buff *tmp;
+
+						/* the aal5 buffer ends here, cut the buffer. */
+						/* buffer will always have at least one whole cell, so */
+						/* don't need to check return from skb_pull */
+						skb_pull (skb, 53);
+						*ctx = vcc;
+						tmp = vcc-&gt;reasBuffer;
+						vcc-&gt;reasBuffer = NULL;
 
-					dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp-&gt;len);
-					return tmp;
+						dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp-&gt;len);
+						return tmp;
+					}
 				}
+				/* flush the cell */
+				/* buffer will always contain at least one whole cell, so don't */
+				/* need to check return value from skb_pull */
+				skb_pull (skb, 53);
+			} else {
+				/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
+				if (skb_pull (skb, 53) == NULL)
+					return NULL;
 			}
-			/* flush the cell */
-			/* buffer will always contain at least one whole cell, so don't */
-			/* need to check return value from skb_pull */
-			skb_pull (skb, 53);
-		} else {
-			/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
-			if (skb_pull (skb, 53) == NULL)
-				return NULL;
 		}
 	}
 
@@ -342,8 +347,7 @@
 	    (skb-&gt;tail[-4] &lt;&lt; 24) + (skb-&gt;tail[-3] &lt;&lt; 16) + (skb-&gt;tail[-2] &lt;&lt; 8) + skb-&gt;tail[-1];
 	pdu_length = ((length + 47 + 8) / 48) * 48;
 
-	dbg ("udsl_decode_aal5: skb-&gt;len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d",
-		skb-&gt;len, length, pdu_crc, pdu_length);
+	dbg ("udsl_decode_aal5: skb-&gt;len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb-&gt;len, length, pdu_crc, pdu_length);
 
 	/* is skb long enough ? */
 	if (skb-&gt;len &lt; pdu_length) {
@@ -354,8 +358,7 @@
 
 	/* is skb too long ? */
 	if (skb-&gt;len &gt; pdu_length) {
-		dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -&gt; %d",
-			skb-&gt;len, pdu_length);
+		dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -&gt; %d", skb-&gt;len, pdu_length);
 		/* buffer is too long. we can try to recover
 		 * if we discard the first part of the skb.
 		 * the crc will decide whether this was ok
@@ -548,7 +551,7 @@
 			dbg ("skb-&gt;len = %d", skb-&gt;len);
 			PACKETDEBUG (skb-&gt;data, skb-&gt;len);
 
-			while ((new = udsl_decode_rawcell (instance-&gt;vcc_list, skb, &amp;atmsar_vcc))) {
+			while ((new = udsl_decode_rawcell (instance, skb, &amp;atmsar_vcc))) {
 				dbg ("(after cell processing)skb-&gt;len = %d", new-&gt;len);
 
 				tmp = new;
@@ -923,94 +926,81 @@
 		return -ENODEV;
 	}
 
+	if ((vpi == ATM_VPI_ANY) || (vci == ATM_VCI_ANY))
+		return -EINVAL;
+
 	/* only support AAL5 */
 	if (vcc-&gt;qos.aal != ATM_AAL5)
 		return -EINVAL;
 
+	if (udsl_find_vcc (instance, vpi, vci))
+		return -EADDRINUSE;
+
 	if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL)))
 		return -ENOMEM;
 
-	MOD_INC_USE_COUNT;
-
 	memset (new, 0, sizeof (struct udsl_vcc_data));
 	new-&gt;vcc = vcc;
 	new-&gt;vpi = vpi;
 	new-&gt;vci = vci;
-
 	new-&gt;mtu = UDSL_MAX_AAL5_MRU;
 
-	new-&gt;atmHeader = ((unsigned long) vpi &lt;&lt; ATM_HDR_VPI_SHIFT) |
-			 ((unsigned long) vci &lt;&lt; ATM_HDR_VCI_SHIFT);
-	new-&gt;reasBuffer = NULL;
-
-	new-&gt;next = instance-&gt;vcc_list;
-	instance-&gt;vcc_list = new;
-
-	dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
-
 	vcc-&gt;dev_data = new;
-
 	vcc-&gt;vpi = vpi;
 	vcc-&gt;vci = vci;
+
+	list_add (&amp;new-&gt;list, &amp;instance-&gt;vcc_list);
+
 	set_bit (ATM_VF_ADDR, &amp;vcc-&gt;flags);
 	set_bit (ATM_VF_PARTIAL, &amp;vcc-&gt;flags);
 	set_bit (ATM_VF_READY, &amp;vcc-&gt;flags);
 
+	dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
+
+	MOD_INC_USE_COUNT;
+
 	if (instance-&gt;firmware_loaded)
 		udsl_fire_receivers (instance);
 
 	dbg ("udsl_atm_open successful");
+
 	return 0;
 }
 
 static void udsl_atm_close (struct atm_vcc *vcc)
 {
 	struct udsl_instance_data *instance = vcc-&gt;dev-&gt;dev_data;
-	struct udsl_vcc_data *work;
+	struct udsl_vcc_data *vcc_data = vcc-&gt;dev_data;
 
 	dbg ("udsl_atm_close called");
 
-	if (!instance) {
-		dbg ("NULL instance!");
+	if (!instance || !vcc_data) {
+		dbg ("NULL data!");
 		return;
 	}
 
-	/* freeing resources */
-	/* cancel all sends on this vcc */
-	udsl_cancel_send (instance, vcc);
-
-	if (instance-&gt;vcc_list == vcc-&gt;dev_data) {
-		instance-&gt;vcc_list = instance-&gt;vcc_list-&gt;next;
-	} else {
-		for (work = instance-&gt;vcc_list; work &amp;&amp; work-&gt;next &amp;&amp; (work-&gt;next != vcc-&gt;dev_data); work = work-&gt;next);
-
-		/* return if not found */
-		if (work-&gt;next != vcc-&gt;dev_data)
-			BUG ();
+	dbg ("Deallocating SARLib vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data-&gt;vpi, vcc_data-&gt;vci);
 
-		work-&gt;next = work-&gt;next-&gt;next;
-	}
-
-	if (((struct udsl_vcc_data *)vcc-&gt;dev_data)-&gt;reasBuffer) {
-		dev_kfree_skb (((struct udsl_vcc_data *)vcc-&gt;dev_data)-&gt;reasBuffer);
-	}
+	udsl_cancel_send (instance, vcc);
 
-	dbg ("Deallocated SARLib vcc 0x%p with vpi %d vci %d", vcc-&gt;dev_data, vcc-&gt;dev_data-&gt;vpi, vcc-&gt;dev_data-&gt;vci);
+	list_del (&amp;vcc_data-&gt;list);
 
-	kfree (vcc-&gt;dev_data);
+	if (vcc_data-&gt;reasBuffer)
+		kfree_skb (vcc_data-&gt;reasBuffer);
+	vcc_data-&gt;reasBuffer = NULL;
 
+	kfree (vcc_data);
 	vcc-&gt;dev_data = NULL;
-	clear_bit (ATM_VF_PARTIAL, &amp;vcc-&gt;flags);
 
-	/* freeing address */
 	vcc-&gt;vpi = ATM_VPI_UNSPEC;
 	vcc-&gt;vci = ATM_VCI_UNSPEC;
+	clear_bit (ATM_VF_READY, &amp;vcc-&gt;flags);
+	clear_bit (ATM_VF_PARTIAL, &amp;vcc-&gt;flags);
 	clear_bit (ATM_VF_ADDR, &amp;vcc-&gt;flags);
 
 	MOD_DEC_USE_COUNT;
 
 	dbg ("udsl_atm_close successful");
-	return;
 }
 
 static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
@@ -1088,6 +1078,8 @@
 	init_MUTEX (&amp;instance-&gt;serialize);
 
 	instance-&gt;usb_dev = dev;
+
+	INIT_LIST_HEAD (&amp;instance-&gt;vcc_list);
 
 	spin_lock_init (&amp;instance-&gt;spare_receivers_lock);
 	INIT_LIST_HEAD (&amp;instance-&gt;spare_receivers);
</pre></body></html>