All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libertas: implement new scanning logic
@ 2007-11-29  8:27 Holger Schurig
  2007-11-29 19:38 ` Dan Williams
  2007-12-04 16:52 ` Dan Williams
  0 siblings, 2 replies; 14+ messages in thread
From: Holger Schurig @ 2007-11-29  8:27 UTC (permalink / raw)
  To: John W. Linville; +Cc: libertas-dev, linux-wireless, Dan Williams

This changes the code that is used for scanning and makes it hopefully
easier to understand:

* move function into logical blocks
* create a bunch of lbs_scan_add_XXXX_tlv() functions, that
  help to create the TLV parameter of CMD_802_11_SCAN
* all of them are now called from the much simpler lbs_do_scan()
* no **puserscancfg double-pointers :-)

Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>


Index: wireless-2.6/drivers/net/wireless/libertas/scan.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/libertas/scan.c	2007-11-29 10:01:07.000000000 +0100
+++ wireless-2.6/drivers/net/wireless/libertas/scan.c	2007-11-29 10:26:07.000000000 +0100
@@ -79,6 +79,22 @@ static inline void clear_bss_descriptor 
 	memset(bss, 0, offsetof(struct bss_descriptor, list));
 }
 
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0: ssid is same, otherwise is different
+ */
+int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+{
+	if (ssid1_len != ssid2_len)
+		return -1;
+
+	return memcmp(ssid1, ssid2, ssid1_len);
+}
+
 static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
@@ -149,6 +165,18 @@ static inline int match_bss_dynamic_wep(
 	return 0;
 }
 
+static inline int is_same_network(struct bss_descriptor *src,
+				  struct bss_descriptor *dst)
+{
+	/* A network is only a duplicate if the channel, BSSID, and ESSID
+	 * all match.  We treat all <hidden> with the same BSSID and channel
+	 * as one network */
+	return ((src->ssid_len == dst->ssid_len) &&
+		(src->channel == dst->channel) &&
+		!compare_ether_addr(src->bssid, dst->bssid) &&
+		!memcmp(src->ssid, dst->ssid, src->ssid_len));
+}
+
 /**
  *  @brief Check if a scanned network compatible with the driver settings
  *
@@ -184,9 +212,9 @@ static int is_network_compatible(struct 
 		goto done;
 	} else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) {
 		lbs_deb_scan(
-		       "is_network_compatible() WPA: wpa_ie=%#x "
-		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+		       "is_network_compatible() WPA: wpa_ie 0x%x "
+		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
 		       adapter->secinfo.wep_enabled ? "e" : "d",
 		       adapter->secinfo.WPAenabled ? "e" : "d",
 		       adapter->secinfo.WPA2enabled ? "e" : "d",
@@ -194,9 +222,9 @@ static int is_network_compatible(struct 
 		goto done;
 	} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
 		lbs_deb_scan(
-		       "is_network_compatible() WPA2: wpa_ie=%#x "
-		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+		       "is_network_compatible() WPA2: wpa_ie 0x%x "
+		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
 		       adapter->secinfo.wep_enabled ? "e" : "d",
 		       adapter->secinfo.WPAenabled ? "e" : "d",
 		       adapter->secinfo.WPA2enabled ? "e" : "d",
@@ -205,7 +233,7 @@ static int is_network_compatible(struct 
 	} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
 		lbs_deb_scan(
 		       "is_network_compatible() dynamic WEP: "
-		       "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
+		       "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
 		       bss->wpa_ie[0], bss->rsn_ie[0],
 		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
@@ -213,8 +241,8 @@ static int is_network_compatible(struct 
 
 	/* bss security settings don't match those configured on card */
 	lbs_deb_scan(
-	       "is_network_compatible() FAILED: wpa_ie=%#x "
-	       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n",
+	       "is_network_compatible() FAILED: wpa_ie 0x%x "
+	       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
 	       bss->wpa_ie[0], bss->rsn_ie[0],
 	       adapter->secinfo.wep_enabled ? "e" : "d",
 	       adapter->secinfo.WPAenabled ? "e" : "d",
@@ -226,22 +254,6 @@ done:
 	return matched;
 }
 
-/**
- *  @brief Compare two SSIDs
- *
- *  @param ssid1    A pointer to ssid to compare
- *  @param ssid2    A pointer to ssid to compare
- *
- *  @return         0--ssid is same, otherwise is different
- */
-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
-{
-	if (ssid1_len != ssid2_len)
-		return -1;
-
-	return memcmp(ssid1, ssid2, ssid1_len);
-}
-
 
 
 
@@ -251,6 +263,16 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
 /*                                                                   */
 /*********************************************************************/
 
+void lbs_scan_worker(struct work_struct *work)
+{
+	struct lbs_private *priv =
+		container_of(work, struct lbs_private, scan_work.work);
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+	lbs_scan_networks(priv, NULL, 0);
+	lbs_deb_leave(LBS_DEB_SCAN);
+}
+
 
 /**
  *  @brief Create a channel list for the driver to scan based on region info
@@ -271,7 +293,7 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
  *
  *  @return              void
  */
-static void lbs_scan_create_channel_list(struct lbs_private *priv,
+static int lbs_scan_create_channel_list(struct lbs_private *priv,
 					  struct chanscanparamset * scanchanlist,
 					  u8 filteredscan)
 {
@@ -284,8 +306,6 @@ static void lbs_scan_create_channel_list
 	int nextchan;
 	u8 scantype;
 
-	lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
-
 	chanidx = 0;
 
 	/* Set the default scan type to the user specified type, will later
@@ -352,383 +372,147 @@ static void lbs_scan_create_channel_list
 			}
 		}
 	}
+	return chanidx;
 }
 
 
-/* Delayed partial scan worker */
-void lbs_scan_worker(struct work_struct *work)
+/*
+ * Add SSID TLV of the form:
+ *
+ * TLV-ID SSID     00 00
+ * length          06 00
+ * ssid            4d 4e 54 45 53 54
+ */
+static int lbs_scan_add_ssid_tlv(u8 *tlv,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg)
 {
-	struct lbs_private *priv = container_of(work,
-		struct lbs_private,
-		scan_work.work);
-
-	lbs_scan_networks(priv, NULL, 0);
+	struct mrvlietypes_ssidparamset *ssid_tlv =
+		(struct mrvlietypes_ssidparamset *)tlv;
+	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+	ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
+	memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
+	return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
 }
 
 
-/**
- *  @brief Construct a lbs_scan_cmd_config structure to use in issue scan cmds
- *
- *  Application layer or other functions can invoke lbs_scan_networks
- *    with a scan configuration supplied in a lbs_ioctl_user_scan_cfg struct.
- *    This structure is used as the basis of one or many lbs_scan_cmd_config
- *    commands that are sent to the command processing module and sent to
- *    firmware.
- *
- *  Create a lbs_scan_cmd_config based on the following user supplied
- *    parameters (if present):
- *             - SSID filter
- *             - BSSID filter
- *             - Number of Probes to be sent
- *             - channel list
- *
- *  If the SSID or BSSID filter is not present, disable/clear the filter.
- *  Qualify the channel
+/*
+ * Add CHANLIST TLV of the form
  *
- *  @param priv             A pointer to struct lbs_private structure
- *  @param puserscanin      NULL or pointer to scan configuration parameters
- *  @param ppchantlvout     Output parameter: Pointer to the start of the
- *                          channel TLV portion of the output scan config
- *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
- *                          list to scan
- *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
- *                          each issuance of the firmware scan command
- *  @param pfilteredscan    Output parameter: Flag indicating whether or not
- *                          a BSSID or SSID filter is being sent in the
- *                          command to firmware.  Used to increase the number
- *                          of channels sent in a scan command and to
- *                          disable the firmware channel scan filter.
- *  @param pscancurrentonly Output parameter: Flag indicating whether or not
- *                          we are only scanning our current active channel
+ * TLV-ID CHANLIST 01 01
+ * length          5b 00
+ * channel 1       00 01 00 00 00 64 00
+ *   radio type    00
+ *   channel          01
+ *   scan type           00
+ *   min scan time          00 00
+ *   max scan time                64 00
+ * channel 2       00 02 00 00 00 64 00
+ * channel 3       00 03 00 00 00 64 00
+ * channel 4       00 04 00 00 00 64 00
+ * channel 5       00 05 00 00 00 64 00
+ * channel 6       00 06 00 00 00 64 00
+ * channel 7       00 07 00 00 00 64 00
+ * channel 8       00 08 00 00 00 64 00
+ * channel 9       00 09 00 00 00 64 00
+ * channel 10      00 0a 00 00 00 64 00
+ * channel 11      00 0b 00 00 00 64 00
+ * channel 12      00 0c 00 00 00 64 00
+ * channel 13      00 0d 00 00 00 64 00
  *
- *  @return                 resulting scan configuration
  */
-static struct lbs_scan_cmd_config *
-lbs_scan_setup_scan_config(struct lbs_private *priv,
-			    const struct lbs_ioctl_user_scan_cfg *puserscanin,
-			    struct mrvlietypes_chanlistparamset ** ppchantlvout,
-			    struct chanscanparamset * pscanchanlist,
-			    int *pmaxchanperscan,
-			    u8 * pfilteredscan,
-			    u8 * pscancurrentonly)
+static int lbs_scan_add_chanlist_tlv(u8 *tlv,
+	struct chanscanparamset *chan_list,
+	int chan_count)
 {
-	struct mrvlietypes_ssidparamset *pssidtlv;
-	struct lbs_scan_cmd_config *pscancfgout = NULL;
-	u8 *ptlvpos;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
-	if (pscancfgout == NULL)
-		goto out;
-
-	/* The tlvbufferlen is calculated for each scan command.  The TLVs added
-	 *   in this routine will be preserved since the routine that sends
-	 *   the command will append channelTLVs at *ppchantlvout.  The difference
-	 *   between the *ppchantlvout and the tlvbuffer start will be used
-	 *   to calculate the size of anything we add in this routine.
-	 */
-	pscancfgout->tlvbufferlen = 0;
-
-	/* Running tlv pointer.  Assigned to ppchantlvout at end of function
-	 *  so later routines know where channels can be added to the command buf
-	 */
-	ptlvpos = pscancfgout->tlvbuffer;
-
-	/*
-	 * Set the initial scan paramters for progressive scanning.  If a specific
-	 *   BSSID or SSID is used, the number of channels in the scan command
-	 *   will be increased to the absolute maximum
-	 */
-	*pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
-
-	/* Initialize the scan as un-filtered by firmware, set to TRUE below if
-	 *   a SSID or BSSID filter is sent in the command
-	 */
-	*pfilteredscan = 0;
-
-	/* Initialize the scan as not being only on the current channel.  If
-	 *   the channel list is customized, only contains one channel, and
-	 *   is the active channel, this is set true and data flow is not halted.
-	 */
-	*pscancurrentonly = 0;
-
-	if (puserscanin) {
-		/* Set the bss type scan filter, use adapter setting if unset */
-		pscancfgout->bsstype =
-		    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
-
-		/*
-		 * Set the BSSID filter to the incoming configuration,
-		 *   if non-zero.  If not set, it will remain disabled (all zeros).
-		 */
-		memcpy(pscancfgout->bssid, puserscanin->bssid,
-		       sizeof(pscancfgout->bssid));
-
-		if (puserscanin->ssid_len) {
-			pssidtlv =
-			    (struct mrvlietypes_ssidparamset *) pscancfgout->
-			    tlvbuffer;
-			pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
-			pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
-			memcpy(pssidtlv->ssid, puserscanin->ssid,
-			       puserscanin->ssid_len);
-			ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
-		}
-
-		/*
-		 *  The default number of channels sent in the command is low to
-		 *    ensure the response buffer from the firmware does not truncate
-		 *    scan results.  That is not an issue with an SSID or BSSID
-		 *    filter applied to the scan results in the firmware.
-		 */
-		if (   puserscanin->ssid_len
-		    || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
-			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
-			*pfilteredscan = 1;
-		}
-	} else {
-		pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
-	}
-
-	/*
-	 * Set the output for the channel TLV to the address in the tlv buffer
-	 *   past any TLVs that were added in this fuction (SSID).
-	 *   channel TLVs will be added past this for each scan command, preserving
-	 *   the TLVs that were previously added.
-	 */
-	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+	size_t size = sizeof(struct chanscanparamset) * chan_count;
+	struct mrvlietypes_chanlistparamset *chan_tlv =
+		(struct mrvlietypes_chanlistparamset *) tlv;
 
-	lbs_scan_create_channel_list(priv, pscanchanlist,
-				      *pfilteredscan);
-out:
-	return pscancfgout;
+	chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+	memcpy(chan_tlv->chanscanparam, chan_list, size);
+	chan_tlv->header.len = cpu_to_le16(size);
+	return sizeof(chan_tlv->header) + size;
 }
 
-/**
- *  @brief Construct and send multiple scan config commands to the firmware
- *
- *  Only used from lbs_scan_networks()
- *
- *  Previous routines have created a lbs_scan_cmd_config with any requested
- *   TLVs.  This function splits the channel TLV into maxchanperscan lists
- *   and sends the portion of the channel TLV along with the other TLVs
- *   to the lbs_cmd routines for execution in the firmware.
+
+/*
+ * Add RATES TLV of the form
  *
- *  @param priv            A pointer to struct lbs_private structure
- *  @param maxchanperscan  Maximum number channels to be included in each
- *                         scan command sent to firmware
- *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
- *                         filter is being used for the firmware command
- *                         scan command sent to firmware
- *  @param pscancfgout     Scan configuration used for this scan.
- *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
- *                         should start.  This is past any other TLVs that
- *                         must be sent down in each firmware command.
- *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
+ * TLV-ID RATES    01 00
+ * length          0e 00
+ * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
  *
- *  @return                0 or error return otherwise
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit isn't set.
  */
-static int lbs_scan_channel_list(struct lbs_private *priv,
-				  int maxchanperscan,
-				  u8 filteredscan,
-				  struct lbs_scan_cmd_config *pscancfgout,
-				  struct mrvlietypes_chanlistparamset * pchantlvout,
-				  struct chanscanparamset * pscanchanlist,
-				  const struct lbs_ioctl_user_scan_cfg *puserscanin,
-				  int full_scan)
+static int lbs_scan_add_rates_tlv(u8 *tlv)
 {
-	struct chanscanparamset *ptmpchan;
-	struct chanscanparamset *pstartchan;
-	u8 scanband;
-	int doneearly;
-	int tlvidx;
-	int ret = 0;
-	int scanned = 0;
-	union iwreq_data wrqu;
-
-	lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
-		"full_scan %d", maxchanperscan, filteredscan, full_scan);
-
-	if (!pscancfgout || !pchantlvout || !pscanchanlist) {
-		lbs_deb_scan("pscancfgout, pchantlvout or "
-			"pscanchanlist is NULL\n");
-		ret = -1;
-		goto out;
-	}
-
-	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
-
-	/* Set the temp channel struct pointer to the start of the desired list */
-	ptmpchan = pscanchanlist;
-
-	if (priv->adapter->last_scanned_channel && !puserscanin)
-		ptmpchan += priv->adapter->last_scanned_channel;
-
-	/* Loop through the desired channel list, sending a new firmware scan
-	 *   commands for each maxchanperscan channels (or for 1,6,11 individually
-	 *   if configured accordingly)
-	 */
-	while (ptmpchan->channumber) {
-
-		tlvidx = 0;
-		pchantlvout->header.len = 0;
-		scanband = ptmpchan->radiotype;
-		pstartchan = ptmpchan;
-		doneearly = 0;
-
-		/* Construct the channel TLV for the scan command.  Continue to
-		 *  insert channel TLVs until:
-		 *    - the tlvidx hits the maximum configured per scan command
-		 *    - the next channel to insert is 0 (end of desired channel list)
-		 *    - doneearly is set (controlling individual scanning of 1,6,11)
-		 */
-		while (tlvidx < maxchanperscan && ptmpchan->channumber
-		       && !doneearly && scanned < 2) {
-
-			lbs_deb_scan("channel %d, radio %d, passive %d, "
-				"dischanflt %d, maxscantime %d\n",
-				ptmpchan->channumber,
-				ptmpchan->radiotype,
-			             ptmpchan->chanscanmode.passivescan,
-			             ptmpchan->chanscanmode.disablechanfilt,
-			             ptmpchan->maxscantime);
-
-			/* Copy the current channel TLV to the command being prepared */
-			memcpy(pchantlvout->chanscanparam + tlvidx,
-			       ptmpchan, sizeof(pchantlvout->chanscanparam));
-
-			/* Increment the TLV header length by the size appended */
-			/* Ew, it would be _so_ nice if we could just declare the
-			   variable little-endian and let GCC handle it for us */
-			pchantlvout->header.len =
-				cpu_to_le16(le16_to_cpu(pchantlvout->header.len) +
-					    sizeof(pchantlvout->chanscanparam));
-
-			/*
-			 *  The tlv buffer length is set to the number of bytes of the
-			 *    between the channel tlv pointer and the start of the
-			 *    tlv buffer.  This compensates for any TLVs that were appended
-			 *    before the channel list.
-			 */
-			pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
-						     - pscancfgout->tlvbuffer);
-
-			/*  Add the size of the channel tlv header and the data length */
-			pscancfgout->tlvbufferlen +=
-			    (sizeof(pchantlvout->header)
-			     + le16_to_cpu(pchantlvout->header.len));
-
-			/* Increment the index to the channel tlv we are constructing */
-			tlvidx++;
-
-			doneearly = 0;
-
-			/* Stop the loop if the *current* channel is in the 1,6,11 set
-			 *   and we are not filtering on a BSSID or SSID.
-			 */
-			if (!filteredscan && (ptmpchan->channumber == 1
-					      || ptmpchan->channumber == 6
-					      || ptmpchan->channumber == 11)) {
-				doneearly = 1;
-			}
-
-			/* Increment the tmp pointer to the next channel to be scanned */
-			ptmpchan++;
-			scanned++;
-
-			/* Stop the loop if the *next* channel is in the 1,6,11 set.
-			 *  This will cause it to be the only channel scanned on the next
-			 *  interation
-			 */
-			if (!filteredscan && (ptmpchan->channumber == 1
-					      || ptmpchan->channumber == 6
-					      || ptmpchan->channumber == 11)) {
-				doneearly = 1;
-			}
-		}
-
-		/* Send the scan command to the firmware with the specified cfg */
-		ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
-					    0, 0, pscancfgout);
-		if (scanned >= 2 && !full_scan) {
-			ret = 0;
-			goto done;
-		}
-		scanned = 0;
-	}
-
-done:
-	priv->adapter->last_scanned_channel = ptmpchan->channumber;
+	int i;
+	struct mrvlietypes_ratesparamset *rate_tlv =
+		(struct mrvlietypes_ratesparamset *) tlv;
 
