rpms/kernel/devel linux-2.6-orinoco-scan.patch, NONE, 1.1.2.1 kernel.spec, 1.215, 1.215.2.1

John W. Linville (linville) fedora-extras-commits at redhat.com
Thu Oct 11 18:07:26 UTC 2007


Author: linville

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv6544

Modified Files:
      Tag: private-linville-bz317691-branch
	kernel.spec 
Added Files:
      Tag: private-linville-bz317691-branch
	linux-2.6-orinoco-scan.patch 
Log Message:
Testing orinoco scanning patches from dcbw (BZ317691)

linux-2.6-orinoco-scan.patch:

--- NEW FILE linux-2.6-orinoco-scan.patch ---
diff -up linux-2.6.23.noarch/drivers/net/wireless/orinoco.c.orig linux-2.6.23.noarch/drivers/net/wireless/orinoco.c
--- linux-2.6.23.noarch/drivers/net/wireless/orinoco.c.orig	2007-10-09 16:31:38.000000000 -0400
+++ linux-2.6.23.noarch/drivers/net/wireless/orinoco.c	2007-10-11 13:46:46.000000000 -0400
@@ -270,6 +270,37 @@ static inline void set_port_type(struct 
 	}
 }
 
+#define ORINOCO_MAX_BSS_COUNT	64
+static int orinoco_bss_data_allocate(struct orinoco_private *priv)
+{
+	if (priv->bss_data)
+		return 0;
+
+	priv->bss_data =
+	    kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL);
+	if (!priv->bss_data) {
+		printk(KERN_WARNING "Out of memory allocating beacons");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void orinoco_bss_data_free(struct orinoco_private *priv)
+{
+	kfree(priv->bss_data);
+	priv->bss_data = NULL;
+}
+
+static void orinoco_bss_data_init(struct orinoco_private *priv)
+{
+	int i;
+
+	INIT_LIST_HEAD(&priv->bss_free_list);
+	INIT_LIST_HEAD(&priv->bss_list);
+	for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+		list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list);
+}
+
 /********************************************************************/
 /* Device methods                                                   */
 /********************************************************************/
@@ -1083,6 +1114,121 @@ static void orinoco_send_wevents(struct 
 	orinoco_unlock(priv, &flags);
 }
 
