libertas: implement new scanning logic
PATCH 1/1 libertas: implement new scanning logic
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 <[email protected]>
---
Now again make last_scanned_channel an int
drivers/net/wireless/libertas/scan.c +355 -506
@@ -79,6 +79,22 @@ static inline void clear_bss_descriptormemset (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_listint 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
@@ -353,383 +373,151 @@ 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 ; +/* This code makes sure that the 802.11b rates (1 MBit/s, 2 +MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set. +Note that the values are MBit/s * 2, to mark them as +basic rates so that the firmware likes it better */ +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; }
@@ -745,29 +533,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.
@@ -775,85 +564,130 @@ int lbs_scan_networks(struct lbs_privateif (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); +netif_carrier_off (priv->dev); +if (priv->mesh_dev) {netif_stop_queue (priv->mesh_dev);netif_carrier_off (priv->mesh_dev); - } } - ret =lbs_scan_channel_list (priv, - maxchanperscan, - filteredscan, - scan_cfg, - pchantlvout, - scan_chan_list, - puserscanin, - full_scan); +/* 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; + } + +/* 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 +out2: + adapter->last_scanned_channel =0 ; + +out:if (adapter->connect_status ==LBS_CONNECTED ) {netif_carrier_on (priv->dev);netif_wake_queue (priv->dev); } -if (priv->mesh_dev && (adapter->mesh_connect_status ==LBS_CONNECTED )) {netif_carrier_on (priv->mesh_dev);netif_wake_queue (priv->mesh_dev); } - -out: -if (scan_cfg) -kfree (scan_cfg); - -if (scan_chan_list) -kfree (scan_chan_list); +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 *
@@ -898,7 +732,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 ) {
@@ -914,7 +748,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 */
@@ -926,18 +760,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 */
@@ -955,7 +789,7 @@ static int lbs_process_bss(struct bss_decase 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 ;
@@ -964,16 +798,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 :
@@ -981,12 +813,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 :
@@ -994,18 +828,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 ;
@@ -1024,8 +856,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 )
@@ -1044,24 +879,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 ; }
@@ -1273,8 +1120,6 @@ int lbs_find_best_network_ssid(struct lbif (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 );
@@ -1288,36 +1133,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
@@ -1329,8 +1144,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 */
@@ -1357,7 +1170,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);
@@ -1373,6 +1185,7 @@ out:/* */ /*********************************************************************/ +#define MAX_CUSTOM_LEN 64 static inline char *lbs_translate_scan(struct lbs_private *priv,
@@ -1398,7 +1211,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 );
@@ -1528,6 +1341,55 @@ 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; + +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 *
@@ -1552,6 +1414,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,
@@ -1609,7 +1475,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.
@@ -1623,7 +1490,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;
@@ -1635,32 +1502,14 @@ int lbs_cmd_80211_scan(struct lbs_privatmemcpy (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 *
@@ -1725,7 +1574,7 @@ int lbs_ret_80211_scan(struct lbs_privatlbs_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;
@@ -1788,7 +1637,7 @@ int lbs_ret_80211_scan(struct lbs_privatcontinue ; } -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 */
drivers/net/wireless/libertas/dev.h +1 -2
@@ -366,9 +366,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