-	if (priv->adapter->last_scanned_channel) {
-		/* Schedule the next part of the partial scan */
-		if (!full_scan && !priv->adapter->surpriseremoved) {
-			cancel_delayed_work(&priv->scan_work);
-			queue_delayed_work(priv->work_thread, &priv->scan_work,
-			                   msecs_to_jiffies(300));
-		}
-	} else {
-		/* All done, tell userspace the scan table has been updated */
-		memset(&wrqu, 0, sizeof(union iwreq_data));
-		wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+	tlv += sizeof(rate_tlv->header);
+	for (i = 0; i < MAX_RATES; i++) {
+		*tlv = lbs_bg_rates[i];
+		if (*tlv == 0)
+			break;
+		if (*tlv == 0x02 || *tlv == 0x04 ||
+		    *tlv == 0x0b || *tlv == 0x16)
+			*tlv |= 0x80;
+		tlv++;
 	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
+	rate_tlv->header.len = i;
+	return sizeof(rate_tlv->header) + i;
 }
 
+
 /*
- * Only used from lbs_scan_networks()
-*/
-static void clear_selected_scan_list_entries(struct lbs_adapter *adapter,
-	const struct lbs_ioctl_user_scan_cfg *scan_cfg)
+ * Generate the CMD_802_11_SCAN command with the proper tlv
+ * for a bunch of channels.
+ */
+static int lbs_do_scan(struct lbs_private *priv,
+	u8 bsstype,
+	struct chanscanparamset *chan_list,
+	int chan_count,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg)
 {
-	struct bss_descriptor *bss;
-	struct bss_descriptor *safe;
-	u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (!scan_cfg)
-		goto out;
-
-	if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
-		clear_ssid_flag = 1;
+	int ret = -ENOMEM;
+	struct lbs_scan_cmd_config *scan_cmd;
+	u8 *tlv;    /* pointer into our current, growing TLV storage area */
 
-	if (scan_cfg->clear_bssid
-	    && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0)
-	    && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) {
-		clear_bssid_flag = 1;
-	}
+	lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
+		"chan_count %d",
+		bsstype, chan_list[0].channumber, chan_count);
 
-	if (!clear_ssid_flag && !clear_bssid_flag)
+	/* create the fixed part for scan command */
+	scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+	if (scan_cmd == NULL)
 		goto out;
+	tlv = scan_cmd->tlvbuffer;
+	if (user_cfg)
+		memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
+	scan_cmd->bsstype = bsstype;
 
-	mutex_lock(&adapter->lock);
-	list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
-		u32 clear = 0;
-
-		/* Check for an SSID match */
-		if (   clear_ssid_flag
-		    && (bss->ssid_len == scan_cfg->ssid_len)
-		    && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len))
-			clear = 1;
+	/* add TLVs */
+	if (user_cfg && user_cfg->ssid_len)
+		tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
+	if (chan_list && chan_count)
+		tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
+	tlv += lbs_scan_add_rates_tlv(tlv);
 
-		/* Check for a BSSID match */
-		if (   clear_bssid_flag
-		    && !compare_ether_addr(bss->bssid, scan_cfg->bssid))
-			clear = 1;
+	/* This is the final data we are about to send */
+	scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+		scan_cmd->tlvbufferlen);
 
-		if (clear) {
-			list_move_tail (&bss->list, &adapter->network_free_list);
-			clear_bss_descriptor(bss);
-		}
-	}
-	mutex_unlock(&adapter->lock);
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
+		CMD_OPTION_WAITFORRSP, 0, scan_cmd);
 out:
-	lbs_deb_leave(LBS_DEB_SCAN);
+	kfree(scan_cmd);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+	return ret;
 }
 
 
@@ -744,29 +528,30 @@ out:
  *  @param priv          A pointer to struct lbs_private structure
  *  @param puserscanin   Pointer to the input configuration for the requested
  *                       scan.
- *  @param full_scan     ???
  *
  *  @return              0 or < 0 if error
  */
 int lbs_scan_networks(struct lbs_private *priv,
-	const struct lbs_ioctl_user_scan_cfg *puserscanin,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg,
                        int full_scan)
 {
 	struct lbs_adapter *adapter = priv->adapter;
-	struct mrvlietypes_chanlistparamset *pchantlvout;
-	struct chanscanparamset * scan_chan_list = NULL;
-	struct lbs_scan_cmd_config *scan_cfg = NULL;
-	u8 filteredscan;
-	u8 scancurrentchanonly;
-	int maxchanperscan;
-	int ret;
+	int ret = -ENOMEM;
+	struct chanscanparamset *chan_list;
+	struct chanscanparamset *curr_chans;
+	int chan_count;
+	u8 bsstype = CMD_BSS_TYPE_ANY;
+	int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
+	int filteredscan = 0;
+	union iwreq_data wrqu;
 #ifdef CONFIG_LIBERTAS_DEBUG
-	struct bss_descriptor * iter_bss;
+	struct bss_descriptor *iter;
 	int i = 0;
 	DECLARE_MAC_BUF(mac);
 #endif
 
-	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
+		full_scan);
 
 	/* Cancel any partial outstanding partial scans if this scan
 	 * is a full scan.
@@ -774,84 +559,122 @@ int lbs_scan_networks(struct lbs_private
 	if (full_scan && delayed_work_pending(&priv->scan_work))
 		cancel_delayed_work(&priv->scan_work);
 
-	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
-				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
-	if (scan_chan_list == NULL) {
-		ret = -ENOMEM;
-		goto out;
+	/* Determine same scan parameters */
+	if (user_cfg) {
+		if (user_cfg->bsstype)
+			bsstype = user_cfg->bsstype;
+		if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
+			numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
+			filteredscan = 1;
+		}
 	}
+	lbs_deb_scan("numchannels %d, bsstype %d, "
+		"filteredscan %d\n",
+		numchannels, bsstype, filteredscan);
 
-	scan_cfg = lbs_scan_setup_scan_config(priv,
-					       puserscanin,
-					       &pchantlvout,
-					       scan_chan_list,
-					       &maxchanperscan,
-					       &filteredscan,
-					       &scancurrentchanonly);
-	if (scan_cfg == NULL) {
-		ret = -ENOMEM;
+	/* Create list of channels to scan */
+	chan_list = kzalloc(sizeof(struct chanscanparamset) *
+				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+	if (!chan_list) {
+		lbs_pr_alert("SCAN: chan_list empty\n");
 		goto out;
 	}
 
-	clear_selected_scan_list_entries(adapter, puserscanin);
+	/* We want to scan all channels */
+	chan_count = lbs_scan_create_channel_list(priv, chan_list,
+		filteredscan);
 
-	/* Keep the data path active if we are only scanning our current channel */
-	if (!scancurrentchanonly) {
-		netif_stop_queue(priv->dev);
-		netif_carrier_off(priv->dev);
-		if (priv->mesh_dev) {
+	netif_stop_queue(priv->dev);
+	if (priv->mesh_dev)
 			netif_stop_queue(priv->mesh_dev);
-			netif_carrier_off(priv->mesh_dev);
-		}
+
+	/* Prepare to continue an interrupted scan */
+	lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
+		chan_count, adapter->last_scanned_channel);
+	curr_chans = chan_list;
+	/* advance channel list by already-scanned-channels */
+	if (adapter->last_scanned_channel > 0) {
+		curr_chans += adapter->last_scanned_channel;
+		chan_count -= adapter->last_scanned_channel;
 	}
 
-	ret = lbs_scan_channel_list(priv,
-				     maxchanperscan,
-				     filteredscan,
-				     scan_cfg,
-				     pchantlvout,
-				     scan_chan_list,
-				     puserscanin,
-				     full_scan);
+	/* Send scan command(s)
+	 * numchannels contains the number of channels we should maximally scan
+	 * chan_count is the total number of channels to scan
+	 */
+
+	while (chan_count) {
+		int to_scan = min(numchannels, chan_count);
+		lbs_deb_scan("scanning %d of %d channels\n",
+			to_scan, chan_count);
+		ret = lbs_do_scan(priv, bsstype, curr_chans,
+			to_scan, user_cfg);
+		if (ret) {
+			lbs_pr_err("SCAN_CMD failed\n");
+			goto out2;
+		}
+		curr_chans += to_scan;
+		chan_count -= to_scan;
+
+		/* somehow schedule the next part of the scan */
+		if (chan_count &&
+		    !full_scan &&
+		    !priv->adapter->surpriseremoved) {
+			/* -1 marks just that we're currently scanning */
+			if (adapter->last_scanned_channel < 0)
+				adapter->last_scanned_channel = to_scan;
+			else
+				adapter->last_scanned_channel += to_scan;
+			cancel_delayed_work(&priv->scan_work);
+			queue_delayed_work(priv->work_thread, &priv->scan_work,
+				msecs_to_jiffies(300));
+			/* skip over GIWSCAN event */
+			goto out;
+		}
+
+	}
+	memset(&wrqu, 0, sizeof(union iwreq_data));
+	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
 
 #ifdef CONFIG_LIBERTAS_DEBUG
 	/* Dump the scan table */
 	mutex_lock(&adapter->lock);
-	lbs_deb_scan("The scan table contains:\n");
-	list_for_each_entry (iter_bss, &adapter->network_list, list) {
-		lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
-		       i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
-		       escape_essid(iter_bss->ssid, iter_bss->ssid_len));
-	}
+	lbs_deb_scan("scan table:\n");
+	list_for_each_entry(iter, &adapter->network_list, list)
+		lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
+		       i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
+		       escape_essid(iter->ssid, iter->ssid_len));
 	mutex_unlock(&adapter->lock);
 #endif
 
-	if (priv->adapter->connect_status == LBS_CONNECTED) {
-		netif_carrier_on(priv->dev);
-		netif_wake_queue(priv->dev);
-		if (priv->mesh_dev) {
-			netif_carrier_on(priv->mesh_dev);
-			netif_wake_queue(priv->mesh_dev);
-		}
-	}
+out2:
+	adapter->last_scanned_channel = 0;
 
 out:
-	if (scan_cfg)
-		kfree(scan_cfg);
-
-	if (scan_chan_list)
-		kfree(scan_chan_list);
+	netif_start_queue(priv->dev);
+	if (priv->mesh_dev)
+		netif_start_queue(priv->mesh_dev);
+	kfree(chan_list);
 
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	return ret;
 }
 
+
+
+
+/*********************************************************************/
+/*                                                                   */
+/*  Result interpretation                                            */
+/*                                                                   */
+/*********************************************************************/
+
 /**
  *  @brief Interpret a BSS scan response returned from the firmware
  *
  *  Parse the various fixed fields and IEs passed back for a a BSS probe
- *   response or beacon from the scan command.  Record information as needed
- *   in the scan table struct bss_descriptor for that entry.
+ *  response or beacon from the scan command.  Record information as needed
+ *  in the scan table struct bss_descriptor for that entry.
  *
  *  @param bss  Output parameter: Pointer to the BSS Entry
  *
@@ -896,7 +719,7 @@ static int lbs_process_bss(struct bss_de
 	*bytesleft -= beaconsize;
 
 	memcpy(bss->bssid, pos, ETH_ALEN);
-	lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
+	lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
 	pos += ETH_ALEN;
 
 	if ((end - pos) < 12) {
@@ -912,7 +735,7 @@ static int lbs_process_bss(struct bss_de
 
 	/* RSSI is 1 byte long */
 	bss->rssi = *pos;
-	lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
+	lbs_deb_scan("process_bss: RSSI %d\n", *pos);
 	pos++;
 
 	/* time stamp is 8 bytes long */