+
+static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
+					      unsigned long scan_age)
+{
+	bss_element *bss;
+	bss_element *tmp_bss;
+
+	/* Blow away current list of scan results */
+	list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+		if (!scan_age ||
+		    time_after(jiffies, bss->last_scanned + scan_age)) {
+			list_move_tail(&bss->list, &priv->bss_free_list);
+			/* Don't blow away ->list, just BSS data */
+			memset(bss, 0, sizeof(bss->bss));
+			bss->last_scanned = 0;
+		}
+	}
+}
+
+static int orinoco_process_scan_results(struct net_device *dev,
+					unsigned char *buf,
+					int len)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int			offset;		/* In the scan data */
+	union hermes_scan_info *atom;
+	int			atom_len;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		atom_len = sizeof(struct agere_scan_apinfo);
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Lack of documentation necessitates this hack.
+		 * Different firmwares have 68 or 76 byte long atoms.
+		 * We try modulo first.  If the length divides by both,
+		 * we check what would be the channel in the second
+		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
+		 * Valid channel cannot be 0.  */
+		if (len % 76)
+			atom_len = 68;
+		else if (len % 68)
+			atom_len = 76;
+		else if (len >= 1292 && buf[68] == 0)
+			atom_len = 76;
+		else
+			atom_len = 68;
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		offset = 4;
+		if (priv->has_hostscan) {
+			atom_len = le16_to_cpup((__le16 *)buf);
+			/* Sanity check for atom_len */
+			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+				printk(KERN_ERR "%s: Invalid atom_len in scan "
+				       "data: %d\n", dev->name, atom_len);
+				return -EIO;
+			}
+		} else
+			atom_len = offsetof(struct prism2_scan_apinfo, atim);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Check that we got an whole number of atoms */
+	if ((len - offset) % atom_len) {
+		printk(KERN_ERR "%s: Unexpected scan data length %d, "
+		       "atom_len %d, offset %d\n", dev->name, len,
+		       atom_len, offset);
+		return -EIO;
+	}
+
+	orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
+
+	/* Read the entries one by one */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		int found = 0;
+		bss_element *bss;
+
+		/* Get next atom */
+		atom = (union hermes_scan_info *) (buf + offset);
+
+		/* Try to update an existing bss first */
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
+				continue;
+			if (le16_to_cpu(bss->bss.a.essid_len) !=
+			      le16_to_cpu(atom->a.essid_len))
+				continue;
+			if (memcmp(bss->bss.a.essid, atom->a.essid,
+			      le16_to_cpu(atom->a.essid_len)))
+				continue;
+			bss->last_scanned = jiffies;
+			found = 1;
+			break;
+		}
+
+		/* Grab a bss off the free list */
+		if (!found && !list_empty(&priv->bss_free_list)) {
+			bss = list_entry(priv->bss_free_list.next,
+					 bss_element, list);
+			list_del(priv->bss_free_list.next);
+
+			memcpy(bss, atom, sizeof(bss->bss));
+			bss->last_scanned = jiffies;
+			list_add_tail(&bss->list, &priv->bss_list);
+		}
+	}
+
+	return 0;
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -1208,6 +1354,9 @@ static void __orinoco_ev_info(struct net
 		union iwreq_data	wrqu;
 		unsigned char *buf;
 
+		/* Scan is no longer in progress */
+		priv->scan_inprogress = 0;
+
 		/* Sanity check */
 		if (len > 4096) {
 			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
@@ -1215,15 +1364,6 @@ static void __orinoco_ev_info(struct net
 			break;
 		}
 
-		/* We are a strict producer. If the previous scan results
-		 * have not been consumed, we just have to drop this
-		 * frame. We can't remove the previous results ourselves,
-		 * that would be *very* racy... Jean II */
-		if (priv->scan_result != NULL) {
-			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
-			break;
-		}
-
 		/* Allocate buffer for results */
 		buf = kmalloc(len, GFP_ATOMIC);
 		if (buf == NULL)
@@ -1248,18 +1388,17 @@ static void __orinoco_ev_info(struct net
 		}
 #endif	/* ORINOCO_DEBUG */
 
-		/* Allow the clients to access the results */
-		priv->scan_len = len;
-		priv->scan_result = buf;
-
-		/* Send an empty event to user space.
-		 * We don't send the received data on the event because
-		 * it would require us to do complex transcoding, and
-		 * we want to minimise the work done in the irq handler
-		 * Use a request to extract the data - Jean II */
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+		if (orinoco_process_scan_results(dev, buf, len) == 0) {
+			/* Send an empty event to user space.
+			 * We don't send the received data on the event because
+			 * it would require us to do complex transcoding, and
+			 * we want to minimise the work done in the irq handler
+			 * Use a request to extract the data - Jean II */
+			wrqu.data.length = 0;
+			wrqu.data.flags = 0;
+			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+		}
+		kfree(buf);
 	}
 	break;
 	case HERMES_INQ_SEC_STAT_AGERE:
@@ -1896,8 +2035,7 @@ static void orinoco_reset(struct work_st
 	orinoco_unlock(priv, &flags);
 
  	/* Scanning support: Cleanup of driver struct */
-	kfree(priv->scan_result);
-	priv->scan_result = NULL;
+	orinoco_clear_scan_results(priv, 0);
 	priv->scan_inprogress = 0;
 
 	if (priv->hard_reset) {
@@ -2413,6 +2551,10 @@ struct net_device *alloc_orinocodev(int 
 	else
 		priv->card = NULL;
 
+	if (orinoco_bss_data_allocate(priv))
+		goto err_out_free;
+	orinoco_bss_data_init(priv);
+
 	/* Setup / override net_device fields */
 	dev->init = orinoco_init;
 	dev->hard_start_xmit = orinoco_xmit;
@@ -2448,13 +2590,16 @@ struct net_device *alloc_orinocodev(int 
 
 	return dev;
 
+err_out_free:
+	free_netdev(dev);
+	return NULL;
 }
 
 void free_orinocodev(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 
-	kfree(priv->scan_result);
+	orinoco_bss_data_free(priv);
 	free_netdev(dev);
 }
 
@@ -3842,23 +3987,10 @@ static int orinoco_ioctl_setscan(struct 
 	 * we access scan variables in priv is critical.
 	 *	o scan_inprogress : not touched by irq handler
 	 *	o scan_mode : not touched by irq handler
-	 *	o scan_result : irq is strict producer, non-irq is strict
-	 *		consumer.
 	 *	o scan_len : synchronised with scan_result
 	 * Before modifying anything on those variables, please think hard !
 	 * Jean II */
 
-	/* If there is still some left-over scan results, get rid of it */
-	if (priv->scan_result != NULL) {
-		/* What's likely is that a client did crash or was killed
-		 * between triggering the scan request and reading the
-		 * results, so we need to reset everything.
-		 * Some clients that are too slow may suffer from that...
-		 * Jean II */
-		kfree(priv->scan_result);
-		priv->scan_result = NULL;
-	}
-
 	/* Save flags */
 	priv->scan_mode = srq->flags;
 
@@ -3906,169 +4038,125 @@ static int orinoco_ioctl_setscan(struct 
 	return err;
 }
 
+#define MAX_CUSTOM_LEN 64
+
 /* Translate scan data returned from the card to a card independant
  * format that the Wireless Tools will understand - Jean II
  * Return message length or -errno for fatal errors */
-static inline int orinoco_translate_scan(struct net_device *dev,
-					 char *buffer,
-					 char *scan,
-					 int scan_len)
+static inline char *orinoco_translate_scan(struct net_device *dev,
+					   char *current_ev,
+					   char *end_buf,
+					   union hermes_scan_info *bss,
+					   unsigned int last_scanned)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int			offset;		/* In the scan data */
-	union hermes_scan_info *atom;
-	int			atom_len;
 	u16			capabilities;
 	u16			channel;
 	struct iw_event		iwe;		/* Temporary buffer */
-	char *			current_ev = buffer;
-	char *			end_buf = buffer + IW_SCAN_MAX_DATA;
+	char                   *p;
+	char custom[MAX_CUSTOM_LEN];
 
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		atom_len = sizeof(struct agere_scan_apinfo);
- 		offset = 0;
-		break;
-	case FIRMWARE_TYPE_SYMBOL:
-		/* Lack of documentation necessitates this hack.
-		 * Different firmwares have 68 or 76 byte long atoms.
-		 * We try modulo first.  If the length divides by both,
-		 * we check what would be the channel in the second
-		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
-		 * Valid channel cannot be 0.  */
-		if (scan_len % 76)
-			atom_len = 68;
-		else if (scan_len % 68)
-			atom_len = 76;
-		else if (scan_len >= 1292 && scan[68] == 0)
-			atom_len = 76;
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
+	if (iwe.u.data.length > 32)
+		iwe.u.data.length = 32;
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.flags = 1;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+
+	/* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	capabilities = le16_to_cpu(bss->a.capabilities);
+	if (capabilities & 0x3) {
+		if (capabilities & 0x1)
+			iwe.u.mode = IW_MODE_MASTER;
 		else
-			atom_len = 68;
-		offset = 0;
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		offset = 4;
-		if (priv->has_hostscan) {
-			atom_len = le16_to_cpup((__le16 *)scan);
-			/* Sanity check for atom_len */
-			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
-				printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
-				dev->name, atom_len);
-				return -EIO;
-			}
-		} else
-			atom_len = offsetof(struct prism2_scan_apinfo, atim);
-		break;
-	default:
-		return -EOPNOTSUPP;
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
 	}
 
-	/* Check that we got an whole number of atoms */
-	if ((scan_len - offset) % atom_len) {
-		printk(KERN_ERR "%s: Unexpected scan data length %d, "
-		       "atom_len %d, offset %d\n", dev->name, scan_len,
-		       atom_len, offset);
-		return -EIO;
-	}
-
-	/* Read the entries one by one */
-	for (; offset + atom_len <= scan_len; offset += atom_len) {
-		/* Get next atom */
-		atom = (union hermes_scan_info *) (scan + offset);
-
-		/* First entry *MUST* be the AP MAC address */
-		iwe.cmd = SIOCGIWAP;
-		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-		memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
-		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
-
-		/* Other entries will be displayed in the order we give them */
-
-		/* Add the ESSID */
-		iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
-		if (iwe.u.data.length > 32)
-			iwe.u.data.length = 32;
-		iwe.cmd = SIOCGIWESSID;
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
-
-		/* Add mode */
-		iwe.cmd = SIOCGIWMODE;
-		capabilities = le16_to_cpu(atom->a.capabilities);
-		if (capabilities & 0x3) {
-			if (capabilities & 0x1)
-				iwe.u.mode = IW_MODE_MASTER;
-			else
-				iwe.u.mode = IW_MODE_ADHOC;
-			current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
-		}
+	channel = bss->s.channel;
+	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+		/* Add frequency */
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+		iwe.u.freq.e = 1;
+		current_ev = iwe_stream_add_event(current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+	}
+
+	/* Add quality statistics */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = 0x10;	/* no link quality */
+	iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
+	iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
+	/* Wireless tools prior to 27.pre22 will show link quality
+	 * anyway, so we provide a reasonable value. */
+	if (iwe.u.qual.level > iwe.u.qual.noise)
+		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+	else
+		iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-		channel = atom->s.channel;
-		if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
-			/* Add frequency */
-			iwe.cmd = SIOCGIWFREQ;
-			iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-			iwe.u.freq.e = 1;
-			current_ev = iwe_stream_add_event(current_ev, end_buf,
-							  &iwe, IW_EV_FREQ_LEN);
-		}
-
-		/* Add quality statistics */
-		iwe.cmd = IWEVQUAL;
-		iwe.u.qual.updated = 0x10;	/* no link quality */
-		iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
-		iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
-		/* Wireless tools prior to 27.pre22 will show link quality
-		 * anyway, so we provide a reasonable value. */
-		if (iwe.u.qual.level > iwe.u.qual.noise)
-			iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-		else
-			iwe.u.qual.qual = 0;
-		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (capabilities & 0x10)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	p = custom;
+	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+		      " Last beacon: %dms ago",
+		      jiffies_to_msecs(jiffies - last_scanned));
+	iwe.u.data.length = p - custom;
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
+
+	/* Bit rate is not available in Lucent/Agere firmwares */
+	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+		char *current_val = current_ev + IW_EV_LCP_LEN;
+		int i;
+		int step;
 
