prism2_rx (hostap_hw.c) patch

Lubomir Gelo lgelo
Tue Jun 17 02:47:12 PDT 2003


Hostap 0.0.3 introduced bug in prism2_rx (hostap_hw.c) in calculating
size for dev_alloc_skb. Driver hangs in monitor mode if frame of
certain length is received. Verified with gcc-2.95 and gcc-3.3 and
secondary FW 1.4.9 and 1.5.6. 

Simple cast to u16 should help, but patch for cleaner (IMHO) 
implementation follows. 

LG
-------------- next part --------------
--- hostap_hw.c.orig	2003-05-23 04:40:58.000000000 +0200
+++ hostap_hw.c	2003-06-17 11:20:25.000000000 +0200
@@ -2129,7 +2129,7 @@
 {
 	struct net_device *dev = local->dev;
 	int res, rx_pending = 0;
-	u16 len, alloc_len, rxfid, status, macport;
+	u16 data_len, hdr_len, rxfid, status, macport;
 	struct net_device_stats *stats;
 	struct hfa384x_rx_frame rxdesc;
 	struct sk_buff *skb = NULL;
@@ -2163,7 +2163,8 @@
 		goto rx_dropped;
 	}
 
-	len = le16_to_cpu(rxdesc.data_len);
+	data_len = le16_to_cpu(rxdesc.data_len);
+	hdr_len = sizeof(rxdesc);
 	status = le16_to_cpu(rxdesc.status);
 	macport = (status >> 8) & 0x07;
 
@@ -2171,17 +2172,20 @@
 	 * seems to sometimes pass frames (e.g., ctrl::ack) with signed and
 	 * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
 	 * macport 7 */
-	if ((len & 0x8000) &&
-	    (macport != 7 || ((len < (u16) -14) && len != 0xffff))) {
+	if (data_len > 2312){
+	    if (macport == 7 && (data_len >= (u16) -14) && data_len != 0xffff ) {
+		data_len = 0;
+		hdr_len = data_len+(u16)sizeof(rxdesc);
+	    } else {
 		spin_unlock(&local->baplock);
 		printk(KERN_DEBUG "%s: Received frame with invalid length "
-		       "0x%04x\n", dev->name, len);
+		       "0x%04x\n", dev->name, data_len);
 		hostap_dump_rx_header(dev->name, &rxdesc);
 		goto rx_dropped;
+	    }	
 	}
 
-	alloc_len = len + sizeof(rxdesc);
-	skb = dev_alloc_skb(alloc_len);
+	skb = dev_alloc_skb(hdr_len+data_len);
 	if (!skb) {
 		spin_unlock(&local->baplock);
 		printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
@@ -2189,11 +2193,10 @@
 		goto rx_dropped;
 	}
 	skb->dev = dev;
-	memcpy(skb_put(skb, sizeof(rxdesc)), &rxdesc,
-	       alloc_len < sizeof(rxdesc) ? alloc_len : sizeof(rxdesc));
+	memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);
 
 #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER)
-	if (!(len & 0x8000) && len >= local->bus_master_threshold_rx) {
+	if (data_len && data_len >= local->bus_master_threshold_rx) {
 		unsigned long addr;
 
 		hfa384x_events_no_bap1(dev);
@@ -2201,13 +2204,13 @@
 		local->rx_skb = skb;
 		/* Internal BAP0 offset points to the byte following rxdesc;
 		 * copy rest of the data using bus master */
-		addr = virt_to_phys(skb_put(skb, len));
+		addr = virt_to_phys(skb_put(skb, data_len));
 		HFA384X_OUTW((addr & 0xffff0000) >> 16,
 			     HFA384X_PCI_M0_ADDRH_OFF);
 		HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF);
-		if (len & 1)
-			len++;
-		HFA384X_OUTW(len / 2, HFA384X_PCI_M0_LEN_OFF);
+		if (data_len & 1)
+			data_len++;
+		HFA384X_OUTW(data_len / 2, HFA384X_PCI_M0_LEN_OFF);
 		HFA384X_OUTW(HFA384X_PCI_CTL_FROM_BAP, HFA384X_PCI_M0_CTL_OFF);
 
 		/* pci_bus_m1 event will be generated when data transfer is
@@ -2222,9 +2225,8 @@
 	} else
 #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */
 	{
-		if (!(len & 0x8000))
-			res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len),
-					       len);
+		if (data_len)
+		    res = hfa384x_from_bap(dev, BAP0, skb_put(skb, data_len), data_len);
 		spin_unlock(&local->baplock);
 		if (res) {
 			printk(KERN_DEBUG "%s: RX failed to read "



More information about the Hostap mailing list