@@ -924,18 +747,18 @@ static int lbs_process_bss(struct bss_de
 
 	/* capability information is 2 bytes long */
 	bss->capability = le16_to_cpup((void *) pos);
-	lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
+	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
 	pos += 2;
 
 	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-		lbs_deb_scan("process_bss: AP WEP enabled\n");
+		lbs_deb_scan("process_bss: WEP enabled\n");
 	if (bss->capability & WLAN_CAPABILITY_IBSS)
 		bss->mode = IW_MODE_ADHOC;
 	else
 		bss->mode = IW_MODE_INFRA;
 
 	/* rest of the current buffer are IE's */
-	lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
+	lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
 	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
 
 	/* process variable IE */
@@ -953,7 +776,7 @@ static int lbs_process_bss(struct bss_de
 		case MFIE_TYPE_SSID:
 			bss->ssid_len = elem->len;
 			memcpy(bss->ssid, elem->data, elem->len);
-			lbs_deb_scan("ssid '%s', ssid length %u\n",
+			lbs_deb_scan("got SSID IE: '%s', len %u\n",
 			             escape_essid(bss->ssid, bss->ssid_len),
 			             bss->ssid_len);
 			break;
@@ -962,16 +785,14 @@ static int lbs_process_bss(struct bss_de
 			n_basic_rates = min_t(u8, MAX_RATES, elem->len);
 			memcpy(bss->rates, elem->data, n_basic_rates);
 			got_basic_rates = 1;
+			lbs_deb_scan("got RATES IE\n");
 			break;
 
 		case MFIE_TYPE_FH_SET:
 			pFH = (struct ieeetypes_fhparamset *) pos;
 			memmove(&bss->phyparamset.fhparamset, pFH,
 				sizeof(struct ieeetypes_fhparamset));
-#if 0 /* I think we can store these LE */
-			bss->phyparamset.fhparamset.dwelltime
-			    = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);
-#endif
+			lbs_deb_scan("got FH IE\n");
 			break;
 
 		case MFIE_TYPE_DS_SET:
@@ -979,12 +800,14 @@ static int lbs_process_bss(struct bss_de
 			bss->channel = pDS->currentchan;
 			memcpy(&bss->phyparamset.dsparamset, pDS,
 			       sizeof(struct ieeetypes_dsparamset));
+			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
 			break;
 
 		case MFIE_TYPE_CF_SET:
 			pCF = (struct ieeetypes_cfparamset *) pos;
 			memcpy(&bss->ssparamset.cfparamset, pCF,
 			       sizeof(struct ieeetypes_cfparamset));
+			lbs_deb_scan("got CF IE\n");
 			break;
 
 		case MFIE_TYPE_IBSS_SET:
@@ -992,18 +815,16 @@ static int lbs_process_bss(struct bss_de
 			bss->atimwindow = le32_to_cpu(pibss->atimwindow);
 			memmove(&bss->ssparamset.ibssparamset, pibss,
 				sizeof(struct ieeetypes_ibssparamset));
-#if 0
-			bss->ssparamset.ibssparamset.atimwindow
-			    = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);
-#endif
+			lbs_deb_scan("got IBSS IE\n");
 			break;
 
 		case MFIE_TYPE_COUNTRY:
 			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
+			lbs_deb_scan("got COUNTRY IE\n");
 			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
 			    || pcountryinfo->len > 254) {
 				lbs_deb_scan("process_bss: 11D- Err "
-				       "CountryInfo len =%d min=%zd max=254\n",
+				       "CountryInfo len %d, min %zd, max 254\n",
 				       pcountryinfo->len,
 				       sizeof(pcountryinfo->countrycode));
 				ret = -1;
@@ -1022,8 +843,11 @@ static int lbs_process_bss(struct bss_de
 			 * already found. Data rate IE should come before
 			 * extended supported rate IE
 			 */
-			if (!got_basic_rates)
+			lbs_deb_scan("got RATESEX IE\n");
+			if (!got_basic_rates) {
+				lbs_deb_scan("... but ignoring it\n");
 				break;
+			}
 
 			n_ex_rates = elem->len;
 			if (n_basic_rates + n_ex_rates > MAX_RATES)
@@ -1042,24 +866,36 @@ static int lbs_process_bss(struct bss_de
 				bss->wpa_ie_len = min(elem->len + 2,
 				                      MAX_WPA_IE_LEN);
 				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
-				lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
+				lbs_deb_scan("got WPA IE\n");
+				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
 				            elem->len);
 			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
 			    elem->data[0] == 0x00 &&
 			    elem->data[1] == 0x50 &&
 			    elem->data[2] == 0x43 &&
 			    elem->data[3] == 0x04) {
+				lbs_deb_scan("got mesh IE\n");
 				bss->mesh = 1;
+			} else {
+				lbs_deb_scan("got generiec IE: "
+					"%02x:%02x:%02x:%02x, len %d\n",
+					elem->data[0], elem->data[1],
+					elem->data[2], elem->data[3],
+					elem->len);
 			}
 			break;
 
 		case MFIE_TYPE_RSN:
+			lbs_deb_scan("got RSN IE\n");
 			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
 			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
-			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
+			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
+				bss->rsn_ie, elem->len);
 			break;
 
 		default:
+			lbs_deb_scan("got IE 0x%04x, len %d\n",
+				elem->id, elem->len);
 			break;
 		}
 
@@ -1271,8 +1107,6 @@ int lbs_find_best_network_ssid(struct lb
 	if (adapter->surpriseremoved)
 		goto out;
 
-	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
-
 	found = lbs_find_best_ssid_in_list(adapter, preferred_mode);
 	if (found && (found->ssid_len > 0)) {
 		memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
@@ -1286,36 +1120,6 @@ out:
 	return ret;
 }
 
-/**
- *  @brief Scan Network
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param vwrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
-		  struct iw_param *vwrq, char *extra)
-{
-	struct lbs_private *priv = dev->priv;
-	struct lbs_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (!delayed_work_pending(&priv->scan_work)) {
-		queue_delayed_work(priv->work_thread, &priv->scan_work,
-		                   msecs_to_jiffies(50));
-	}
-
-	if (adapter->surpriseremoved)
-		return -1;
-
-	lbs_deb_leave(LBS_DEB_SCAN);
-	return 0;
-}
-
 
 /**
  *  @brief Send a scan command for all available channels filtered on a spec
@@ -1327,8 +1131,6 @@ int lbs_set_scan(struct net_device *dev,
  *  @param ssid_len         Length of the SSID
  *  @param clear_ssid       Should existing scan results with this SSID
  *                          be cleared?
- *  @param prequestedssid   A pointer to AP's ssid
- *  @param keeppreviousscan Flag used to save/clear scan table before scan
  *
  *  @return                0-success, otherwise fail
  */
@@ -1355,7 +1157,6 @@ int lbs_send_specific_ssid_scan(struct l
 		ret = -1;
 		goto out;
 	}
-	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
@@ -1371,6 +1172,7 @@ out:
 /*                                                                   */
 /*********************************************************************/
 
+
 #define MAX_CUSTOM_LEN 64
 
 static inline char *lbs_translate_scan(struct lbs_private *priv,
@@ -1396,7 +1198,7 @@ static inline char *lbs_translate_scan(s
 		goto out;
 	}
 
-	/* First entry *MUST* be the AP BSSID */
+	/* First entry *MUST* be the BSSID */
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
@@ -1526,6 +1328,56 @@ out:
 	return start;
 }
 
+
+/**
+ *  @brief Handle Scan Network ioctl
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_param *wrqu, char *extra)
+{
+	struct lbs_private *priv = dev->priv;
+	struct lbs_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	/* mac80211 does this:
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type != IEEE80211_IF_TYPE_xxx)
+		return -EOPNOTSUPP;
+
+	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+		req = (struct iw_scan_req *)extra;
+			ssid = req->essid;
+		ssid_len = req->essid_len;
+	}
+	*/
+
+	if (!delayed_work_pending(&priv->scan_work))
+		queue_delayed_work(priv->work_thread, &priv->scan_work,
+			msecs_to_jiffies(50));
+	/* set marker that currently a scan is taking place */
+	adapter->last_scanned_channel = -1;
+
+	if (adapter->surpriseremoved)
+		return -EIO;
+
+	lbs_deb_leave(LBS_DEB_SCAN);
+	return 0;
+}
+
+
 /**
  *  @brief  Handle Retrieve scan table ioctl
  *
@@ -1550,6 +1402,10 @@ int lbs_get_scan(struct net_device *dev,
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
+	/* iwlist should wait until the current scan is finished */
+	if (adapter->last_scanned_channel)
+		return -EAGAIN;
+
 	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
 	if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
 		lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
@@ -1607,7 +1463,8 @@ int lbs_get_scan(struct net_device *dev,
 /**
  *  @brief Prepare a scan command to be sent to the firmware
  *
- *  Called from lbs_prepare_and_send_command() in cmd.c
+ *  Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
+ *  from cmd.c
  *
  *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
  *  as well as a variable number/length of TLVs to the firmware.
@@ -1621,7 +1478,7 @@ int lbs_get_scan(struct net_device *dev,
  *  @return           0 or -1
  */
 int lbs_cmd_80211_scan(struct lbs_private *priv,
-			 struct cmd_ds_command *cmd, void *pdata_buf)
+	struct cmd_ds_command *cmd, void *pdata_buf)
 {
 	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
 	struct lbs_scan_cmd_config *pscancfg = pdata_buf;
@@ -1633,32 +1490,14 @@ int lbs_cmd_80211_scan(struct lbs_privat
 	memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
 	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
 
-	cmd->command = cpu_to_le16(CMD_802_11_SCAN);
-
 	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
 	cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
 				+ pscancfg->tlvbufferlen + S_DS_GEN);
 
-	lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
-		     le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
-		     le16_to_cpu(cmd->seqnum));
-
 	lbs_deb_leave(LBS_DEB_SCAN);
 	return 0;
 }
 
-static inline int is_same_network(struct bss_descriptor *src,
-				  struct bss_descriptor *dst)
-{
-	/* A network is only a duplicate if the channel, BSSID, and ESSID
-	 * all match.  We treat all <hidden> with the same BSSID and channel
-	 * as one network */
-	return ((src->ssid_len == dst->ssid_len) &&
-		(src->channel == dst->channel) &&
-		!compare_ether_addr(src->bssid, dst->bssid) &&
-		!memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
 /**
  *  @brief This function handles the command response of scan
  *
@@ -1723,7 +1562,7 @@ int lbs_ret_80211_scan(struct lbs_privat
 	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
 
 	scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
-	lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
+	lbs_deb_scan("SCAN_RESP: scan results %d\n",
 	       pscan->nr_sets);
 
 	pbssinfo = pscan->bssdesc_and_tlvbuffer;
@@ -1786,7 +1625,7 @@ int lbs_ret_80211_scan(struct lbs_privat
 			continue;
 		}
 
-		lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
+		lbs_deb_scan("SCAN_RESP: BSSID %s\n",
 			     print_mac(mac, new.bssid));
 
 		/* Copy the locally created newbssentry to the scan table */
Index: wireless-2.6/drivers/net/wireless/libertas/dev.h
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:04.000000000 +0100
+++ wireless-2.6/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:19.000000000 +0100
@@ -363,9 +363,8 @@ struct lbs_adapter {
 	struct cmd_ds_802_11_get_log logmsg;
 
 	u32 monitormode;
+	int last_scanned_channel;
 	u8 fw_ready;
-
-	u8 last_scanned_channel;
 };
 
 #endif

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-11-29  8:27 [PATCH] libertas: implement new scanning logic Holger Schurig
@ 2007-11-29 19:38 ` Dan Williams
  2007-12-04 16:52 ` Dan Williams
  1 sibling, 0 replies; 14+ messages in thread
From: Dan Williams @ 2007-11-29 19:38 UTC (permalink / raw)
  To: Holger Schurig; +Cc: John W. Linville, libertas-dev, linux-wireless

On Thu, 2007-11-29 at 09:27 +0100, Holger Schurig wrote:
> This changes the code that is used for scanning and makes it hopefully
> easier to understand:
> 
> * move function into logical blocks
> * create a bunch of lbs_scan_add_XXXX_tlv() functions, that
>   help to create the TLV parameter of CMD_802_11_SCAN
> * all of them are now called from the much simpler lbs_do_scan()
> * no **puserscancfg double-pointers :-)
> 
> Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>

NAK for the moment, need to hash out some of the remaining questions I
posted to libertas-dev...

Dan

> 
> Index: wireless-2.6/drivers/net/wireless/libertas/scan.c
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/scan.c	2007-11-29 10:01:07.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/scan.c	2007-11-29 10:26:07.000000000 +0100
> @@ -79,6 +79,22 @@ static inline void clear_bss_descriptor 
>  	memset(bss, 0, offsetof(struct bss_descriptor, list));
>  }
>  
> +/**
> + *  @brief Compare two SSIDs
> + *
> + *  @param ssid1    A pointer to ssid to compare
> + *  @param ssid2    A pointer to ssid to compare
> + *
> + *  @return         0: ssid is same, otherwise is different
> + */
> +int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
> +{
> +	if (ssid1_len != ssid2_len)
> +		return -1;
> +
> +	return memcmp(ssid1, ssid2, ssid1_len);
> +}
> +
>  static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
>  			struct bss_descriptor * match_bss)
>  {
> @@ -149,6 +165,18 @@ static inline int match_bss_dynamic_wep(
>  	return 0;
>  }
>  
> +static inline int is_same_network(struct bss_descriptor *src,
> +				  struct bss_descriptor *dst)
> +{
> +	/* A network is only a duplicate if the channel, BSSID, and ESSID
> +	 * all match.  We treat all <hidden> with the same BSSID and channel
> +	 * as one network */
> +	return ((src->ssid_len == dst->ssid_len) &&
> +		(src->channel == dst->channel) &&
> +		!compare_ether_addr(src->bssid, dst->bssid) &&
> +		!memcmp(src->ssid, dst->ssid, src->ssid_len));
> +}
> +
>  /**
>   *  @brief Check if a scanned network compatible with the driver settings
>   *
> @@ -184,9 +212,9 @@ static int is_network_compatible(struct 
>  		goto done;
>  	} else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
> -		       "is_network_compatible() WPA: wpa_ie=%#x "
> -		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
> -		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
> +		       "is_network_compatible() WPA: wpa_ie 0x%x "
> +		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
> +		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
>  		       adapter->secinfo.wep_enabled ? "e" : "d",
>  		       adapter->secinfo.WPAenabled ? "e" : "d",
>  		       adapter->secinfo.WPA2enabled ? "e" : "d",
> @@ -194,9 +222,9 @@ static int is_network_compatible(struct 
>  		goto done;
>  	} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
> -		       "is_network_compatible() WPA2: wpa_ie=%#x "
> -		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
> -		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
> +		       "is_network_compatible() WPA2: wpa_ie 0x%x "
> +		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
> +		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
>  		       adapter->secinfo.wep_enabled ? "e" : "d",
>  		       adapter->secinfo.WPAenabled ? "e" : "d",
>  		       adapter->secinfo.WPA2enabled ? "e" : "d",
> @@ -205,7 +233,7 @@ static int is_network_compatible(struct 
>  	} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
>  		       "is_network_compatible() dynamic WEP: "
> -		       "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
> +		       "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
>  		       bss->wpa_ie[0], bss->rsn_ie[0],
>  		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
>  		goto done;
> @@ -213,8 +241,8 @@ static int is_network_compatible(struct 
>  
>  	/* bss security settings don't match those configured on card */
>  	lbs_deb_scan(
> -	       "is_network_compatible() FAILED: wpa_ie=%#x "
> -	       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n",
> +	       "is_network_compatible() FAILED: wpa_ie 0x%x "
> +	       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
>  	       bss->wpa_ie[0], bss->rsn_ie[0],
>  	       adapter->secinfo.wep_enabled ? "e" : "d",
>  	       adapter->secinfo.WPAenabled ? "e" : "d",
> @@ -226,22 +254,6 @@ done:
>  	return matched;
>  }
>  
> -/**
> - *  @brief Compare two SSIDs
> - *
> - *  @param ssid1    A pointer to ssid to compare
> - *  @param ssid2    A pointer to ssid to compare
> - *
> - *  @return         0--ssid is same, otherwise is different
> - */
> -int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
> -{
> -	if (ssid1_len != ssid2_len)
> -		return -1;
> -
> -	return memcmp(ssid1, ssid2, ssid1_len);
> -}
> -
>  
> 
> 
> @@ -251,6 +263,16 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
>  /*                                                                   */
>  /*********************************************************************/
>  
> +void lbs_scan_worker(struct work_struct *work)
> +{
> +	struct lbs_private *priv =
> +		container_of(work, struct lbs_private, scan_work.work);
> +
> +	lbs_deb_enter(LBS_DEB_SCAN);
> +	lbs_scan_networks(priv, NULL, 0);
> +	lbs_deb_leave(LBS_DEB_SCAN);
> +}
> +
>  
>  /**
>   *  @brief Create a channel list for the driver to scan based on region info
> @@ -271,7 +293,7 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
>   *
>   *  @return              void
>   */
> -static void lbs_scan_create_channel_list(struct lbs_private *priv,
> +static int lbs_scan_create_channel_list(struct lbs_private *priv,
>  					  struct chanscanparamset * scanchanlist,
>  					  u8 filteredscan)
>  {
> @@ -284,8 +306,6 @@ static void lbs_scan_create_channel_list
>  	int nextchan;
>  	u8 scantype;
>  
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
> -
>  	chanidx = 0;
>  
>  	/* Set the default scan type to the user specified type, will later
> @@ -352,383 +372,147 @@ static void lbs_scan_create_channel_list
>  			}
>  		}
>  	}
> +	return chanidx;
>  }
>  
> 
> -/* Delayed partial scan worker */
> -void lbs_scan_worker(struct work_struct *work)
> +/*
> + * Add SSID TLV of the form:
> + *
> + * TLV-ID SSID     00 00
> + * length          06 00
> + * ssid            4d 4e 54 45 53 54
> + */
> +static int lbs_scan_add_ssid_tlv(u8 *tlv,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg)
>  {
> -	struct lbs_private *priv = container_of(work,
> -		struct lbs_private,
> -		scan_work.work);
> -
> -	lbs_scan_networks(priv, NULL, 0);
> +	struct mrvlietypes_ssidparamset *ssid_tlv =
> +		(struct mrvlietypes_ssidparamset *)tlv;
> +	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
> +	ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
> +	memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
> +	return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
>  }
>  
> 
> -/**
> - *  @brief Construct a lbs_scan_cmd_config structure to use in issue scan cmds
> - *
> - *  Application layer or other functions can invoke lbs_scan_networks
> - *    with a scan configuration supplied in a lbs_ioctl_user_scan_cfg struct.
> - *    This structure is used as the basis of one or many lbs_scan_cmd_config
> - *    commands that are sent to the command processing module and sent to
> - *    firmware.
> - *
> - *  Create a lbs_scan_cmd_config based on the following user supplied
> - *    parameters (if present):
> - *             - SSID filter
> - *             - BSSID filter
> - *             - Number of Probes to be sent
> - *             - channel list
> - *
> - *  If the SSID or BSSID filter is not present, disable/clear the filter.
> - *  Qualify the channel
> +/*
> + * Add CHANLIST TLV of the form
>   *
> - *  @param priv             A pointer to struct lbs_private structure
> - *  @param puserscanin      NULL or pointer to scan configuration parameters
> - *  @param ppchantlvout     Output parameter: Pointer to the start of the
> - *                          channel TLV portion of the output scan config
> - *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
> - *                          list to scan
> - *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
> - *                          each issuance of the firmware scan command
> - *  @param pfilteredscan    Output parameter: Flag indicating whether or not
> - *                          a BSSID or SSID filter is being sent in the
> - *                          command to firmware.  Used to increase the number
> - *                          of channels sent in a scan command and to
> - *                          disable the firmware channel scan filter.
> - *  @param pscancurrentonly Output parameter: Flag indicating whether or not
> - *                          we are only scanning our current active channel
> + * TLV-ID CHANLIST 01 01
> + * length          5b 00
> + * channel 1       00 01 00 00 00 64 00
> + *   radio type    00
> + *   channel          01
> + *   scan type           00
> + *   min scan time          00 00
> + *   max scan time                64 00
> + * channel 2       00 02 00 00 00 64 00
> + * channel 3       00 03 00 00 00 64 00
> + * channel 4       00 04 00 00 00 64 00
> + * channel 5       00 05 00 00 00 64 00
> + * channel 6       00 06 00 00 00 64 00
> + * channel 7       00 07 00 00 00 64 00
> + * channel 8       00 08 00 00 00 64 00
> + * channel 9       00 09 00 00 00 64 00
> + * channel 10      00 0a 00 00 00 64 00
> + * channel 11      00 0b 00 00 00 64 00
> + * channel 12      00 0c 00 00 00 64 00
> + * channel 13      00 0d 00 00 00 64 00
>   *
> - *  @return                 resulting scan configuration
>   */
> -static struct lbs_scan_cmd_config *
> -lbs_scan_setup_scan_config(struct lbs_private *priv,
> -			    const struct lbs_ioctl_user_scan_cfg *puserscanin,
> -			    struct mrvlietypes_chanlistparamset ** ppchantlvout,
> -			    struct chanscanparamset * pscanchanlist,
> -			    int *pmaxchanperscan,
> -			    u8 * pfilteredscan,
> -			    u8 * pscancurrentonly)
> +static int lbs_scan_add_chanlist_tlv(u8 *tlv,
> +	struct chanscanparamset *chan_list,
> +	int chan_count)
>  {
> -	struct mrvlietypes_ssidparamset *pssidtlv;
> -	struct lbs_scan_cmd_config *pscancfgout = NULL;
> -	u8 *ptlvpos;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
> -	if (pscancfgout == NULL)
> -		goto out;
> -
> -	/* The tlvbufferlen is calculated for each scan command.  The TLVs added
> -	 *   in this routine will be preserved since the routine that sends
> -	 *   the command will append channelTLVs at *ppchantlvout.  The difference
> -	 *   between the *ppchantlvout and the tlvbuffer start will be used
> -	 *   to calculate the size of anything we add in this routine.
> -	 */
> -	pscancfgout->tlvbufferlen = 0;
> -
> -	/* Running tlv pointer.  Assigned to ppchantlvout at end of function
> -	 *  so later routines know where channels can be added to the command buf
> -	 */
> -	ptlvpos = pscancfgout->tlvbuffer;
> -
> -	/*
> -	 * Set the initial scan paramters for progressive scanning.  If a specific
> -	 *   BSSID or SSID is used, the number of channels in the scan command
> -	 *   will be increased to the absolute maximum
> -	 */
> -	*pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
> -
> -	/* Initialize the scan as un-filtered by firmware, set to TRUE below if
> -	 *   a SSID or BSSID filter is sent in the command
> -	 */
> -	*pfilteredscan = 0;
> -
> -	/* Initialize the scan as not being only on the current channel.  If
> -	 *   the channel list is customized, only contains one channel, and
> -	 *   is the active channel, this is set true and data flow is not halted.
> -	 */
> -	*pscancurrentonly = 0;
> -
> -	if (puserscanin) {
> -		/* Set the bss type scan filter, use adapter setting if unset */
> -		pscancfgout->bsstype =
> -		    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
> -
> -		/*
> -		 * Set the BSSID filter to the incoming configuration,
> -		 *   if non-zero.  If not set, it will remain disabled (all zeros).
> -		 */
> -		memcpy(pscancfgout->bssid, puserscanin->bssid,
> -		       sizeof(pscancfgout->bssid));
> -
> -		if (puserscanin->ssid_len) {
> -			pssidtlv =
> -			    (struct mrvlietypes_ssidparamset *) pscancfgout->
> -			    tlvbuffer;
> -			pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
> -			pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
> -			memcpy(pssidtlv->ssid, puserscanin->ssid,
> -			       puserscanin->ssid_len);
> -			ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
> -		}
> -
> -		/*
> -		 *  The default number of channels sent in the command is low to
> -		 *    ensure the response buffer from the firmware does not truncate
> -		 *    scan results.  That is not an issue with an SSID or BSSID
> -		 *    filter applied to the scan results in the firmware.
> -		 */
> -		if (   puserscanin->ssid_len
> -		    || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
> -			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
> -			*pfilteredscan = 1;
> -		}
> -	} else {
> -		pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
> -	}
> -
> -	/*
> -	 * Set the output for the channel TLV to the address in the tlv buffer
> -	 *   past any TLVs that were added in this fuction (SSID).
> -	 *   channel TLVs will be added past this for each scan command, preserving
> -	 *   the TLVs that were previously added.
> -	 */
> -	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
> +	size_t size = sizeof(struct chanscanparamset) * chan_count;
> +	struct mrvlietypes_chanlistparamset *chan_tlv =
> +		(struct mrvlietypes_chanlistparamset *) tlv;
>  
> -	lbs_scan_create_channel_list(priv, pscanchanlist,
> -				      *pfilteredscan);
> -out:
> -	return pscancfgout;
> +	chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
> +	memcpy(chan_tlv->chanscanparam, chan_list, size);
> +	chan_tlv->header.len = cpu_to_le16(size);
> +	return sizeof(chan_tlv->header) + size;
>  }
>  
> -/**
> - *  @brief Construct and send multiple scan config commands to the firmware
> - *
> - *  Only used from lbs_scan_networks()
> - *
> - *  Previous routines have created a lbs_scan_cmd_config with any requested
> - *   TLVs.  This function splits the channel TLV into maxchanperscan lists
> - *   and sends the portion of the channel TLV along with the other TLVs
> - *   to the lbs_cmd routines for execution in the firmware.
> +
> +/*
> + * Add RATES TLV of the form
>   *
> - *  @param priv            A pointer to struct lbs_private structure
> - *  @param maxchanperscan  Maximum number channels to be included in each
> - *                         scan command sent to firmware
> - *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
> - *                         filter is being used for the firmware command
> - *                         scan command sent to firmware
> - *  @param pscancfgout     Scan configuration used for this scan.
> - *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
> - *                         should start.  This is past any other TLVs that
> - *                         must be sent down in each firmware command.
> - *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
> + * TLV-ID RATES    01 00
> + * length          0e 00
> + * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
>   *
> - *  @return                0 or error return otherwise
> + * The rates are in lbs_bg_rates[], but for the 802.11b
> + * rates the high bit isn't set.
>   */
> -static int lbs_scan_channel_list(struct lbs_private *priv,
> -				  int maxchanperscan,
> -				  u8 filteredscan,
> -				  struct lbs_scan_cmd_config *pscancfgout,
> -				  struct mrvlietypes_chanlistparamset * pchantlvout,
> -				  struct chanscanparamset * pscanchanlist,
> -				  const struct lbs_ioctl_user_scan_cfg *puserscanin,
> -				  int full_scan)
> +static int lbs_scan_add_rates_tlv(u8 *tlv)
>  {
> -	struct chanscanparamset *ptmpchan;
> -	struct chanscanparamset *pstartchan;
> -	u8 scanband;
> -	int doneearly;
> -	int tlvidx;
> -	int ret = 0;
> -	int scanned = 0;
> -	union iwreq_data wrqu;
> -
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
> -		"full_scan %d", maxchanperscan, filteredscan, full_scan);
> -
> -	if (!pscancfgout || !pchantlvout || !pscanchanlist) {
> -		lbs_deb_scan("pscancfgout, pchantlvout or "
> -			"pscanchanlist is NULL\n");
> -		ret = -1;
> -		goto out;
> -	}
> -
> -	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
> -
> -	/* Set the temp channel struct pointer to the start of the desired list */
> -	ptmpchan = pscanchanlist;
> -
> -	if (priv->adapter->last_scanned_channel && !puserscanin)
> -		ptmpchan += priv->adapter->last_scanned_channel;
> -
> -	/* Loop through the desired channel list, sending a new firmware scan
> -	 *   commands for each maxchanperscan channels (or for 1,6,11 individually
> -	 *   if configured accordingly)
> -	 */
> -	while (ptmpchan->channumber) {
> -
> -		tlvidx = 0;
> -		pchantlvout->header.len = 0;
> -		scanband = ptmpchan->radiotype;
> -		pstartchan = ptmpchan;
> -		doneearly = 0;
> -
> -		/* Construct the channel TLV for the scan command.  Continue to
> -		 *  insert channel TLVs until:
> -		 *    - the tlvidx hits the maximum configured per scan command
> -		 *    - the next channel to insert is 0 (end of desired channel list)
> -		 *    - doneearly is set (controlling individual scanning of 1,6,11)
> -		 */
> -		while (tlvidx < maxchanperscan && ptmpchan->channumber
> -		       && !doneearly && scanned < 2) {
> -
> -			lbs_deb_scan("channel %d, radio %d, passive %d, "
> -				"dischanflt %d, maxscantime %d\n",
> -				ptmpchan->channumber,
> -				ptmpchan->radiotype,
> -			             ptmpchan->chanscanmode.passivescan,
> -			             ptmpchan->chanscanmode.disablechanfilt,
> -			             ptmpchan->maxscantime);
> -
> -			/* Copy the current channel TLV to the command being prepared */
> -			memcpy(pchantlvout->chanscanparam + tlvidx,
> -			       ptmpchan, sizeof(pchantlvout->chanscanparam));
> -
> -			/* Increment the TLV header length by the size appended */
> -			/* Ew, it would be _so_ nice if we could just declare the
> -			   variable little-endian and let GCC handle it for us */
> -			pchantlvout->header.len =
> -				cpu_to_le16(le16_to_cpu(pchantlvout->header.len) +
> -					    sizeof(pchantlvout->chanscanparam));
> -
> -			/*
> -			 *  The tlv buffer length is set to the number of bytes of the
> -			 *    between the channel tlv pointer and the start of the
> -			 *    tlv buffer.  This compensates for any TLVs that were appended
> -			 *    before the channel list.
> -			 */
> -			pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
> -						     - pscancfgout->tlvbuffer);
> -
> -			/*  Add the size of the channel tlv header and the data length */
> -			pscancfgout->tlvbufferlen +=
> -			    (sizeof(pchantlvout->header)
> -			     + le16_to_cpu(pchantlvout->header.len));
> -
> -			/* Increment the index to the channel tlv we are constructing */
> -			tlvidx++;
> -
> -			doneearly = 0;
> -
> -			/* Stop the loop if the *current* channel is in the 1,6,11 set
> -			 *   and we are not filtering on a BSSID or SSID.
> -			 */
> -			if (!filteredscan && (ptmpchan->channumber == 1
> -					      || ptmpchan->channumber == 6
> -					      || ptmpchan->channumber == 11)) {
> -				doneearly = 1;
> -			}
> -
> -			/* Increment the tmp pointer to the next channel to be scanned */
> -			ptmpchan++;
> -			scanned++;
> -
> -			/* Stop the loop if the *next* channel is in the 1,6,11 set.
> -			 *  This will cause it to be the only channel scanned on the next
> -			 *  interation
> -			 */
> -			if (!filteredscan && (ptmpchan->channumber == 1
> -					      || ptmpchan->channumber == 6
> -					      || ptmpchan->channumber == 11)) {
> -				doneearly = 1;
> -			}
> -		}
> -
> -		/* Send the scan command to the firmware with the specified cfg */
> -		ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
> -					    0, 0, pscancfgout);
> -		if (scanned >= 2 && !full_scan) {
> -			ret = 0;
> -			goto done;
> -		}
> -		scanned = 0;
> -	}
> -
> -done:
> -	priv->adapter->last_scanned_channel = ptmpchan->channumber;
> +	int i;
> +	struct mrvlietypes_ratesparamset *rate_tlv =
> +		(struct mrvlietypes_ratesparamset *) tlv;
>  
> -	if (priv->adapter->last_scanned_channel) {
> -		/* Schedule the next part of the partial scan */
> -		if (!full_scan && !priv->adapter->surpriseremoved) {
> -			cancel_delayed_work(&priv->scan_work);
> -			queue_delayed_work(priv->work_thread, &priv->scan_work,
> -			                   msecs_to_jiffies(300));
> -		}
> -	} else {
> -		/* All done, tell userspace the scan table has been updated */
> -		memset(&wrqu, 0, sizeof(union iwreq_data));
> -		wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
> +	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
> +	tlv += sizeof(rate_tlv->header);
> +	for (i = 0; i < MAX_RATES; i++) {
> +		*tlv = lbs_bg_rates[i];
> +		if (*tlv == 0)
> +			break;
> +		if (*tlv == 0x02 || *tlv == 0x04 ||
> +		    *tlv == 0x0b || *tlv == 0x16)
> +			*tlv |= 0x80;
> +		tlv++;
>  	}
> -
> -out:
> -	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> -	return ret;
> +	rate_tlv->header.len = i;
> +	return sizeof(rate_tlv->header) + i;
>  }
>  
> +
>  /*
> - * Only used from lbs_scan_networks()
> -*/
> -static void clear_selected_scan_list_entries(struct lbs_adapter *adapter,
> -	const struct lbs_ioctl_user_scan_cfg *scan_cfg)
> + * Generate the CMD_802_11_SCAN command with the proper tlv
> + * for a bunch of channels.
> + */
> +static int lbs_do_scan(struct lbs_private *priv,
> +	u8 bsstype,
> +	struct chanscanparamset *chan_list,
> +	int chan_count,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg)
>  {
> -	struct bss_descriptor *bss;
> -	struct bss_descriptor *safe;
> -	u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	if (!scan_cfg)
> -		goto out;
> -
> -	if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
> -		clear_ssid_flag = 1;
> +	int ret = -ENOMEM;
> +	struct lbs_scan_cmd_config *scan_cmd;
> +	u8 *tlv;    /* pointer into our current, growing TLV storage area */
>  
> -	if (scan_cfg->clear_bssid
> -	    && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0)
> -	    && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) {
> -		clear_bssid_flag = 1;
> -	}
> +	lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
> +		"chan_count %d",
> +		bsstype, chan_list[0].channumber, chan_count);
>  
> -	if (!clear_ssid_flag && !clear_bssid_flag)
> +	/* create the fixed part for scan command */
> +	scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
> +	if (scan_cmd == NULL)
>  		goto out;
> +	tlv = scan_cmd->tlvbuffer;
> +	if (user_cfg)
> +		memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
> +	scan_cmd->bsstype = bsstype;
>  
> -	mutex_lock(&adapter->lock);
> -	list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
> -		u32 clear = 0;
> -
> -		/* Check for an SSID match */
> -		if (   clear_ssid_flag
> -		    && (bss->ssid_len == scan_cfg->ssid_len)
> -		    && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len))
> -			clear = 1;
> +	/* add TLVs */
> +	if (user_cfg && user_cfg->ssid_len)
> +		tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
> +	if (chan_list && chan_count)
> +		tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
> +	tlv += lbs_scan_add_rates_tlv(tlv);
>  
> -		/* Check for a BSSID match */
> -		if (   clear_bssid_flag
> -		    && !compare_ether_addr(bss->bssid, scan_cfg->bssid))
> -			clear = 1;
> +	/* This is the final data we are about to send */
> +	scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
> +	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
> +	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
> +		scan_cmd->tlvbufferlen);
>  
> -		if (clear) {
> -			list_move_tail (&bss->list, &adapter->network_free_list);
> -			clear_bss_descriptor(bss);
> -		}
> -	}
> -	mutex_unlock(&adapter->lock);
> +	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
> +		CMD_OPTION_WAITFORRSP, 0, scan_cmd);
>  out:
> -	lbs_deb_leave(LBS_DEB_SCAN);
> +	kfree(scan_cmd);
> +	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> +	return ret;
>  }
>  
> 
> @@ -744,29 +528,30 @@ out:
>   *  @param priv          A pointer to struct lbs_private structure
>   *  @param puserscanin   Pointer to the input configuration for the requested
>   *                       scan.
> - *  @param full_scan     ???
>   *
>   *  @return              0 or < 0 if error
>   */
>  int lbs_scan_networks(struct lbs_private *priv,
> -	const struct lbs_ioctl_user_scan_cfg *puserscanin,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg,
>                         int full_scan)
>  {
>  	struct lbs_adapter *adapter = priv->adapter;
> -	struct mrvlietypes_chanlistparamset *pchantlvout;
> -	struct chanscanparamset * scan_chan_list = NULL;
> -	struct lbs_scan_cmd_config *scan_cfg = NULL;
> -	u8 filteredscan;
> -	u8 scancurrentchanonly;
> -	int maxchanperscan;
> -	int ret;
> +	int ret = -ENOMEM;
> +	struct chanscanparamset *chan_list;
> +	struct chanscanparamset *curr_chans;
> +	int chan_count;
> +	u8 bsstype = CMD_BSS_TYPE_ANY;
> +	int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
> +	int filteredscan = 0;
> +	union iwreq_data wrqu;
>  #ifdef CONFIG_LIBERTAS_DEBUG
> -	struct bss_descriptor * iter_bss;
> +	struct bss_descriptor *iter;
>  	int i = 0;
>  	DECLARE_MAC_BUF(mac);
>  #endif
>  
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
> +	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
> +		full_scan);
>  
>  	/* Cancel any partial outstanding partial scans if this scan
>  	 * is a full scan.
> @@ -774,84 +559,122 @@ int lbs_scan_networks(struct lbs_private
>  	if (full_scan && delayed_work_pending(&priv->scan_work))
>  		cancel_delayed_work(&priv->scan_work);
>  
> -	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
> -				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
> -	if (scan_chan_list == NULL) {
> -		ret = -ENOMEM;
> -		goto out;
> +	/* Determine same scan parameters */
> +	if (user_cfg) {
> +		if (user_cfg->bsstype)
> +			bsstype = user_cfg->bsstype;
> +		if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
> +			numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
> +			filteredscan = 1;
> +		}
>  	}
> +	lbs_deb_scan("numchannels %d, bsstype %d, "
> +		"filteredscan %d\n",
> +		numchannels, bsstype, filteredscan);
>  
> -	scan_cfg = lbs_scan_setup_scan_config(priv,
> -					       puserscanin,
> -					       &pchantlvout,
> -					       scan_chan_list,
> -					       &maxchanperscan,
> -					       &filteredscan,
> -					       &scancurrentchanonly);
> -	if (scan_cfg == NULL) {
> -		ret = -ENOMEM;
> +	/* Create list of channels to scan */
> +	chan_list = kzalloc(sizeof(struct chanscanparamset) *
> +				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
> +	if (!chan_list) {
> +		lbs_pr_alert("SCAN: chan_list empty\n");
>  		goto out;
>  	}
>  
> -	clear_selected_scan_list_entries(adapter, puserscanin);
> +	/* We want to scan all channels */
> +	chan_count = lbs_scan_create_channel_list(priv, chan_list,
> +		filteredscan);
>  
> -	/* Keep the data path active if we are only scanning our current channel */
> -	if (!scancurrentchanonly) {
> -		netif_stop_queue(priv->dev);
> -		netif_carrier_off(priv->dev);
> -		if (priv->mesh_dev) {
> +	netif_stop_queue(priv->dev);
> +	if (priv->mesh_dev)
>  			netif_stop_queue(priv->mesh_dev);
> -			netif_carrier_off(priv->mesh_dev);
> -		}
> +
> +	/* Prepare to continue an interrupted scan */
> +	lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
> +		chan_count, adapter->last_scanned_channel);
> +	curr_chans = chan_list;
> +	/* advance channel list by already-scanned-channels */
> +	if (adapter->last_scanned_channel > 0) {
> +		curr_chans += adapter->last_scanned_channel;
> +		chan_count -= adapter->last_scanned_channel;
>  	}
>  
> -	ret = lbs_scan_channel_list(priv,
> -				     maxchanperscan,
> -				     filteredscan,
> -				     scan_cfg,
> -				     pchantlvout,
> -				     scan_chan_list,
> -				     puserscanin,
> -				     full_scan);
> +	/* Send scan command(s)
> +	 * numchannels contains the number of channels we should maximally scan
> +	 * chan_count is the total number of channels to scan
> +	 */
> +
> +	while (chan_count) {
> +		int to_scan = min(numchannels, chan_count);
> +		lbs_deb_scan("scanning %d of %d channels\n",
> +			to_scan, chan_count);
> +		ret = lbs_do_scan(priv, bsstype, curr_chans,
> +			to_scan, user_cfg);
> +		if (ret) {
> +			lbs_pr_err("SCAN_CMD failed\n");
> +			goto out2;
> +		}
> +		curr_chans += to_scan;
> +		chan_count -= to_scan;
> +
> +		/* somehow schedule the next part of the scan */
> +		if (chan_count &&
> +		    !full_scan &&
> +		    !priv->adapter->surpriseremoved) {
> +			/* -1 marks just that we're currently scanning */
> +			if (adapter->last_scanned_channel < 0)
> +				adapter->last_scanned_channel = to_scan;
> +			else
> +				adapter->last_scanned_channel += to_scan;
> +			cancel_delayed_work(&priv->scan_work);
> +			queue_delayed_work(priv->work_thread, &priv->scan_work,
> +				msecs_to_jiffies(300));
> +			/* skip over GIWSCAN event */
> +			goto out;
> +		}
> +
> +	}
> +	memset(&wrqu, 0, sizeof(union iwreq_data));
> +	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
>  
>  #ifdef CONFIG_LIBERTAS_DEBUG
>  	/* Dump the scan table */
>  	mutex_lock(&adapter->lock);
> -	lbs_deb_scan("The scan table contains:\n");
> -	list_for_each_entry (iter_bss, &adapter->network_list, list) {
> -		lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
> -		       i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
> -		       escape_essid(iter_bss->ssid, iter_bss->ssid_len));
> -	}
> +	lbs_deb_scan("scan table:\n");
> +	list_for_each_entry(iter, &adapter->network_list, list)
> +		lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
> +		       i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
> +		       escape_essid(iter->ssid, iter->ssid_len));
>  	mutex_unlock(&adapter->lock);
>  #endif
>  
> -	if (priv->adapter->connect_status == LBS_CONNECTED) {
> -		netif_carrier_on(priv->dev);
> -		netif_wake_queue(priv->dev);
> -		if (priv->mesh_dev) {
> -			netif_carrier_on(priv->mesh_dev);
> -			netif_wake_queue(priv->mesh_dev);
> -		}
> -	}
> +out2:
> +	adapter->last_scanned_channel = 0;
>  
>  out:
> -	if (scan_cfg)
> -		kfree(scan_cfg);
> -
> -	if (scan_chan_list)
> -		kfree(scan_chan_list);
> +	netif_start_queue(priv->dev);
> +	if (priv->mesh_dev)
> +		netif_start_queue(priv->mesh_dev);
> +	kfree(chan_list);
>  
>  	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
>  	return ret;
>  }
>  
> +
> +
> +
> +/*********************************************************************/
> +/*                                                                   */
> +/*  Result interpretation                                            */
> +/*                                                                   */
> +/*********************************************************************/
> +
>  /**
>   *  @brief Interpret a BSS scan response returned from the firmware
>   *
>   *  Parse the various fixed fields and IEs passed back for a a BSS probe
> - *   response or beacon from the scan command.  Record information as needed
> - *   in the scan table struct bss_descriptor for that entry.
> + *  response or beacon from the scan command.  Record information as needed
> + *  in the scan table struct bss_descriptor for that entry.
>   *
>   *  @param bss  Output parameter: Pointer to the BSS Entry
>   *
> @@ -896,7 +719,7 @@ static int lbs_process_bss(struct bss_de
>  	*bytesleft -= beaconsize;
>  
>  	memcpy(bss->bssid, pos, ETH_ALEN);
> -	lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
> +	lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
>  	pos += ETH_ALEN;
>  
>  	if ((end - pos) < 12) {
> @@ -912,7 +735,7 @@ static int lbs_process_bss(struct bss_de
>  
>  	/* RSSI is 1 byte long */
>  	bss->rssi = *pos;
> -	lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
> +	lbs_deb_scan("process_bss: RSSI %d\n", *pos);
>  	pos++;
>  
>  	/* time stamp is 8 bytes long */
> @@ -924,18 +747,18 @@ static int lbs_process_bss(struct bss_de
>  
>  	/* capability information is 2 bytes long */
>  	bss->capability = le16_to_cpup((void *) pos);
> -	lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
> +	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
>  	pos += 2;
>  
>  	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
> -		lbs_deb_scan("process_bss: AP WEP enabled\n");
> +		lbs_deb_scan("process_bss: WEP enabled\n");
>  	if (bss->capability & WLAN_CAPABILITY_IBSS)
>  		bss->mode = IW_MODE_ADHOC;
>  	else
>  		bss->mode = IW_MODE_INFRA;
>  
>  	/* rest of the current buffer are IE's */
> -	lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
> +	lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
>  	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
>  
>  	/* process variable IE */
> @@ -953,7 +776,7 @@ static int lbs_process_bss(struct bss_de
>  		case MFIE_TYPE_SSID:
>  			bss->ssid_len = elem->len;
>  			memcpy(bss->ssid, elem->data, elem->len);
> -			lbs_deb_scan("ssid '%s', ssid length %u\n",
> +			lbs_deb_scan("got SSID IE: '%s', len %u\n",
>  			             escape_essid(bss->ssid, bss->ssid_len),
>  			             bss->ssid_len);
>  			break;
> @@ -962,16 +785,14 @@ static int lbs_process_bss(struct bss_de
>  			n_basic_rates = min_t(u8, MAX_RATES, elem->len);
>  			memcpy(bss->rates, elem->data, n_basic_rates);
>  			got_basic_rates = 1;
> +			lbs_deb_scan("got RATES IE\n");
>  			break;
>  
>  		case MFIE_TYPE_FH_SET:
>  			pFH = (struct ieeetypes_fhparamset *) pos;
>  			memmove(&bss->phyparamset.fhparamset, pFH,
>  				sizeof(struct ieeetypes_fhparamset));
> -#if 0 /* I think we can store these LE */
> -			bss->phyparamset.fhparamset.dwelltime
> -			    = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);
> -#endif
> +			lbs_deb_scan("got FH IE\n");
>  			break;
>  
>  		case MFIE_TYPE_DS_SET:
> @@ -979,12 +800,14 @@ static int lbs_process_bss(struct bss_de
>  			bss->channel = pDS->currentchan;
>  			memcpy(&bss->phyparamset.dsparamset, pDS,
>  			       sizeof(struct ieeetypes_dsparamset));
> +			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
>  			break;
>  
>  		case MFIE_TYPE_CF_SET:
>  			pCF = (struct ieeetypes_cfparamset *) pos;
>  			memcpy(&bss->ssparamset.cfparamset, pCF,
>  			       sizeof(struct ieeetypes_cfparamset));
> +			lbs_deb_scan("got CF IE\n");
>  			break;
>  
>  		case MFIE_TYPE_IBSS_SET:
> @@ -992,18 +815,16 @@ static int lbs_process_bss(struct bss_de
>  			bss->atimwindow = le32_to_cpu(pibss->atimwindow);
>  			memmove(&bss->ssparamset.ibssparamset, pibss,
>  				sizeof(struct ieeetypes_ibssparamset));
> -#if 0
> -			bss->ssparamset.ibssparamset.atimwindow
> -			    = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);
> -#endif
> +			lbs_deb_scan("got IBSS IE\n");
>  			break;
>  
>  		case MFIE_TYPE_COUNTRY:
>  			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
> +			lbs_deb_scan("got COUNTRY IE\n");
>  			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
>  			    || pcountryinfo->len > 254) {
>  				lbs_deb_scan("process_bss: 11D- Err "
> -				       "CountryInfo len =%d min=%zd max=254\n",
> +				       "CountryInfo len %d, min %zd, max 254\n",
>  				       pcountryinfo->len,
>  				       sizeof(pcountryinfo->countrycode));
>  				ret = -1;
> @@ -1022,8 +843,11 @@ static int lbs_process_bss(struct bss_de
>  			 * already found. Data rate IE should come before
>  			 * extended supported rate IE
>  			 */
> -			if (!got_basic_rates)
> +			lbs_deb_scan("got RATESEX IE\n");
> +			if (!got_basic_rates) {
> +				lbs_deb_scan("... but ignoring it\n");
>  				break;
> +			}
>  
>  			n_ex_rates = elem->len;
>  			if (n_basic_rates + n_ex_rates > MAX_RATES)
> @@ -1042,24 +866,36 @@ static int lbs_process_bss(struct bss_de
>  				bss->wpa_ie_len = min(elem->len + 2,
>  				                      MAX_WPA_IE_LEN);
>  				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
> -				lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
> +				lbs_deb_scan("got WPA IE\n");
> +				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
>  				            elem->len);
>  			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
>  			    elem->data[0] == 0x00 &&
>  			    elem->data[1] == 0x50 &&
>  			    elem->data[2] == 0x43 &&
>  			    elem->data[3] == 0x04) {
> +				lbs_deb_scan("got mesh IE\n");
>  				bss->mesh = 1;
> +			} else {
> +				lbs_deb_scan("got generiec IE: "
> +					"%02x:%02x:%02x:%02x, len %d\n",
> +					elem->data[0], elem->data[1],
> +					elem->data[2], elem->data[3],
> +					elem->len);
>  			}
>  			break;
>  
>  		case MFIE_TYPE_RSN:
> +			lbs_deb_scan("got RSN IE\n");
>  			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
>  			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
> -			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
> +			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
> +				bss->rsn_ie, elem->len);
>  			break;
>  
>  		default:
> +			lbs_deb_scan("got IE 0x%04x, len %d\n",
> +				elem->id, elem->len);
>  			break;
>  		}
>  
> @@ -1271,8 +1107,6 @@ int lbs_find_best_network_ssid(struct lb
>  	if (adapter->surpriseremoved)
>  		goto out;
>  
> -	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
> -
>  	found = lbs_find_best_ssid_in_list(adapter, preferred_mode);
>  	if (found && (found->ssid_len > 0)) {
>  		memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
> @@ -1286,36 +1120,6 @@ out:
>  	return ret;
>  }
>  
> -/**
> - *  @brief Scan Network
> - *
> - *  @param dev          A pointer to net_device structure
> - *  @param info         A pointer to iw_request_info structure
> - *  @param vwrq         A pointer to iw_param structure
> - *  @param extra        A pointer to extra data buf
> - *
> - *  @return             0 --success, otherwise fail
> - */
> -int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
> -		  struct iw_param *vwrq, char *extra)
> -{
> -	struct lbs_private *priv = dev->priv;
> -	struct lbs_adapter *adapter = priv->adapter;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	if (!delayed_work_pending(&priv->scan_work)) {
> -		queue_delayed_work(priv->work_thread, &priv->scan_work,
> -		                   msecs_to_jiffies(50));
> -	}
> -
> -	if (adapter->surpriseremoved)
> -		return -1;
> -
> -	lbs_deb_leave(LBS_DEB_SCAN);
> -	return 0;
> -}
> -
>  
>  /**
>   *  @brief Send a scan command for all available channels filtered on a spec
> @@ -1327,8 +1131,6 @@ int lbs_set_scan(struct net_device *dev,
>   *  @param ssid_len         Length of the SSID
>   *  @param clear_ssid       Should existing scan results with this SSID
>   *                          be cleared?
> - *  @param prequestedssid   A pointer to AP's ssid
> - *  @param keeppreviousscan Flag used to save/clear scan table before scan
>   *
>   *  @return                0-success, otherwise fail
>   */
> @@ -1355,7 +1157,6 @@ int lbs_send_specific_ssid_scan(struct l
>  		ret = -1;
>  		goto out;
>  	}
> -	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
>  
>  out:
>  	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> @@ -1371,6 +1172,7 @@ out:
>  /*                                                                   */
>  /*********************************************************************/
>  
> +
>  #define MAX_CUSTOM_LEN 64
>  
>  static inline char *lbs_translate_scan(struct lbs_private *priv,
> @@ -1396,7 +1198,7 @@ static inline char *lbs_translate_scan(s
>  		goto out;
>  	}
>  
> -	/* First entry *MUST* be the AP BSSID */
> +	/* First entry *MUST* be the BSSID */
>  	iwe.cmd = SIOCGIWAP;
>  	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
>  	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
> @@ -1526,6 +1328,56 @@ out:
>  	return start;
>  }
>  
> +
> +/**
> + *  @brief Handle Scan Network ioctl
> + *
> + *  @param dev          A pointer to net_device structure
> + *  @param info         A pointer to iw_request_info structure
> + *  @param vwrq         A pointer to iw_param structure
> + *  @param extra        A pointer to extra data buf
> + *
> + *  @return             0 --success, otherwise fail
> + */
> +int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
> +		  struct iw_param *wrqu, char *extra)
> +{
> +	struct lbs_private *priv = dev->priv;
> +	struct lbs_adapter *adapter = priv->adapter;
> +	int ret = 0;
> +
> +	lbs_deb_enter(LBS_DEB_SCAN);
> +
> +	if (!netif_running(dev))
> +		return -ENETDOWN;
> +
> +	/* mac80211 does this:
> +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +	if (sdata->type != IEEE80211_IF_TYPE_xxx)
> +		return -EOPNOTSUPP;
> +
> +	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
> +	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
> +		req = (struct iw_scan_req *)extra;
> +			ssid = req->essid;
> +		ssid_len = req->essid_len;
> +	}
> +	*/
> +
> +	if (!delayed_work_pending(&priv->scan_work))
> +		queue_delayed_work(priv->work_thread, &priv->scan_work,
> +			msecs_to_jiffies(50));
> +	/* set marker that currently a scan is taking place */
> +	adapter->last_scanned_channel = -1;
> +
> +	if (adapter->surpriseremoved)
> +		return -EIO;
> +
> +	lbs_deb_leave(LBS_DEB_SCAN);
> +	return 0;
> +}
> +
> +
>  /**
>   *  @brief  Handle Retrieve scan table ioctl
>   *
> @@ -1550,6 +1402,10 @@ int lbs_get_scan(struct net_device *dev,
>  
>  	lbs_deb_enter(LBS_DEB_SCAN);
>  
> +	/* iwlist should wait until the current scan is finished */
> +	if (adapter->last_scanned_channel)
> +		return -EAGAIN;
> +
>  	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
>  	if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
>  		lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
> @@ -1607,7 +1463,8 @@ int lbs_get_scan(struct net_device *dev,
>  /**
>   *  @brief Prepare a scan command to be sent to the firmware
>   *
> - *  Called from lbs_prepare_and_send_command() in cmd.c
> + *  Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
> + *  from cmd.c
>   *
>   *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
>   *  as well as a variable number/length of TLVs to the firmware.
> @@ -1621,7 +1478,7 @@ int lbs_get_scan(struct net_device *dev,
>   *  @return           0 or -1
>   */
>  int lbs_cmd_80211_scan(struct lbs_private *priv,
> -			 struct cmd_ds_command *cmd, void *pdata_buf)
> +	struct cmd_ds_command *cmd, void *pdata_buf)
>  {
>  	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
>  	struct lbs_scan_cmd_config *pscancfg = pdata_buf;
> @@ -1633,32 +1490,14 @@ int lbs_cmd_80211_scan(struct lbs_privat
>  	memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
>  	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
>  
> -	cmd->command = cpu_to_le16(CMD_802_11_SCAN);
> -
>  	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
>  	cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
>  				+ pscancfg->tlvbufferlen + S_DS_GEN);
>  
> -	lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
> -		     le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
> -		     le16_to_cpu(cmd->seqnum));
> -
>  	lbs_deb_leave(LBS_DEB_SCAN);
>  	return 0;
>  }
>  
> -static inline int is_same_network(struct bss_descriptor *src,
> -				  struct bss_descriptor *dst)
> -{
> -	/* A network is only a duplicate if the channel, BSSID, and ESSID
> -	 * all match.  We treat all <hidden> with the same BSSID and channel
> -	 * as one network */
> -	return ((src->ssid_len == dst->ssid_len) &&
> -		(src->channel == dst->channel) &&
> -		!compare_ether_addr(src->bssid, dst->bssid) &&
> -		!memcmp(src->ssid, dst->ssid, src->ssid_len));
> -}
> -
>  /**
>   *  @brief This function handles the command response of scan
>   *
> @@ -1723,7 +1562,7 @@ int lbs_ret_80211_scan(struct lbs_privat
>  	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
>  
>  	scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
> -	lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
> +	lbs_deb_scan("SCAN_RESP: scan results %d\n",
>  	       pscan->nr_sets);
>  
>  	pbssinfo = pscan->bssdesc_and_tlvbuffer;
> @@ -1786,7 +1625,7 @@ int lbs_ret_80211_scan(struct lbs_privat
>  			continue;
>  		}
>  
> -		lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
> +		lbs_deb_scan("SCAN_RESP: BSSID %s\n",
>  			     print_mac(mac, new.bssid));
>  
>  		/* Copy the locally created newbssentry to the scan table */
> Index: wireless-2.6/drivers/net/wireless/libertas/dev.h
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:04.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:19.000000000 +0100
> @@ -363,9 +363,8 @@ struct lbs_adapter {
>  	struct cmd_ds_802_11_get_log logmsg;
>  
>  	u32 monitormode;
> +	int last_scanned_channel;
>  	u8 fw_ready;
> -
> -	u8 last_scanned_channel;
>  };
>  
>  #endif


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-11-29  8:27 [PATCH] libertas: implement new scanning logic Holger Schurig
  2007-11-29 19:38 ` Dan Williams
@ 2007-12-04 16:52 ` Dan Williams
  2007-12-04 20:34   ` Holger Schurig
  2007-12-07 14:47   ` Holger Schurig
  1 sibling, 2 replies; 14+ messages in thread