-		/* Add encryption capability */
-		iwe.cmd = SIOCGIWENCODE;
-		if (capabilities & 0x10)
-			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+		if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+			step = 2;
 		else
-			iwe.u.data.flags = IW_ENCODE_DISABLED;
-		iwe.u.data.length = 0;
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
-
-		/* Bit rate is not available in Lucent/Agere firmwares */
-		if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-			char *	current_val = current_ev + IW_EV_LCP_LEN;
-			int	i;
-			int	step;
+			step = 1;
 
-			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-				step = 2;
-			else
-				step = 1;
-
-			iwe.cmd = SIOCGIWRATE;
-			/* Those two flags are ignored... */
-			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-			/* Max 10 values */
-			for (i = 0; i < 10; i += step) {
-				/* NULL terminated */
-				if (atom->p.rates[i] == 0x0)
-					break;
-				/* Bit rate given in 500 kb/s units (+ 0x80) */
-				iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
-				current_val = iwe_stream_add_value(current_ev, current_val,
-								   end_buf, &iwe,
-								   IW_EV_PARAM_LEN);
-			}
-			/* Check if we added any event */
-			if ((current_val - current_ev) > IW_EV_LCP_LEN)
-				current_ev = current_val;
-		}
-
-		/* The other data in the scan result are not really
-		 * interesting, so for now drop it - Jean II */
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+		/* Max 10 values */
+		for (i = 0; i < 10; i += step) {
+			/* NULL terminated */
+			if (bss->p.rates[i] == 0x0)
+				break;
+			/* Bit rate given in 500 kb/s units (+ 0x80) */
+			iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
+			current_val = iwe_stream_add_value(current_ev, current_val,
+							   end_buf, &iwe,
+							   IW_EV_PARAM_LEN);
+		}
+		/* Check if we added any event */
+		if ((current_val - current_ev) > IW_EV_LCP_LEN)
+			current_ev = current_val;
 	}