From: Dan Williams @ 2007-12-04 16:52 UTC (permalink / raw)
  To: Holger Schurig; +Cc: John W. Linville, libertas-dev, linux-wireless

On Thu, 2007-11-29 at 09:27 +0100, Holger Schurig wrote:
> This changes the code that is used for scanning and makes it hopefully
> easier to understand:
> 
> * move function into logical blocks
> * create a bunch of lbs_scan_add_XXXX_tlv() functions, that
>   help to create the TLV parameter of CMD_802_11_SCAN
> * all of them are now called from the much simpler lbs_do_scan()
> * no **puserscancfg double-pointers :-)
> 
> Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>

So I tested this one, not the one from libertas-dev (which was posted a
day earlier).  And this one seems fine.  Ack for commit to libertas-2.6.

Would you like me to confirm on SDIO?

Dan

> Index: wireless-2.6/drivers/net/wireless/libertas/scan.c
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/scan.c	2007-11-29 10:01:07.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/scan.c	2007-11-29 10:26:07.000000000 +0100
> @@ -79,6 +79,22 @@ static inline void clear_bss_descriptor 
>  	memset(bss, 0, offsetof(struct bss_descriptor, list));
>  }
>  
> +/**
> + *  @brief Compare two SSIDs
> + *
> + *  @param ssid1    A pointer to ssid to compare
> + *  @param ssid2    A pointer to ssid to compare
> + *
> + *  @return         0: ssid is same, otherwise is different
> + */
> +int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
> +{
> +	if (ssid1_len != ssid2_len)
> +		return -1;
> +
> +	return memcmp(ssid1, ssid2, ssid1_len);
> +}
> +
>  static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
>  			struct bss_descriptor * match_bss)
>  {
> @@ -149,6 +165,18 @@ static inline int match_bss_dynamic_wep(
>  	return 0;
>  }
>  
> +static inline int is_same_network(struct bss_descriptor *src,
> +				  struct bss_descriptor *dst)
> +{
> +	/* A network is only a duplicate if the channel, BSSID, and ESSID
> +	 * all match.  We treat all <hidden> with the same BSSID and channel
> +	 * as one network */
> +	return ((src->ssid_len == dst->ssid_len) &&
> +		(src->channel == dst->channel) &&
> +		!compare_ether_addr(src->bssid, dst->bssid) &&
> +		!memcmp(src->ssid, dst->ssid, src->ssid_len));
> +}
> +
>  /**
>   *  @brief Check if a scanned network compatible with the driver settings
>   *
> @@ -184,9 +212,9 @@ static int is_network_compatible(struct 
>  		goto done;
>  	} else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
> -		       "is_network_compatible() WPA: wpa_ie=%#x "
> -		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
> -		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
> +		       "is_network_compatible() WPA: wpa_ie 0x%x "
> +		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
> +		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
>  		       adapter->secinfo.wep_enabled ? "e" : "d",
>  		       adapter->secinfo.WPAenabled ? "e" : "d",
>  		       adapter->secinfo.WPA2enabled ? "e" : "d",
> @@ -194,9 +222,9 @@ static int is_network_compatible(struct 
>  		goto done;
>  	} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
> -		       "is_network_compatible() WPA2: wpa_ie=%#x "
> -		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
> -		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
> +		       "is_network_compatible() WPA2: wpa_ie 0x%x "
> +		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
> +		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
>  		       adapter->secinfo.wep_enabled ? "e" : "d",
>  		       adapter->secinfo.WPAenabled ? "e" : "d",
>  		       adapter->secinfo.WPA2enabled ? "e" : "d",
> @@ -205,7 +233,7 @@ static int is_network_compatible(struct 
>  	} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
>  		lbs_deb_scan(
>  		       "is_network_compatible() dynamic WEP: "
> -		       "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
> +		       "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
>  		       bss->wpa_ie[0], bss->rsn_ie[0],
>  		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
>  		goto done;
> @@ -213,8 +241,8 @@ static int is_network_compatible(struct 
>  
>  	/* bss security settings don't match those configured on card */
>  	lbs_deb_scan(
> -	       "is_network_compatible() FAILED: wpa_ie=%#x "
> -	       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n",
> +	       "is_network_compatible() FAILED: wpa_ie 0x%x "
> +	       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
>  	       bss->wpa_ie[0], bss->rsn_ie[0],
>  	       adapter->secinfo.wep_enabled ? "e" : "d",
>  	       adapter->secinfo.WPAenabled ? "e" : "d",
> @@ -226,22 +254,6 @@ done:
>  	return matched;
>  }
>  
> -/**
> - *  @brief Compare two SSIDs
> - *
> - *  @param ssid1    A pointer to ssid to compare
> - *  @param ssid2    A pointer to ssid to compare
> - *
> - *  @return         0--ssid is same, otherwise is different
> - */
> -int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
> -{
> -	if (ssid1_len != ssid2_len)
> -		return -1;
> -
> -	return memcmp(ssid1, ssid2, ssid1_len);
> -}
> -
>  
> 
> 
> @@ -251,6 +263,16 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
>  /*                                                                   */
>  /*********************************************************************/
>  
> +void lbs_scan_worker(struct work_struct *work)
> +{
> +	struct lbs_private *priv =
> +		container_of(work, struct lbs_private, scan_work.work);
> +
> +	lbs_deb_enter(LBS_DEB_SCAN);
> +	lbs_scan_networks(priv, NULL, 0);
> +	lbs_deb_leave(LBS_DEB_SCAN);
> +}
> +
>  
>  /**
>   *  @brief Create a channel list for the driver to scan based on region info
> @@ -271,7 +293,7 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len
>   *
>   *  @return              void
>   */
> -static void lbs_scan_create_channel_list(struct lbs_private *priv,
> +static int lbs_scan_create_channel_list(struct lbs_private *priv,
>  					  struct chanscanparamset * scanchanlist,
>  					  u8 filteredscan)
>  {
> @@ -284,8 +306,6 @@ static void lbs_scan_create_channel_list
>  	int nextchan;
>  	u8 scantype;
>  
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
> -
>  	chanidx = 0;
>  
>  	/* Set the default scan type to the user specified type, will later
> @@ -352,383 +372,147 @@ static void lbs_scan_create_channel_list
>  			}
>  		}
>  	}
> +	return chanidx;
>  }
>  
> 
> -/* Delayed partial scan worker */
> -void lbs_scan_worker(struct work_struct *work)
> +/*
> + * Add SSID TLV of the form:
> + *
> + * TLV-ID SSID     00 00
> + * length          06 00
> + * ssid            4d 4e 54 45 53 54
> + */
> +static int lbs_scan_add_ssid_tlv(u8 *tlv,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg)
>  {
> -	struct lbs_private *priv = container_of(work,
> -		struct lbs_private,
> -		scan_work.work);
> -
> -	lbs_scan_networks(priv, NULL, 0);
> +	struct mrvlietypes_ssidparamset *ssid_tlv =
> +		(struct mrvlietypes_ssidparamset *)tlv;
> +	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
> +	ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
> +	memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
> +	return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
>  }
>  
> 
> -/**
> - *  @brief Construct a lbs_scan_cmd_config structure to use in issue scan cmds
> - *
> - *  Application layer or other functions can invoke lbs_scan_networks
> - *    with a scan configuration supplied in a lbs_ioctl_user_scan_cfg struct.
> - *    This structure is used as the basis of one or many lbs_scan_cmd_config
> - *    commands that are sent to the command processing module and sent to
> - *    firmware.
> - *
> - *  Create a lbs_scan_cmd_config based on the following user supplied
> - *    parameters (if present):
> - *             - SSID filter
> - *             - BSSID filter
> - *             - Number of Probes to be sent
> - *             - channel list
> - *
> - *  If the SSID or BSSID filter is not present, disable/clear the filter.
> - *  Qualify the channel
> +/*
> + * Add CHANLIST TLV of the form
>   *
> - *  @param priv             A pointer to struct lbs_private structure
> - *  @param puserscanin      NULL or pointer to scan configuration parameters
> - *  @param ppchantlvout     Output parameter: Pointer to the start of the
> - *                          channel TLV portion of the output scan config
> - *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
> - *                          list to scan
> - *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
> - *                          each issuance of the firmware scan command
> - *  @param pfilteredscan    Output parameter: Flag indicating whether or not
> - *                          a BSSID or SSID filter is being sent in the
> - *                          command to firmware.  Used to increase the number
> - *                          of channels sent in a scan command and to
> - *                          disable the firmware channel scan filter.
> - *  @param pscancurrentonly Output parameter: Flag indicating whether or not
> - *                          we are only scanning our current active channel
> + * TLV-ID CHANLIST 01 01
> + * length          5b 00
> + * channel 1       00 01 00 00 00 64 00
> + *   radio type    00
> + *   channel          01
> + *   scan type           00
> + *   min scan time          00 00
> + *   max scan time                64 00
> + * channel 2       00 02 00 00 00 64 00
> + * channel 3       00 03 00 00 00 64 00
> + * channel 4       00 04 00 00 00 64 00
> + * channel 5       00 05 00 00 00 64 00
> + * channel 6       00 06 00 00 00 64 00
> + * channel 7       00 07 00 00 00 64 00
> + * channel 8       00 08 00 00 00 64 00
> + * channel 9       00 09 00 00 00 64 00
> + * channel 10      00 0a 00 00 00 64 00
> + * channel 11      00 0b 00 00 00 64 00
> + * channel 12      00 0c 00 00 00 64 00
> + * channel 13      00 0d 00 00 00 64 00
>   *
> - *  @return                 resulting scan configuration
>   */
> -static struct lbs_scan_cmd_config *
> -lbs_scan_setup_scan_config(struct lbs_private *priv,
> -			    const struct lbs_ioctl_user_scan_cfg *puserscanin,
> -			    struct mrvlietypes_chanlistparamset ** ppchantlvout,
> -			    struct chanscanparamset * pscanchanlist,
> -			    int *pmaxchanperscan,
> -			    u8 * pfilteredscan,
> -			    u8 * pscancurrentonly)
> +static int lbs_scan_add_chanlist_tlv(u8 *tlv,
> +	struct chanscanparamset *chan_list,
> +	int chan_count)
>  {
> -	struct mrvlietypes_ssidparamset *pssidtlv;
> -	struct lbs_scan_cmd_config *pscancfgout = NULL;
> -	u8 *ptlvpos;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
> -	if (pscancfgout == NULL)
> -		goto out;
> -
> -	/* The tlvbufferlen is calculated for each scan command.  The TLVs added
> -	 *   in this routine will be preserved since the routine that sends
> -	 *   the command will append channelTLVs at *ppchantlvout.  The difference
> -	 *   between the *ppchantlvout and the tlvbuffer start will be used
> -	 *   to calculate the size of anything we add in this routine.
> -	 */
> -	pscancfgout->tlvbufferlen = 0;
> -
> -	/* Running tlv pointer.  Assigned to ppchantlvout at end of function
> -	 *  so later routines know where channels can be added to the command buf
> -	 */
> -	ptlvpos = pscancfgout->tlvbuffer;
> -
> -	/*
> -	 * Set the initial scan paramters for progressive scanning.  If a specific
> -	 *   BSSID or SSID is used, the number of channels in the scan command
> -	 *   will be increased to the absolute maximum
> -	 */
> -	*pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
> -
> -	/* Initialize the scan as un-filtered by firmware, set to TRUE below if
> -	 *   a SSID or BSSID filter is sent in the command
> -	 */
> -	*pfilteredscan = 0;
> -
> -	/* Initialize the scan as not being only on the current channel.  If
> -	 *   the channel list is customized, only contains one channel, and
> -	 *   is the active channel, this is set true and data flow is not halted.
> -	 */
> -	*pscancurrentonly = 0;
> -
> -	if (puserscanin) {
> -		/* Set the bss type scan filter, use adapter setting if unset */
> -		pscancfgout->bsstype =
> -		    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
> -
> -		/*
> -		 * Set the BSSID filter to the incoming configuration,
> -		 *   if non-zero.  If not set, it will remain disabled (all zeros).
> -		 */
> -		memcpy(pscancfgout->bssid, puserscanin->bssid,
> -		       sizeof(pscancfgout->bssid));
> -
> -		if (puserscanin->ssid_len) {
> -			pssidtlv =
> -			    (struct mrvlietypes_ssidparamset *) pscancfgout->
> -			    tlvbuffer;
> -			pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
> -			pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
> -			memcpy(pssidtlv->ssid, puserscanin->ssid,
> -			       puserscanin->ssid_len);
> -			ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
> -		}
> -
> -		/*
> -		 *  The default number of channels sent in the command is low to
> -		 *    ensure the response buffer from the firmware does not truncate
> -		 *    scan results.  That is not an issue with an SSID or BSSID
> -		 *    filter applied to the scan results in the firmware.
> -		 */
> -		if (   puserscanin->ssid_len
> -		    || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
> -			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
> -			*pfilteredscan = 1;
> -		}
> -	} else {
> -		pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
> -	}
> -
> -	/*
> -	 * Set the output for the channel TLV to the address in the tlv buffer
> -	 *   past any TLVs that were added in this fuction (SSID).
> -	 *   channel TLVs will be added past this for each scan command, preserving
> -	 *   the TLVs that were previously added.
> -	 */
> -	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
> +	size_t size = sizeof(struct chanscanparamset) * chan_count;
> +	struct mrvlietypes_chanlistparamset *chan_tlv =
> +		(struct mrvlietypes_chanlistparamset *) tlv;
>  
> -	lbs_scan_create_channel_list(priv, pscanchanlist,
> -				      *pfilteredscan);
> -out:
> -	return pscancfgout;
> +	chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
> +	memcpy(chan_tlv->chanscanparam, chan_list, size);
> +	chan_tlv->header.len = cpu_to_le16(size);
> +	return sizeof(chan_tlv->header) + size;
>  }
>  
> -/**
> - *  @brief Construct and send multiple scan config commands to the firmware
> - *
> - *  Only used from lbs_scan_networks()
> - *
> - *  Previous routines have created a lbs_scan_cmd_config with any requested
> - *   TLVs.  This function splits the channel TLV into maxchanperscan lists
> - *   and sends the portion of the channel TLV along with the other TLVs
> - *   to the lbs_cmd routines for execution in the firmware.
> +
> +/*
> + * Add RATES TLV of the form
>   *
> - *  @param priv            A pointer to struct lbs_private structure
> - *  @param maxchanperscan  Maximum number channels to be included in each
> - *                         scan command sent to firmware
> - *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
> - *                         filter is being used for the firmware command
> - *                         scan command sent to firmware
> - *  @param pscancfgout     Scan configuration used for this scan.
> - *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
> - *                         should start.  This is past any other TLVs that
> - *                         must be sent down in each firmware command.
> - *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
> + * TLV-ID RATES    01 00
> + * length          0e 00
> + * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
>   *
> - *  @return                0 or error return otherwise
> + * The rates are in lbs_bg_rates[], but for the 802.11b
> + * rates the high bit isn't set.
>   */
> -static int lbs_scan_channel_list(struct lbs_private *priv,
> -				  int maxchanperscan,
> -				  u8 filteredscan,
> -				  struct lbs_scan_cmd_config *pscancfgout,
> -				  struct mrvlietypes_chanlistparamset * pchantlvout,
> -				  struct chanscanparamset * pscanchanlist,
> -				  const struct lbs_ioctl_user_scan_cfg *puserscanin,
> -				  int full_scan)
> +static int lbs_scan_add_rates_tlv(u8 *tlv)
>  {
> -	struct chanscanparamset *ptmpchan;
> -	struct chanscanparamset *pstartchan;
> -	u8 scanband;
> -	int doneearly;
> -	int tlvidx;
> -	int ret = 0;
> -	int scanned = 0;
> -	union iwreq_data wrqu;
> -
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
> -		"full_scan %d", maxchanperscan, filteredscan, full_scan);
> -
> -	if (!pscancfgout || !pchantlvout || !pscanchanlist) {
> -		lbs_deb_scan("pscancfgout, pchantlvout or "
> -			"pscanchanlist is NULL\n");
> -		ret = -1;
> -		goto out;
> -	}
> -
> -	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
> -
> -	/* Set the temp channel struct pointer to the start of the desired list */
> -	ptmpchan = pscanchanlist;
> -
> -	if (priv->adapter->last_scanned_channel && !puserscanin)
> -		ptmpchan += priv->adapter->last_scanned_channel;
> -
> -	/* Loop through the desired channel list, sending a new firmware scan
> -	 *   commands for each maxchanperscan channels (or for 1,6,11 individually
> -	 *   if configured accordingly)
> -	 */
> -	while (ptmpchan->channumber) {
> -
> -		tlvidx = 0;
> -		pchantlvout->header.len = 0;
> -		scanband = ptmpchan->radiotype;
> -		pstartchan = ptmpchan;
> -		doneearly = 0;
> -
> -		/* Construct the channel TLV for the scan command.  Continue to
> -		 *  insert channel TLVs until:
> -		 *    - the tlvidx hits the maximum configured per scan command
> -		 *    - the next channel to insert is 0 (end of desired channel list)
> -		 *    - doneearly is set (controlling individual scanning of 1,6,11)
> -		 */
> -		while (tlvidx < maxchanperscan && ptmpchan->channumber
> -		       && !doneearly && scanned < 2) {
> -
> -			lbs_deb_scan("channel %d, radio %d, passive %d, "
> -				"dischanflt %d, maxscantime %d\n",
> -				ptmpchan->channumber,
> -				ptmpchan->radiotype,
> -			             ptmpchan->chanscanmode.passivescan,
> -			             ptmpchan->chanscanmode.disablechanfilt,
> -			             ptmpchan->maxscantime);
> -
> -			/* Copy the current channel TLV to the command being prepared */
> -			memcpy(pchantlvout->chanscanparam + tlvidx,
> -			       ptmpchan, sizeof(pchantlvout->chanscanparam));
> -
> -			/* Increment the TLV header length by the size appended */
> -			/* Ew, it would be _so_ nice if we could just declare the
> -			   variable little-endian and let GCC handle it for us */
> -			pchantlvout->header.len =
> -				cpu_to_le16(le16_to_cpu(pchantlvout->header.len) +
> -					    sizeof(pchantlvout->chanscanparam));
> -
> -			/*
> -			 *  The tlv buffer length is set to the number of bytes of the
> -			 *    between the channel tlv pointer and the start of the
> -			 *    tlv buffer.  This compensates for any TLVs that were appended
> -			 *    before the channel list.
> -			 */
> -			pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
> -						     - pscancfgout->tlvbuffer);
> -
> -			/*  Add the size of the channel tlv header and the data length */
> -			pscancfgout->tlvbufferlen +=
> -			    (sizeof(pchantlvout->header)
> -			     + le16_to_cpu(pchantlvout->header.len));
> -
> -			/* Increment the index to the channel tlv we are constructing */
> -			tlvidx++;
> -
> -			doneearly = 0;
> -
> -			/* Stop the loop if the *current* channel is in the 1,6,11 set
> -			 *   and we are not filtering on a BSSID or SSID.
> -			 */
> -			if (!filteredscan && (ptmpchan->channumber == 1
> -					      || ptmpchan->channumber == 6
> -					      || ptmpchan->channumber == 11)) {
> -				doneearly = 1;
> -			}
> -
> -			/* Increment the tmp pointer to the next channel to be scanned */
> -			ptmpchan++;
> -			scanned++;
> -
> -			/* Stop the loop if the *next* channel is in the 1,6,11 set.
> -			 *  This will cause it to be the only channel scanned on the next
> -			 *  interation
> -			 */
> -			if (!filteredscan && (ptmpchan->channumber == 1
> -					      || ptmpchan->channumber == 6
> -					      || ptmpchan->channumber == 11)) {
> -				doneearly = 1;
> -			}
> -		}
> -
> -		/* Send the scan command to the firmware with the specified cfg */
> -		ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
> -					    0, 0, pscancfgout);
> -		if (scanned >= 2 && !full_scan) {
> -			ret = 0;
> -			goto done;
> -		}
> -		scanned = 0;
> -	}
> -
> -done:
> -	priv->adapter->last_scanned_channel = ptmpchan->channumber;
> +	int i;
> +	struct mrvlietypes_ratesparamset *rate_tlv =
> +		(struct mrvlietypes_ratesparamset *) tlv;
>  
> -	if (priv->adapter->last_scanned_channel) {
> -		/* Schedule the next part of the partial scan */
> -		if (!full_scan && !priv->adapter->surpriseremoved) {
> -			cancel_delayed_work(&priv->scan_work);
> -			queue_delayed_work(priv->work_thread, &priv->scan_work,
> -			                   msecs_to_jiffies(300));
> -		}
> -	} else {
> -		/* All done, tell userspace the scan table has been updated */
> -		memset(&wrqu, 0, sizeof(union iwreq_data));
> -		wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
> +	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
> +	tlv += sizeof(rate_tlv->header);
> +	for (i = 0; i < MAX_RATES; i++) {
> +		*tlv = lbs_bg_rates[i];
> +		if (*tlv == 0)
> +			break;
> +		if (*tlv == 0x02 || *tlv == 0x04 ||
> +		    *tlv == 0x0b || *tlv == 0x16)
> +			*tlv |= 0x80;
> +		tlv++;
>  	}
> -
> -out:
> -	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> -	return ret;
> +	rate_tlv->header.len = i;
> +	return sizeof(rate_tlv->header) + i;
>  }
>  
> +
>  /*
> - * Only used from lbs_scan_networks()
> -*/
> -static void clear_selected_scan_list_entries(struct lbs_adapter *adapter,
> -	const struct lbs_ioctl_user_scan_cfg *scan_cfg)
> + * Generate the CMD_802_11_SCAN command with the proper tlv
> + * for a bunch of channels.
> + */
> +static int lbs_do_scan(struct lbs_private *priv,
> +	u8 bsstype,
> +	struct chanscanparamset *chan_list,
> +	int chan_count,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg)
>  {
> -	struct bss_descriptor *bss;
> -	struct bss_descriptor *safe;
> -	u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	if (!scan_cfg)
> -		goto out;
> -
> -	if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
> -		clear_ssid_flag = 1;
> +	int ret = -ENOMEM;
> +	struct lbs_scan_cmd_config *scan_cmd;
> +	u8 *tlv;    /* pointer into our current, growing TLV storage area */
>  
> -	if (scan_cfg->clear_bssid
> -	    && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0)
> -	    && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) {
> -		clear_bssid_flag = 1;
> -	}
> +	lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
> +		"chan_count %d",
> +		bsstype, chan_list[0].channumber, chan_count);
>  
> -	if (!clear_ssid_flag && !clear_bssid_flag)
> +	/* create the fixed part for scan command */
> +	scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
> +	if (scan_cmd == NULL)
>  		goto out;
> +	tlv = scan_cmd->tlvbuffer;
> +	if (user_cfg)
> +		memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
> +	scan_cmd->bsstype = bsstype;
>  
> -	mutex_lock(&adapter->lock);
> -	list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
> -		u32 clear = 0;
> -
> -		/* Check for an SSID match */
> -		if (   clear_ssid_flag
> -		    && (bss->ssid_len == scan_cfg->ssid_len)
> -		    && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len))
> -			clear = 1;
> +	/* add TLVs */
> +	if (user_cfg && user_cfg->ssid_len)
> +		tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
> +	if (chan_list && chan_count)
> +		tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
> +	tlv += lbs_scan_add_rates_tlv(tlv);
>  
> -		/* Check for a BSSID match */
> -		if (   clear_bssid_flag
> -		    && !compare_ether_addr(bss->bssid, scan_cfg->bssid))
> -			clear = 1;
> +	/* This is the final data we are about to send */
> +	scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
> +	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
> +	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
> +		scan_cmd->tlvbufferlen);
>  
> -		if (clear) {
> -			list_move_tail (&bss->list, &adapter->network_free_list);
> -			clear_bss_descriptor(bss);
> -		}
> -	}
> -	mutex_unlock(&adapter->lock);
> +	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
> +		CMD_OPTION_WAITFORRSP, 0, scan_cmd);
>  out:
> -	lbs_deb_leave(LBS_DEB_SCAN);
> +	kfree(scan_cmd);
> +	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> +	return ret;
>  }
>  
> 
> @@ -744,29 +528,30 @@ out:
>   *  @param priv          A pointer to struct lbs_private structure
>   *  @param puserscanin   Pointer to the input configuration for the requested
>   *                       scan.
> - *  @param full_scan     ???
>   *
>   *  @return              0 or < 0 if error
>   */
>  int lbs_scan_networks(struct lbs_private *priv,
> -	const struct lbs_ioctl_user_scan_cfg *puserscanin,
> +	const struct lbs_ioctl_user_scan_cfg *user_cfg,
>                         int full_scan)
>  {
>  	struct lbs_adapter *adapter = priv->adapter;
> -	struct mrvlietypes_chanlistparamset *pchantlvout;
> -	struct chanscanparamset * scan_chan_list = NULL;
> -	struct lbs_scan_cmd_config *scan_cfg = NULL;
> -	u8 filteredscan;
> -	u8 scancurrentchanonly;
> -	int maxchanperscan;
> -	int ret;
> +	int ret = -ENOMEM;
> +	struct chanscanparamset *chan_list;
> +	struct chanscanparamset *curr_chans;
> +	int chan_count;
> +	u8 bsstype = CMD_BSS_TYPE_ANY;
> +	int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
> +	int filteredscan = 0;
> +	union iwreq_data wrqu;
>  #ifdef CONFIG_LIBERTAS_DEBUG
> -	struct bss_descriptor * iter_bss;
> +	struct bss_descriptor *iter;
>  	int i = 0;
>  	DECLARE_MAC_BUF(mac);
>  #endif
>  
> -	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
> +	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
> +		full_scan);
>  
>  	/* Cancel any partial outstanding partial scans if this scan
>  	 * is a full scan.
> @@ -774,84 +559,122 @@ int lbs_scan_networks(struct lbs_private
>  	if (full_scan && delayed_work_pending(&priv->scan_work))
>  		cancel_delayed_work(&priv->scan_work);
>  
> -	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
> -				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
> -	if (scan_chan_list == NULL) {
> -		ret = -ENOMEM;
> -		goto out;
> +	/* Determine same scan parameters */
> +	if (user_cfg) {
> +		if (user_cfg->bsstype)
> +			bsstype = user_cfg->bsstype;
> +		if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
> +			numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
> +			filteredscan = 1;
> +		}
>  	}
> +	lbs_deb_scan("numchannels %d, bsstype %d, "
> +		"filteredscan %d\n",
> +		numchannels, bsstype, filteredscan);
>  
> -	scan_cfg = lbs_scan_setup_scan_config(priv,
> -					       puserscanin,
> -					       &pchantlvout,
> -					       scan_chan_list,
> -					       &maxchanperscan,
> -					       &filteredscan,
> -					       &scancurrentchanonly);
> -	if (scan_cfg == NULL) {
> -		ret = -ENOMEM;
> +	/* Create list of channels to scan */
> +	chan_list = kzalloc(sizeof(struct chanscanparamset) *
> +				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
> +	if (!chan_list) {
> +		lbs_pr_alert("SCAN: chan_list empty\n");
>  		goto out;
>  	}
>  
> -	clear_selected_scan_list_entries(adapter, puserscanin);
> +	/* We want to scan all channels */
> +	chan_count = lbs_scan_create_channel_list(priv, chan_list,
> +		filteredscan);
>  
> -	/* Keep the data path active if we are only scanning our current channel */
> -	if (!scancurrentchanonly) {
> -		netif_stop_queue(priv->dev);
> -		netif_carrier_off(priv->dev);
> -		if (priv->mesh_dev) {
> +	netif_stop_queue(priv->dev);
> +	if (priv->mesh_dev)
>  			netif_stop_queue(priv->mesh_dev);
> -			netif_carrier_off(priv->mesh_dev);
> -		}
> +
> +	/* Prepare to continue an interrupted scan */
> +	lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
> +		chan_count, adapter->last_scanned_channel);
> +	curr_chans = chan_list;
> +	/* advance channel list by already-scanned-channels */
> +	if (adapter->last_scanned_channel > 0) {
> +		curr_chans += adapter->last_scanned_channel;
> +		chan_count -= adapter->last_scanned_channel;
>  	}
>  
> -	ret = lbs_scan_channel_list(priv,
> -				     maxchanperscan,
> -				     filteredscan,
> -				     scan_cfg,
> -				     pchantlvout,
> -				     scan_chan_list,
> -				     puserscanin,
> -				     full_scan);
> +	/* Send scan command(s)
> +	 * numchannels contains the number of channels we should maximally scan
> +	 * chan_count is the total number of channels to scan
> +	 */
> +
> +	while (chan_count) {
> +		int to_scan = min(numchannels, chan_count);
> +		lbs_deb_scan("scanning %d of %d channels\n",
> +			to_scan, chan_count);
> +		ret = lbs_do_scan(priv, bsstype, curr_chans,
> +			to_scan, user_cfg);
> +		if (ret) {
> +			lbs_pr_err("SCAN_CMD failed\n");
> +			goto out2;
> +		}
> +		curr_chans += to_scan;
> +		chan_count -= to_scan;
> +
> +		/* somehow schedule the next part of the scan */
> +		if (chan_count &&
> +		    !full_scan &&
> +		    !priv->adapter->surpriseremoved) {
> +			/* -1 marks just that we're currently scanning */
> +			if (adapter->last_scanned_channel < 0)
> +				adapter->last_scanned_channel = to_scan;
> +			else
> +				adapter->last_scanned_channel += to_scan;
> +			cancel_delayed_work(&priv->scan_work);
> +			queue_delayed_work(priv->work_thread, &priv->scan_work,
> +				msecs_to_jiffies(300));
> +			/* skip over GIWSCAN event */
> +			goto out;
> +		}
> +
> +	}
> +	memset(&wrqu, 0, sizeof(union iwreq_data));
> +	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
>  
>  #ifdef CONFIG_LIBERTAS_DEBUG
>  	/* Dump the scan table */
>  	mutex_lock(&adapter->lock);
> -	lbs_deb_scan("The scan table contains:\n");
> -	list_for_each_entry (iter_bss, &adapter->network_list, list) {
> -		lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
> -		       i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
> -		       escape_essid(iter_bss->ssid, iter_bss->ssid_len));
> -	}
> +	lbs_deb_scan("scan table:\n");
> +	list_for_each_entry(iter, &adapter->network_list, list)
> +		lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
> +		       i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
> +		       escape_essid(iter->ssid, iter->ssid_len));
>  	mutex_unlock(&adapter->lock);
>  #endif
>  
> -	if (priv->adapter->connect_status == LBS_CONNECTED) {
> -		netif_carrier_on(priv->dev);
> -		netif_wake_queue(priv->dev);
> -		if (priv->mesh_dev) {
> -			netif_carrier_on(priv->mesh_dev);
> -			netif_wake_queue(priv->mesh_dev);
> -		}
> -	}
> +out2:
> +	adapter->last_scanned_channel = 0;
>  
>  out:
> -	if (scan_cfg)
> -		kfree(scan_cfg);
> -
> -	if (scan_chan_list)
> -		kfree(scan_chan_list);
> +	netif_start_queue(priv->dev);
> +	if (priv->mesh_dev)
> +		netif_start_queue(priv->mesh_dev);
> +	kfree(chan_list);
>  
>  	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
>  	return ret;
>  }
>  
> +
> +
> +
> +/*********************************************************************/
> +/*                                                                   */
> +/*  Result interpretation                                            */
> +/*                                                                   */
> +/*********************************************************************/
> +
>  /**
>   *  @brief Interpret a BSS scan response returned from the firmware
>   *
>   *  Parse the various fixed fields and IEs passed back for a a BSS probe
> - *   response or beacon from the scan command.  Record information as needed
> - *   in the scan table struct bss_descriptor for that entry.
> + *  response or beacon from the scan command.  Record information as needed
> + *  in the scan table struct bss_descriptor for that entry.
>   *
>   *  @param bss  Output parameter: Pointer to the BSS Entry
>   *
> @@ -896,7 +719,7 @@ static int lbs_process_bss(struct bss_de
>  	*bytesleft -= beaconsize;
>  
>  	memcpy(bss->bssid, pos, ETH_ALEN);
> -	lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
> +	lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
>  	pos += ETH_ALEN;
>  
>  	if ((end - pos) < 12) {
> @@ -912,7 +735,7 @@ static int lbs_process_bss(struct bss_de
>  
>  	/* RSSI is 1 byte long */
>  	bss->rssi = *pos;
> -	lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
> +	lbs_deb_scan("process_bss: RSSI %d\n", *pos);
>  	pos++;
>  
>  	/* time stamp is 8 bytes long */
> @@ -924,18 +747,18 @@ static int lbs_process_bss(struct bss_de
>  
>  	/* capability information is 2 bytes long */
>  	bss->capability = le16_to_cpup((void *) pos);
> -	lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
> +	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
>  	pos += 2;
>  
>  	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
> -		lbs_deb_scan("process_bss: AP WEP enabled\n");
> +		lbs_deb_scan("process_bss: WEP enabled\n");
>  	if (bss->capability & WLAN_CAPABILITY_IBSS)
>  		bss->mode = IW_MODE_ADHOC;
>  	else
>  		bss->mode = IW_MODE_INFRA;
>  
>  	/* rest of the current buffer are IE's */
> -	lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
> +	lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
>  	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
>  
>  	/* process variable IE */
> @@ -953,7 +776,7 @@ static int lbs_process_bss(struct bss_de
>  		case MFIE_TYPE_SSID:
>  			bss->ssid_len = elem->len;
>  			memcpy(bss->ssid, elem->data, elem->len);
> -			lbs_deb_scan("ssid '%s', ssid length %u\n",
> +			lbs_deb_scan("got SSID IE: '%s', len %u\n",
>  			             escape_essid(bss->ssid, bss->ssid_len),
>  			             bss->ssid_len);
>  			break;
> @@ -962,16 +785,14 @@ static int lbs_process_bss(struct bss_de
>  			n_basic_rates = min_t(u8, MAX_RATES, elem->len);
>  			memcpy(bss->rates, elem->data, n_basic_rates);
>  			got_basic_rates = 1;
> +			lbs_deb_scan("got RATES IE\n");
>  			break;
>  
>  		case MFIE_TYPE_FH_SET:
>  			pFH = (struct ieeetypes_fhparamset *) pos;
>  			memmove(&bss->phyparamset.fhparamset, pFH,
>  				sizeof(struct ieeetypes_fhparamset));
> -#if 0 /* I think we can store these LE */
> -			bss->phyparamset.fhparamset.dwelltime
> -			    = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);
> -#endif
> +			lbs_deb_scan("got FH IE\n");
>  			break;
>  
>  		case MFIE_TYPE_DS_SET:
> @@ -979,12 +800,14 @@ static int lbs_process_bss(struct bss_de
>  			bss->channel = pDS->currentchan;
>  			memcpy(&bss->phyparamset.dsparamset, pDS,
>  			       sizeof(struct ieeetypes_dsparamset));
> +			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
>  			break;
>  
>  		case MFIE_TYPE_CF_SET:
>  			pCF = (struct ieeetypes_cfparamset *) pos;
>  			memcpy(&bss->ssparamset.cfparamset, pCF,
>  			       sizeof(struct ieeetypes_cfparamset));
> +			lbs_deb_scan("got CF IE\n");
>  			break;
>  
>  		case MFIE_TYPE_IBSS_SET:
> @@ -992,18 +815,16 @@ static int lbs_process_bss(struct bss_de
>  			bss->atimwindow = le32_to_cpu(pibss->atimwindow);
>  			memmove(&bss->ssparamset.ibssparamset, pibss,
>  				sizeof(struct ieeetypes_ibssparamset));
> -#if 0
> -			bss->ssparamset.ibssparamset.atimwindow
> -			    = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);
> -#endif
> +			lbs_deb_scan("got IBSS IE\n");
>  			break;
>  
>  		case MFIE_TYPE_COUNTRY:
>  			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
> +			lbs_deb_scan("got COUNTRY IE\n");
>  			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
>  			    || pcountryinfo->len > 254) {
>  				lbs_deb_scan("process_bss: 11D- Err "
> -				       "CountryInfo len =%d min=%zd max=254\n",
> +				       "CountryInfo len %d, min %zd, max 254\n",
>  				       pcountryinfo->len,
>  				       sizeof(pcountryinfo->countrycode));
>  				ret = -1;
> @@ -1022,8 +843,11 @@ static int lbs_process_bss(struct bss_de
>  			 * already found. Data rate IE should come before
>  			 * extended supported rate IE
>  			 */
> -			if (!got_basic_rates)
> +			lbs_deb_scan("got RATESEX IE\n");
> +			if (!got_basic_rates) {
> +				lbs_deb_scan("... but ignoring it\n");
>  				break;
> +			}
>  
>  			n_ex_rates = elem->len;
>  			if (n_basic_rates + n_ex_rates > MAX_RATES)
> @@ -1042,24 +866,36 @@ static int lbs_process_bss(struct bss_de
>  				bss->wpa_ie_len = min(elem->len + 2,
>  				                      MAX_WPA_IE_LEN);
>  				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
> -				lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
> +				lbs_deb_scan("got WPA IE\n");
> +				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
>  				            elem->len);
>  			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
>  			    elem->data[0] == 0x00 &&
>  			    elem->data[1] == 0x50 &&
>  			    elem->data[2] == 0x43 &&
>  			    elem->data[3] == 0x04) {
> +				lbs_deb_scan("got mesh IE\n");
>  				bss->mesh = 1;
> +			} else {
> +				lbs_deb_scan("got generiec IE: "
> +					"%02x:%02x:%02x:%02x, len %d\n",
> +					elem->data[0], elem->data[1],
> +					elem->data[2], elem->data[3],
> +					elem->len);
>  			}
>  			break;
>  
>  		case MFIE_TYPE_RSN:
> +			lbs_deb_scan("got RSN IE\n");
>  			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
>  			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
> -			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
> +			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
> +				bss->rsn_ie, elem->len);
>  			break;
>  
>  		default:
> +			lbs_deb_scan("got IE 0x%04x, len %d\n",
> +				elem->id, elem->len);
>  			break;
>  		}
>  
> @@ -1271,8 +1107,6 @@ int lbs_find_best_network_ssid(struct lb
>  	if (adapter->surpriseremoved)
>  		goto out;
>  
> -	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
> -
>  	found = lbs_find_best_ssid_in_list(adapter, preferred_mode);
>  	if (found && (found->ssid_len > 0)) {
>  		memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
> @@ -1286,36 +1120,6 @@ out:
>  	return ret;
>  }
>  
> -/**
> - *  @brief Scan Network
> - *
> - *  @param dev          A pointer to net_device structure
> - *  @param info         A pointer to iw_request_info structure
> - *  @param vwrq         A pointer to iw_param structure
> - *  @param extra        A pointer to extra data buf
> - *
> - *  @return             0 --success, otherwise fail
> - */
> -int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
> -		  struct iw_param *vwrq, char *extra)
> -{
> -	struct lbs_private *priv = dev->priv;
> -	struct lbs_adapter *adapter = priv->adapter;
> -
> -	lbs_deb_enter(LBS_DEB_SCAN);
> -
> -	if (!delayed_work_pending(&priv->scan_work)) {
> -		queue_delayed_work(priv->work_thread, &priv->scan_work,
> -		                   msecs_to_jiffies(50));
> -	}
> -
> -	if (adapter->surpriseremoved)
> -		return -1;
> -
> -	lbs_deb_leave(LBS_DEB_SCAN);
> -	return 0;
> -}
> -
>  
>  /**
>   *  @brief Send a scan command for all available channels filtered on a spec
> @@ -1327,8 +1131,6 @@ int lbs_set_scan(struct net_device *dev,
>   *  @param ssid_len         Length of the SSID
>   *  @param clear_ssid       Should existing scan results with this SSID
>   *                          be cleared?
> - *  @param prequestedssid   A pointer to AP's ssid
> - *  @param keeppreviousscan Flag used to save/clear scan table before scan
>   *
>   *  @return                0-success, otherwise fail
>   */
> @@ -1355,7 +1157,6 @@ int lbs_send_specific_ssid_scan(struct l
>  		ret = -1;
>  		goto out;
>  	}
> -	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
>  
>  out:
>  	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
> @@ -1371,6 +1172,7 @@ out:
>  /*                                                                   */
>  /*********************************************************************/
>  
> +
>  #define MAX_CUSTOM_LEN 64
>  
>  static inline char *lbs_translate_scan(struct lbs_private *priv,
> @@ -1396,7 +1198,7 @@ static inline char *lbs_translate_scan(s
>  		goto out;
>  	}
>  
> -	/* First entry *MUST* be the AP BSSID */
> +	/* First entry *MUST* be the BSSID */
>  	iwe.cmd = SIOCGIWAP;
>  	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
>  	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
> @@ -1526,6 +1328,56 @@ out:
>  	return start;
>  }
>  
> +
> +/**
> + *  @brief Handle Scan Network ioctl
> + *
> + *  @param dev          A pointer to net_device structure
> + *  @param info         A pointer to iw_request_info structure
> + *  @param vwrq         A pointer to iw_param structure
> + *  @param extra        A pointer to extra data buf
> + *
> + *  @return             0 --success, otherwise fail
> + */
> +int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
> +		  struct iw_param *wrqu, char *extra)
> +{
> +	struct lbs_private *priv = dev->priv;
> +	struct lbs_adapter *adapter = priv->adapter;
> +	int ret = 0;
> +
> +	lbs_deb_enter(LBS_DEB_SCAN);
> +
> +	if (!netif_running(dev))
> +		return -ENETDOWN;
> +
> +	/* mac80211 does this:
> +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +	if (sdata->type != IEEE80211_IF_TYPE_xxx)
> +		return -EOPNOTSUPP;
> +
> +	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
> +	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
> +		req = (struct iw_scan_req *)extra;
> +			ssid = req->essid;
> +		ssid_len = req->essid_len;
> +	}
> +	*/
> +
> +	if (!delayed_work_pending(&priv->scan_work))
> +		queue_delayed_work(priv->work_thread, &priv->scan_work,
> +			msecs_to_jiffies(50));
> +	/* set marker that currently a scan is taking place */
> +	adapter->last_scanned_channel = -1;
> +
> +	if (adapter->surpriseremoved)
> +		return -EIO;
> +
> +	lbs_deb_leave(LBS_DEB_SCAN);
> +	return 0;
> +}
> +
> +
>  /**
>   *  @brief  Handle Retrieve scan table ioctl
>   *
> @@ -1550,6 +1402,10 @@ int lbs_get_scan(struct net_device *dev,
>  
>  	lbs_deb_enter(LBS_DEB_SCAN);
>  
> +	/* iwlist should wait until the current scan is finished */
> +	if (adapter->last_scanned_channel)
> +		return -EAGAIN;
> +
>  	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
>  	if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
>  		lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
> @@ -1607,7 +1463,8 @@ int lbs_get_scan(struct net_device *dev,
>  /**
>   *  @brief Prepare a scan command to be sent to the firmware
>   *
> - *  Called from lbs_prepare_and_send_command() in cmd.c
> + *  Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
> + *  from cmd.c
>   *
>   *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
>   *  as well as a variable number/length of TLVs to the firmware.
> @@ -1621,7 +1478,7 @@ int lbs_get_scan(struct net_device *dev,
>   *  @return           0 or -1
>   */
>  int lbs_cmd_80211_scan(struct lbs_private *priv,
> -			 struct cmd_ds_command *cmd, void *pdata_buf)
> +	struct cmd_ds_command *cmd, void *pdata_buf)
>  {
>  	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
>  	struct lbs_scan_cmd_config *pscancfg = pdata_buf;
> @@ -1633,32 +1490,14 @@ int lbs_cmd_80211_scan(struct lbs_privat
>  	memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
>  	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
>  
> -	cmd->command = cpu_to_le16(CMD_802_11_SCAN);
> -
>  	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
>  	cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
>  				+ pscancfg->tlvbufferlen + S_DS_GEN);
>  
> -	lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
> -		     le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
> -		     le16_to_cpu(cmd->seqnum));
> -
>  	lbs_deb_leave(LBS_DEB_SCAN);
>  	return 0;
>  }
>  
> -static inline int is_same_network(struct bss_descriptor *src,
> -				  struct bss_descriptor *dst)
> -{
> -	/* A network is only a duplicate if the channel, BSSID, and ESSID
> -	 * all match.  We treat all <hidden> with the same BSSID and channel
> -	 * as one network */
> -	return ((src->ssid_len == dst->ssid_len) &&
> -		(src->channel == dst->channel) &&
> -		!compare_ether_addr(src->bssid, dst->bssid) &&
> -		!memcmp(src->ssid, dst->ssid, src->ssid_len));
> -}
> -
>  /**
>   *  @brief This function handles the command response of scan
>   *
> @@ -1723,7 +1562,7 @@ int lbs_ret_80211_scan(struct lbs_privat
>  	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
>  
>  	scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
> -	lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
> +	lbs_deb_scan("SCAN_RESP: scan results %d\n",
>  	       pscan->nr_sets);
>  
>  	pbssinfo = pscan->bssdesc_and_tlvbuffer;
> @@ -1786,7 +1625,7 @@ int lbs_ret_80211_scan(struct lbs_privat
>  			continue;
>  		}
>  
> -		lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
> +		lbs_deb_scan("SCAN_RESP: BSSID %s\n",
>  			     print_mac(mac, new.bssid));
>  
>  		/* Copy the locally created newbssentry to the scan table */
> Index: wireless-2.6/drivers/net/wireless/libertas/dev.h
> ===================================================================
> --- wireless-2.6.orig/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:04.000000000 +0100
> +++ wireless-2.6/drivers/net/wireless/libertas/dev.h	2007-11-29 10:13:19.000000000 +0100
> @@ -363,9 +363,8 @@ struct lbs_adapter {
>  	struct cmd_ds_802_11_get_log logmsg;
>  
>  	u32 monitormode;
> +	int last_scanned_channel;
>  	u8 fw_ready;
> -
> -	u8 last_scanned_channel;
>  };
>  
>  #endif


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-04 16:52 ` Dan Williams
@ 2007-12-04 20:34   ` Holger Schurig
  2007-12-07 14:47   ` Holger Schurig
  1 sibling, 0 replies; 14+ messages in thread
From: Holger Schurig @ 2007-12-04 20:34 UTC (permalink / raw)
  To: Dan Williams; +Cc: John W. Linville, libertas-dev, linux-wireless

> So I tested this one, not the one from libertas-dev (which was posted
> a day earlier).  And this one seems fine.  Ack for commit to
> libertas-2.6.

Hmm, for the patch you just "acked" inofficially is already older.
I know at least two changes that I made since then:

* add a comment to the section where I change the basic rates by
  setting the high bit (your idea)

* adapt to the patch "ibertas: separate mesh connectivity from that
  of the main interface" that appeared in wireless-2.6/everything

Please note that my current patch doesn't apply anymore to 
wireless-2.6/everything (a.k.a wl26e). It might still apply to 
libertas-2.6, because this tree lacked (four hours ago) at least 4 
patches that are in wl26e.

>From the 40 mails about git, commits, patches, rebases etc I was not 
able to draw a real conclusion. I'm tending towards basing my patches 
against wl26e, so that John, Jeff etc can push the patches easily up. 
And if a patch still applies, I can commit/push the patch once you 
acked them. If the patch doesn't apply there, I'll post about this face 
in libertas-dev. I hope that helps all sides the most.


> Would you like me to confirm on SDIO?

Yes, please. I think the patch is hardware agnistic, but you can
never know because SDIO firmware != CF firmware != USB firmware.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-04 16:52 ` Dan Williams
  2007-12-04 20:34   ` Holger Schurig
@ 2007-12-07 14:47   ` Holger Schurig
  2007-12-07 17:57     ` Dan Williams
  1 sibling, 1 reply; 14+ messages in thread
From: Holger Schurig @ 2007-12-07 14:47 UTC (permalink / raw)
  To: libertas-dev; +Cc: Dan Williams, linux-wireless, John W. Linville

> So I tested this one, not the one from libertas-dev (which was
> posted a day earlier).  And this one seems fine.  Ack for
> commit to libertas-2.6.
>
> Would you like me to confirm on SDIO?

I now commit that to libertas-2.6, even without your 
SDIO-testing.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 14:47   ` Holger Schurig
@ 2007-12-07 17:57     ` Dan Williams
  2007-12-07 18:05       ` David Woodhouse
  0 siblings, 1 reply; 14+ messages in thread
From: Dan Williams @ 2007-12-07 17:57 UTC (permalink / raw)
  To: Holger Schurig; +Cc: libertas-dev, linux-wireless, John W. Linville

On Fri, 2007-12-07 at 15:47 +0100, Holger Schurig wrote:
> > So I tested this one, not the one from libertas-dev (which was
> > posted a day earlier).  And this one seems fine.  Ack for
> > commit to libertas-2.6.
> >
> > Would you like me to confirm on SDIO?
> 
> I now commit that to libertas-2.6, even without your 
> SDIO-testing.

Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
that cause the driver not to build there, and haven't chased them down
yet.

Dan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 17:57     ` Dan Williams
@ 2007-12-07 18:05       ` David Woodhouse
  2007-12-07 18:09         ` Dan Williams
  2007-12-07 18:12         ` Dan Williams
  0 siblings, 2 replies; 14+ messages in thread
From: David Woodhouse @ 2007-12-07 18:05 UTC (permalink / raw)
  To: Dan Williams
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev

On Fri, 2007-12-07 at 12:57 -0500, Dan Williams wrote:
> Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
> that cause the driver not to build there, and haven't chased them down
> yet.

Hm, it's building for me. Where can I get hold of hardware?

-- 
dwmw2


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:05       ` David Woodhouse
@ 2007-12-07 18:09         ` Dan Williams
  2007-12-07 18:19           ` David Woodhouse
  2007-12-07 18:12         ` Dan Williams
  1 sibling, 1 reply; 14+ messages in thread