-	return current_ev - buffer;
+
+	return current_ev;
 }
 
 /* Return results of a scan */
@@ -4078,68 +4166,45 @@ static int orinoco_ioctl_getscan(struct 
 				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
+	bss_element *bss;
 	int err = 0;
 	unsigned long flags;
+	char *current_ev = extra;
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	/* If no results yet, ask to try again later */
-	if (priv->scan_result == NULL) {
-		if (priv->scan_inprogress)
-			/* Important note : we don't want to block the caller
-			 * until results are ready for various reasons.
-			 * First, managing wait queues is complex and racy.
-			 * Second, we grab some rtnetlink lock before comming
-			 * here (in dev_ioctl()).
-			 * Third, we generate an Wireless Event, so the
-			 * caller can wait itself on that - Jean II */
-			err = -EAGAIN;
-		else
-			/* Client error, no scan results...
-			 * The caller need to restart the scan. */
-			err = -ENODATA;
-	} else {
-		/* We have some results to push back to user space */
-
-		/* Translate to WE format */
-		int ret = orinoco_translate_scan(dev, extra,
-						 priv->scan_result,
-						 priv->scan_len);
-
-		if (ret < 0) {
-			err = ret;
-			kfree(priv->scan_result);
-			priv->scan_result = NULL;
-		} else {
-			srq->length = ret;
-
-			/* Return flags */
-			srq->flags = (__u16) priv->scan_mode;
-
-			/* In any case, Scan results will be cleaned up in the
-			 * reset function and when exiting the driver.
-			 * The person triggering the scanning may never come to
-			 * pick the results, so we need to do it in those places.
-			 * Jean II */
+	if (priv->scan_inprogress) {
+		/* Important note : we don't want to block the caller
+		 * until results are ready for various reasons.
+		 * First, managing wait queues is complex and racy.
+		 * Second, we grab some rtnetlink lock before comming
+		 * here (in dev_ioctl()).
+		 * Third, we generate an Wireless Event, so the
+		 * caller can wait itself on that - Jean II */
+		err = -EAGAIN;
+		goto out;
+	}
 
-#ifdef SCAN_SINGLE_READ
-			/* If you enable this option, only one client (the first
-			 * one) will be able to read the result (and only one
-			 * time). If there is multiple concurent clients that
-			 * want to read scan results, this behavior is not
-			 * advisable - Jean II */
-			kfree(priv->scan_result);
-			priv->scan_result = NULL;
-#endif /* SCAN_SINGLE_READ */
-			/* Here, if too much time has elapsed since last scan,
-			 * we may want to clean up scan results... - Jean II */
+	list_for_each_entry(bss, &priv->bss_list, list) {
+		/* Translate to WE format this entry */
+		current_ev = orinoco_translate_scan(dev, current_ev,
+						    extra + srq->length,
+						    &bss->bss,
+						    bss->last_scanned);
+
+		/* Check if there is space for one more entry */
+		if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) {
+			/* Ask user space to try again with a bigger buffer */
+			err = -E2BIG;
+			goto out;
 		}
-
-		/* Scan is no longer in progress */
-		priv->scan_inprogress = 0;
 	}
-	  
+
+	srq->length = (current_ev - extra);
+	srq->flags = (__u16) priv->scan_mode;
+
+out:
 	orinoco_unlock(priv, &flags);
 	return err;
 }
diff -up linux-2.6.23.noarch/drivers/net/wireless/orinoco.h.orig linux-2.6.23.noarch/drivers/net/wireless/orinoco.h
--- linux-2.6.23.noarch/drivers/net/wireless/orinoco.h.orig	2007-10-09 16:31:38.000000000 -0400
+++ linux-2.6.23.noarch/drivers/net/wireless/orinoco.h	2007-10-11 13:46:46.000000000 -0400
@@ -36,6 +36,12 @@ typedef enum {
 	FIRMWARE_TYPE_SYMBOL
 } fwtype_t;
 
+typedef struct {
+	union hermes_scan_info bss;
+	unsigned long last_scanned;
+	struct list_head list;
+} bss_element;
+
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
 	int (*hard_reset)(struct orinoco_private *);
@@ -105,10 +111,12 @@ struct orinoco_private {
 	int promiscuous, mc_count;
 
 	/* Scanning support */
+	struct list_head bss_list;
+	struct list_head bss_free_list;
+	bss_element *bss_data;
+
 	int	scan_inprogress;	/* Scan pending... */
 	u32	scan_mode;		/* Type of scan done */
-	char *	scan_result;		/* Result of previous scan */
-	int	scan_len;		/* Lenght of result */
 };
 
 #ifdef ORINOCO_DEBUG


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.215
retrieving revision 1.215.2.1
diff -u -r1.215 -r1.215.2.1
--- kernel.spec	11 Oct 2007 17:18:58 -0000	1.215
+++ kernel.spec	11 Oct 2007 18:06:53 -0000	1.215.2.1
@@ -13,6 +13,7 @@
 # by setting the define to ".local" or ".bz123456"
 #
 #% define buildid .local
+%define buildid .bz317691.1
 
 # fedora_build defines which build revision of this kernel version we're
 # building. Rather than incrementing forever, as with the prior versioning
@@ -625,6 +626,7 @@
 Patch680: linux-2.6-wireless.patch
 Patch682: linux-2.6-iwlwifi-fixes.patch
 Patch683: linux-2.6-mac80211-nm-hidden-ssid.patch
+Patch684: linux-2.6-orinoco-scan.patch
 Patch690: linux-2.6-at76.patch
 Patch691: linux-2.6-ath5k.patch
 Patch692: linux-2.6-zd1211rw-mac80211.patch
@@ -1146,6 +1148,9 @@
 ApplyPatch linux-2.6-zd1211rw-mac80211.patch
 ApplyPatch linux-2.6-mac80211-extras.patch
 
+# orinico scanning fixes
+ApplyPatch linux-2.6-orinoco-scan.patch
+
 # avoid bcm3xx vs bcm43xx-mac80211 PCI ID conflicts
 ApplyPatch linux-2.6-bcm43xx-pci-neuter.patch
 
@@ -1813,6 +1818,9 @@
 
 
 %changelog
+* Wed Oct 11 2007 John W. Linville <linville at redhat.com>
+- Testing orinoco scanning patches from dcbw (BZ317691)
+
 * Thu Oct 11 2007 Dave Jones <davej at redhat.com>
 - Fix race in e100 driver.
 




More information about the fedora-extras-commits mailing list