From: Dan Williams @ 2007-12-07 18:09 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev

On Fri, 2007-12-07 at 18:05 +0000, David Woodhouse wrote:
> On Fri, 2007-12-07 at 12:57 -0500, Dan Williams wrote:
> > Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
> > that cause the driver not to build there, and haven't chased them down
> > yet.
> 
> Hm, it's building for me. Where can I get hold of hardware?

Either get some from Manas, or find me.

Dan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:05       ` David Woodhouse
  2007-12-07 18:09         ` Dan Williams
@ 2007-12-07 18:12         ` Dan Williams
  1 sibling, 0 replies; 14+ messages in thread
From: Dan Williams @ 2007-12-07 18:12 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev

On Fri, 2007-12-07 at 18:05 +0000, David Woodhouse wrote:
> On Fri, 2007-12-07 at 12:57 -0500, Dan Williams wrote:
> > Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
> > that cause the driver not to build there, and haven't chased them down
> > yet.
> 
> Hm, it's building for me. Where can I get hold of hardware?

Cute, whatever it was got resolved.  Will test now.

Dan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:09         ` Dan Williams
@ 2007-12-07 18:19           ` David Woodhouse
  2007-12-07 18:24             ` Dan Williams
  0 siblings, 1 reply; 14+ messages in thread
From: David Woodhouse @ 2007-12-07 18:19 UTC (permalink / raw)
  To: Dan Williams
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev


On Fri, 2007-12-07 at 13:09 -0500, Dan Williams wrote:
> On Fri, 2007-12-07 at 18:05 +0000, David Woodhouse wrote:
> > On Fri, 2007-12-07 at 12:57 -0500, Dan Williams wrote:
> > > Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
> > > that cause the driver not to build there, and haven't chased them down
> > > yet.
> > 
> > Hm, it's building for me. Where can I get hold of hardware?
> 
> Either get some from Manas, or find me.

I'll be in Boston next week. I'll try to find you.

Btw, is there any particular reason we're setting IW_ENCODE_NOKEY in
lbs_get_encode()? Looks like we aren't returning it for WPA, but we
could return it in WEP modes. This seems to work...

diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index b8c93c0..1af140b 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -1122,14 +1122,6 @@ static int lbs_get_encode(struct net_device *dev,
 		break;
 	}
 
-	if (   adapter->secinfo.wep_enabled
-	    || adapter->secinfo.WPAenabled
-	    || adapter->secinfo.WPA2enabled) {
-		dwrq->flags &= ~IW_ENCODE_DISABLED;
-	} else {
-		dwrq->flags |= IW_ENCODE_DISABLED;
-	}
-
 	memset(extra, 0, 16);
 
 	mutex_lock(&adapter->lock);
@@ -1150,14 +1142,13 @@ static int lbs_get_encode(struct net_device *dev,
 		   || (adapter->secinfo.WPA2enabled)) {
 		/* return WPA enabled */
 		dwrq->flags &= ~IW_ENCODE_DISABLED;
+		dwrq->flags |= IW_ENCODE_NOKEY;
 	} else {
 		dwrq->flags |= IW_ENCODE_DISABLED;
 	}
 
 	mutex_unlock(&adapter->lock);
 
-	dwrq->flags |= IW_ENCODE_NOKEY;
-
 	lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
 	       extra[0], extra[1], extra[2],
 	       extra[3], extra[4], extra[5], dwrq->length);


-- 
dwmw2


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:19           ` David Woodhouse
@ 2007-12-07 18:24             ` Dan Williams
  2007-12-07 18:33               ` David Woodhouse
  0 siblings, 1 reply; 14+ messages in thread
From: Dan Williams @ 2007-12-07 18:24 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev

On Fri, 2007-12-07 at 18:19 +0000, David Woodhouse wrote:
> On Fri, 2007-12-07 at 13:09 -0500, Dan Williams wrote:
> > On Fri, 2007-12-07 at 18:05 +0000, David Woodhouse wrote:
> > > On Fri, 2007-12-07 at 12:57 -0500, Dan Williams wrote:
> > > > Yeah, go ahead.  I got distracted because of changes in > 2.6.23 kernels
> > > > that cause the driver not to build there, and haven't chased them down
> > > > yet.
> > > 
> > > Hm, it's building for me. Where can I get hold of hardware?
> > 
> > Either get some from Manas, or find me.
> 
> I'll be in Boston next week. I'll try to find you.
> 
> Btw, is there any particular reason we're setting IW_ENCODE_NOKEY in
> lbs_get_encode()? Looks like we aren't returning it for WPA, but we
> could return it in WEP modes. This seems to work...

In GIWENCODE, NOKEY is supposed to mean that the key is write-only and
can't be read out of the card's registers or firmware.  This one came
over when harmonizing the libertas handlers with airo.  Since libertas
always caches the keys (both WEP and WPA) internally, it doesn't ever
need to set NOKEY in GIWENCODE because they are always available.

You can really just take that NOKEY line out completely, you don't need
anything else in this patch.

Dan

> diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
> index b8c93c0..1af140b 100644
> --- a/drivers/net/wireless/libertas/wext.c
> +++ b/drivers/net/wireless/libertas/wext.c
> @@ -1122,14 +1122,6 @@ static int lbs_get_encode(struct net_device *dev,
>  		break;
>  	}
>  
> -	if (   adapter->secinfo.wep_enabled
> -	    || adapter->secinfo.WPAenabled
> -	    || adapter->secinfo.WPA2enabled) {
> -		dwrq->flags &= ~IW_ENCODE_DISABLED;
> -	} else {
> -		dwrq->flags |= IW_ENCODE_DISABLED;
> -	}
> -
>  	memset(extra, 0, 16);
>  
>  	mutex_lock(&adapter->lock);
> @@ -1150,14 +1142,13 @@ static int lbs_get_encode(struct net_device *dev,
>  		   || (adapter->secinfo.WPA2enabled)) {
>  		/* return WPA enabled */
>  		dwrq->flags &= ~IW_ENCODE_DISABLED;
> +		dwrq->flags |= IW_ENCODE_NOKEY;
>  	} else {
>  		dwrq->flags |= IW_ENCODE_DISABLED;
>  	}
>  
>  	mutex_unlock(&adapter->lock);
>  
> -	dwrq->flags |= IW_ENCODE_NOKEY;
> -
>  	lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
>  	       extra[0], extra[1], extra[2],
>  	       extra[3], extra[4], extra[5], dwrq->length);
> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:24             ` Dan Williams
@ 2007-12-07 18:33               ` David Woodhouse
  2007-12-07 19:14                 ` Dan Williams
  0 siblings, 1 reply; 14+ messages in thread
From: David Woodhouse @ 2007-12-07 18:33 UTC (permalink / raw)
  To: Dan Williams
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev


On Fri, 2007-12-07 at 13:24 -0500, Dan Williams wrote:
> You can really just take that NOKEY line out completely, you don't need
> anything else in this patch.

Well, there's no point in setting/clearing IW_ENCODE_DISABLED twice,
which is why I removed that bit...

> > -	if (   adapter->secinfo.wep_enabled
> > -	    || adapter->secinfo.WPAenabled
> > -	    || adapter->secinfo.WPA2enabled) {
> > -		dwrq->flags &= ~IW_ENCODE_DISABLED;
> > -	} else {
> > -		dwrq->flags |= IW_ENCODE_DISABLED;
> > -	}
> > -
> >  	memset(extra, 0, 16);
> >  
> >  	mutex_lock(&adapter->lock);


And since I don't see anywhere that we'd copy a WPA key into the
response, I figured it made sense to keep IW_ENCODE_NOKEY in this bit
too: 

> > @@ -1150,14 +1142,13 @@ static int lbs_get_encode(struct net_device *dev,
> >  		   || (adapter->secinfo.WPA2enabled)) {
> >  		/* return WPA enabled */
> >  		dwrq->flags &= ~IW_ENCODE_DISABLED;
> > +		dwrq->flags |= IW_ENCODE_NOKEY;
> >  	} else {
> >  		dwrq->flags |= IW_ENCODE_DISABLED;
> >  	}

I'd want to set up an AP with WPA and test it if I was going to actually
make it find and return the WPA key.

-- 
dwmw2


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 18:33               ` David Woodhouse
@ 2007-12-07 19:14                 ` Dan Williams
  2007-12-07 19:34                   ` David Woodhouse
  0 siblings, 1 reply; 14+ messages in thread
From: Dan Williams @ 2007-12-07 19:14 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Holger Schurig, linux-wireless, John W. Linville, libertas-dev

On Fri, 2007-12-07 at 18:33 +0000, David Woodhouse wrote:
> On Fri, 2007-12-07 at 13:24 -0500, Dan Williams wrote:
> > You can really just take that NOKEY line out completely, you don't need
> > anything else in this patch.
> 
> Well, there's no point in setting/clearing IW_ENCODE_DISABLED twice,
> which is why I removed that bit...
> 
> > > -	if (   adapter->secinfo.wep_enabled
> > > -	    || adapter->secinfo.WPAenabled
> > > -	    || adapter->secinfo.WPA2enabled) {
> > > -		dwrq->flags &= ~IW_ENCODE_DISABLED;
> > > -	} else {
> > > -		dwrq->flags |= IW_ENCODE_DISABLED;
> > > -	}
> > > -
> > >  	memset(extra, 0, 16);
> > >  
> > >  	mutex_lock(&adapter->lock);
> 
> 
> And since I don't see anywhere that we'd copy a WPA key into the
> response, I figured it made sense to keep IW_ENCODE_NOKEY in this bit
> too: 
> 
> > > @@ -1150,14 +1142,13 @@ static int lbs_get_encode(struct net_device *dev,
> > >  		   || (adapter->secinfo.WPA2enabled)) {
> > >  		/* return WPA enabled */
> > >  		dwrq->flags &= ~IW_ENCODE_DISABLED;
> > > +		dwrq->flags |= IW_ENCODE_NOKEY;
> > >  	} else {
> > >  		dwrq->flags |= IW_ENCODE_DISABLED;
> > >  	}
> 
> I'd want to set up an AP with WPA and test it if I was going to actually
> make it find and return the WPA key.

You could, but there's not too much of a point in spending time on this
unless you've got a really good reason?  I'm sure there are more
important things to do in the driver...

Dan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] libertas: implement new scanning logic
  2007-12-07 19:14                 ` Dan Williams
@ 2007-12-07 19:34                   ` David Woodhouse
  0 siblings, 0 replies; 14+ messages in thread
From: David Woodhouse @ 2007-12-07 19:34 UTC (permalink / raw)
  To: Dan Williams
  Cc: linux-wireless, Holger Schurig, John W. Linville, libertas-dev


On Fri, 2007-12-07 at 14:14 -0500, Dan Williams wrote:
> You could, but there's not too much of a point in spending time on
> this unless you've got a really good reason?  I'm sure there are more
> important things to do in the driver...

Indeed. That's exactly the reason I left it returning IW_ENCODE_NOKEY
for WPA, although my patch fixes it for WEP.

-- 
dwmw2


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-12-07 19:34 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-11-29  8:27 [PATCH] libertas: implement new scanning logic Holger Schurig
2007-11-29 19:38 ` Dan Williams
2007-12-04 16:52 ` Dan Williams
2007-12-04 20:34   ` Holger Schurig
2007-12-07 14:47   ` Holger Schurig
2007-12-07 17:57     ` Dan Williams
2007-12-07 18:05       ` David Woodhouse
2007-12-07 18:09         ` Dan Williams
2007-12-07 18:19           ` David Woodhouse
2007-12-07 18:24             ` Dan Williams
2007-12-07 18:33               ` David Woodhouse
2007-12-07 19:14                 ` Dan Williams
2007-12-07 19:34                   ` David Woodhouse
2007-12-07 18:12         ` Dan Williams

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.