diff options
Diffstat (limited to 'drivers/net/wireless/libertas/scan.c')
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 1192 |
1 files changed, 483 insertions, 709 deletions
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index ad1e67d984ce..9a61188b62e9 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -39,9 +39,8 @@ //! Memory needed to store a max number/size SSID TLV for a firmware scan #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) -//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max -#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ - + sizeof(struct mrvlietypes_numprobes) \ +//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max +#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \ + CHAN_TLV_MAX_SIZE \ + SSID_TLV_MAX_SIZE) @@ -80,7 +79,23 @@ static inline void clear_bss_descriptor (struct bss_descriptor * bss) memset(bss, 0, offsetof(struct bss_descriptor, list)); } -static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, +/** + * @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) { if ( !secinfo->wep_enabled @@ -94,7 +109,7 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, +static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( secinfo->wep_enabled @@ -106,7 +121,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, +static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -121,7 +136,7 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, +static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -136,7 +151,7 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, +static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -150,6 +165,18 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, 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 * @@ -163,13 +190,13 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP * * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param index Index in scantable to check against current driver settings * @param mode Network mode: Infrastructure or IBSS * * @return Index in scantable, or error code if negative */ -static int is_network_compatible(wlan_adapter * adapter, +static int is_network_compatible(struct lbs_private *priv, struct bss_descriptor * bss, u8 mode) { int matched = 0; @@ -179,34 +206,34 @@ static int is_network_compatible(wlan_adapter * adapter, if (bss->mode != mode) goto done; - if ((matched = match_bss_no_security(&adapter->secinfo, bss))) { + if ((matched = match_bss_no_security(&priv->secinfo, bss))) { goto done; - } else if ((matched = match_bss_static_wep(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) { goto done; - } else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_wpa(&priv->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], - adapter->secinfo.wep_enabled ? "e" : "d", - adapter->secinfo.WPAenabled ? "e" : "d", - adapter->secinfo.WPA2enabled ? "e" : "d", + "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], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; - } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_wpa2(&priv->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], - adapter->secinfo.wep_enabled ? "e" : "d", - adapter->secinfo.WPAenabled ? "e" : "d", - adapter->secinfo.WPA2enabled ? "e" : "d", + "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], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; - } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_dynamic_wep(&priv->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; @@ -214,12 +241,12 @@ static int is_network_compatible(wlan_adapter * adapter, /* 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", - adapter->secinfo.WPA2enabled ? "e" : "d", + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: @@ -227,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 libertas_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); -} - @@ -252,17 +263,27 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_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 * - * Only used from wlan_scan_setup_scan_config() + * Only used from lbs_scan_setup_scan_config() * * Use the driver region/band information to construct a comprehensive list * of channels to scan. This routine is used for any scan that is not * provided a specific channel list to scan. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param scanchanlist Output parameter: resulting channel list to scan * @param filteredscan Flag indicating whether or not a BSSID or SSID filter * is being sent in the command to firmware. Used to @@ -272,12 +293,11 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) * * @return void */ -static void wlan_scan_create_channel_list(wlan_private * priv, +static int lbs_scan_create_channel_list(struct lbs_private *priv, struct chanscanparamset * scanchanlist, u8 filteredscan) { - wlan_adapter *adapter = priv->adapter; struct region_channel *scanregion; struct chan_freq_power *cfp; int rgnidx; @@ -285,8 +305,6 @@ static void wlan_scan_create_channel_list(wlan_private * priv, 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 @@ -295,21 +313,22 @@ static void wlan_scan_create_channel_list(wlan_private * priv, */ scantype = CMD_SCAN_TYPE_ACTIVE; - for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { - if (priv->adapter->enable11d && - adapter->connect_status != LIBERTAS_CONNECTED) { + for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { + if (priv->enable11d && + (priv->connect_status != LBS_CONNECTED) && + (priv->mesh_connect_status != LBS_CONNECTED)) { /* Scan all the supported chan for the first scan */ - if (!adapter->universal_channel[rgnidx].valid) + if (!priv->universal_channel[rgnidx].valid) continue; - scanregion = &adapter->universal_channel[rgnidx]; + scanregion = &priv->universal_channel[rgnidx]; /* clear the parsed_region_chan for the first scan */ - memset(&adapter->parsed_region_chan, 0x00, - sizeof(adapter->parsed_region_chan)); + memset(&priv->parsed_region_chan, 0x00, + sizeof(priv->parsed_region_chan)); } else { - if (!adapter->region_channel[rgnidx].valid) + if (!priv->region_channel[rgnidx].valid) continue; - scanregion = &adapter->region_channel[rgnidx]; + scanregion = &priv->region_channel[rgnidx]; } for (nextchan = 0; @@ -317,10 +336,10 @@ static void wlan_scan_create_channel_list(wlan_private * priv, cfp = scanregion->CFP + nextchan; - if (priv->adapter->enable11d) { + if (priv->enable11d) { scantype = - libertas_get_scan_type_11d(cfp->channel, - &adapter-> + lbs_get_scan_type_11d(cfp->channel, + &priv-> parsed_region_chan); } @@ -353,453 +372,151 @@ static void wlan_scan_create_channel_list(wlan_private * priv, } } } + return chanidx; } -/* Delayed partial scan worker */ -void libertas_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) { - wlan_private *priv = container_of(work, wlan_private, scan_work.work); - - wlan_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 wlan_scan_cmd_config structure to use in issue scan cmds - * - * Application layer or other functions can invoke wlan_scan_networks - * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. - * This structure is used as the basis of one or many wlan_scan_cmd_config - * commands that are sent to the command processing module and sent to - * firmware. - * - * Create a wlan_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. - * If the number of probes is not set, use the adapter default setting - * Qualify the channel +/* + * Add CHANLIST TLV of the form * - * @param priv A pointer to wlan_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 wlan_scan_cmd_config * -wlan_scan_setup_scan_config(wlan_private * priv, - const struct wlan_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_numprobes *pnumprobestlv; - struct mrvlietypes_ssidparamset *pssidtlv; - struct wlan_scan_cmd_config * pscancfgout = NULL; - u8 *ptlvpos; - u16 numprobes; - int chanidx; - int scantype; - int scandur; - int channel; - int radiotype; - - 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 number of probes to send, use adapter setting if unset */ - numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; - - /* - * 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; - numprobes = 0; - } - - /* If the input config or adapter has the number of Probes set, add tlv */ - if (numprobes) { - pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; - pnumprobestlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); - pnumprobestlv->header.len = cpu_to_le16(2); - pnumprobestlv->numprobes = cpu_to_le16(numprobes); - - ptlvpos += sizeof(*pnumprobestlv); - } - - /* - * Set the output for the channel TLV to the address in the tlv buffer - * past any TLVs that were added in this fuction (SSID, numprobes). - * channel TLVs will be added past this for each scan command, preserving - * the TLVs that were previously added. - */ - *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; - - if (!puserscanin || !puserscanin->chanlist[0].channumber) { - /* Create a default channel scan list */ - lbs_deb_scan("creating full region channel list\n"); - wlan_scan_create_channel_list(priv, pscanchanlist, - *pfilteredscan); - goto out; - } - - for (chanidx = 0; - chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX - && puserscanin->chanlist[chanidx].channumber; chanidx++) { - - channel = puserscanin->chanlist[chanidx].channumber; - (pscanchanlist + chanidx)->channumber = channel; - - radiotype = puserscanin->chanlist[chanidx].radiotype; - (pscanchanlist + chanidx)->radiotype = radiotype; - - scantype = puserscanin->chanlist[chanidx].scantype; - - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 1; - } else { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 0; - } - - if (puserscanin->chanlist[chanidx].scantime) { - scandur = puserscanin->chanlist[chanidx].scantime; - } else { - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; - } else { - scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; - } - } - - (pscanchanlist + chanidx)->minscantime = - cpu_to_le16(scandur); - (pscanchanlist + chanidx)->maxscantime = - cpu_to_le16(scandur); - } - - /* Check if we are only scanning the current channel */ - if ((chanidx == 1) && - (puserscanin->chanlist[0].channumber == - priv->adapter->curbssparams.channel)) { - *pscancurrentonly = 1; - lbs_deb_scan("scanning current channel only"); - } - -out: - return pscancfgout; + size_t size = sizeof(struct chanscanparamset) * chan_count; + struct mrvlietypes_chanlistparamset *chan_tlv = + (struct mrvlietypes_chanlistparamset *) tlv; + + 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 wlan_scan_networks() - * - * Previous routines have created a wlan_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 wlan_cmd routines for execution in the firmware. + +/* + * Add RATES TLV of the form * - * @param priv A pointer to wlan_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 wlan_scan_channel_list(wlan_private * priv, - int maxchanperscan, - u8 filteredscan, - struct wlan_scan_cmd_config * pscancfgout, - struct mrvlietypes_chanlistparamset * pchantlvout, - struct chanscanparamset * pscanchanlist, - const struct wlan_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 = libertas_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; - - 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); + int i; + struct mrvlietypes_ratesparamset *rate_tlv = + (struct mrvlietypes_ratesparamset *) tlv; + + 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 = cpu_to_le16(i); + return sizeof(rate_tlv->header) + i; } + /* - * Only used from wlan_scan_networks() -*/ -static void clear_selected_scan_list_entries(wlan_adapter *adapter, - const struct wlan_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; + int ret = -ENOMEM; + struct lbs_scan_cmd_config *scan_cmd; + u8 *tlv; /* pointer into our current, growing TLV storage area */ - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, " + "chan_count %d", + bsstype, chan_list[0].channumber, chan_count); - if (!scan_cfg) + /* create the fixed part for scan command */ + scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); + if (scan_cmd == NULL) goto out; - - if (scan_cfg->clear_ssid && scan_cfg->ssid_len) - clear_ssid_flag = 1; - - 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; - } - - if (!clear_ssid_flag && !clear_bssid_flag) - goto out; - - 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; - - /* Check for a BSSID match */ - if ( clear_bssid_flag - && !compare_ether_addr(bss->bssid, scan_cfg->bssid)) - clear = 1; - - if (clear) { - list_move_tail (&bss->list, &adapter->network_free_list); - clear_bss_descriptor(bss); - } - } - mutex_unlock(&adapter->lock); + tlv = scan_cmd->tlvbuffer; + if (user_cfg) + memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); + scan_cmd->bsstype = bsstype; + + /* 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); + + /* 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); + + 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; } @@ -812,32 +529,32 @@ out: * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table * - * @param priv A pointer to wlan_private structure + * @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 wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, +int lbs_scan_networks(struct lbs_private *priv, + const struct lbs_ioctl_user_scan_cfg *user_cfg, int full_scan) { - wlan_adapter * adapter = priv->adapter; - struct mrvlietypes_chanlistparamset *pchantlvout; - struct chanscanparamset * scan_chan_list = NULL; - struct wlan_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. @@ -845,90 +562,138 @@ int wlan_scan_networks(wlan_private * priv, if (full_scan && delayed_work_pending(&priv->scan_work)) cancel_delayed_work(&priv->scan_work); - scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * - WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); - if (scan_chan_list == NULL) { - ret = -ENOMEM; + /* 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); + + /* 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; } - scan_cfg = wlan_scan_setup_scan_config(priv, - puserscanin, - &pchantlvout, - scan_chan_list, - &maxchanperscan, - &filteredscan, - &scancurrentchanonly); - if (scan_cfg == NULL) { - ret = -ENOMEM; - goto out; + /* We want to scan all channels */ + chan_count = lbs_scan_create_channel_list(priv, chan_list, + filteredscan); + + 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); + } + + /* Prepare to continue an interrupted scan */ + lbs_deb_scan("chan_count %d, last_scanned_channel %d\n", + chan_count, priv->last_scanned_channel); + curr_chans = chan_list; + /* advance channel list by already-scanned-channels */ + if (priv->last_scanned_channel > 0) { + curr_chans += priv->last_scanned_channel; + chan_count -= priv->last_scanned_channel; } - clear_selected_scan_list_entries(adapter, puserscanin); + /* Send scan command(s) + * numchannels contains the number of channels we should maximally scan + * chan_count is the total number of channels to scan + */ - /* 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->mesh_dev); - netif_carrier_off(priv->mesh_dev); + 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->surpriseremoved) { + /* -1 marks just that we're currently scanning */ + if (priv->last_scanned_channel < 0) + priv->last_scanned_channel = to_scan; + else + priv->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; } - } - ret = wlan_scan_channel_list(priv, - maxchanperscan, - filteredscan, - scan_cfg, - pchantlvout, - scan_chan_list, - puserscanin, - full_scan); + } + 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)); - } - mutex_unlock(&adapter->lock); + mutex_lock(&priv->lock); + lbs_deb_scan("scan table:\n"); + list_for_each_entry(iter, &priv->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(&priv->lock); #endif - if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { +out2: + priv->last_scanned_channel = 0; + +out: + if (priv->connect_status == LBS_CONNECTED) { netif_carrier_on(priv->dev); - netif_wake_queue(priv->dev); - if (priv->mesh_dev) { - netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + } + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { + netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) 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 * * @return 0 or -1 */ -static int libertas_process_bss(struct bss_descriptor * bss, +static int lbs_process_bss(struct bss_descriptor *bss, u8 ** pbeaconinfo, int *bytesleft) { struct ieeetypes_fhparamset *pFH; @@ -946,7 +711,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo)); + beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo)); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } @@ -967,7 +732,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, *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) { @@ -983,7 +748,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* 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 */ @@ -995,18 +760,18 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* 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 */ @@ -1024,7 +789,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, 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; @@ -1033,16 +798,14 @@ static int libertas_process_bss(struct bss_descriptor * bss, 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: @@ -1050,31 +813,31 @@ static int libertas_process_bss(struct bss_descriptor * bss, 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: pibss = (struct ieeetypes_ibssparamset *) pos; - bss->atimwindow = le32_to_cpu(pibss->atimwindow); + bss->atimwindow = le16_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; @@ -1093,8 +856,11 @@ static int libertas_process_bss(struct bss_descriptor * bss, * 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) @@ -1113,24 +879,36 @@ static int libertas_process_bss(struct bss_descriptor * bss, 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; } @@ -1139,7 +917,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* Timestamp */ bss->last_scanned = jiffies; - libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); + lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); ret = 0; @@ -1153,13 +931,13 @@ done: * * Used in association code * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param bssid BSSID to find in the scan list * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list, or error return code (< 0) */ -struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, u8 * bssid, u8 mode) { struct bss_descriptor * iter_bss; @@ -1177,14 +955,14 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, * continue past a matched bssid that is not compatible in case there * is an AP with multiple SSIDs assigned to the same BSSID */ - mutex_lock(&adapter->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + mutex_lock(&priv->lock); + list_for_each_entry (iter_bss, &priv->network_list, list) { if (compare_ether_addr(iter_bss->bssid, bssid)) continue; /* bssid doesn't match */ switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; found_bss = iter_bss; break; @@ -1193,7 +971,7 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, break; } } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); out: lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); @@ -1205,14 +983,14 @@ out: * * Used in association code * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param ssid SSID to find in the list * @param bssid BSSID to qualify the SSID selection (if provided) * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list */ -struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, int channel) { @@ -1223,14 +1001,14 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, lbs_deb_enter(LBS_DEB_SCAN); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { if ( !tmp_oldest || (iter_bss->last_scanned < tmp_oldest->last_scanned)) tmp_oldest = iter_bss; - if (libertas_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, + if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, ssid, ssid_len) != 0) continue; /* ssid doesn't match */ if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) @@ -1241,7 +1019,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; if (bssid) { @@ -1266,7 +1044,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, } out: - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } @@ -1277,12 +1055,13 @@ out: * Search the scan table for the best SSID that also matches the current * adapter network preference (infrastructure or adhoc) * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * * @return index in BSSID list */ -static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, - u8 mode) +static struct bss_descriptor *lbs_find_best_ssid_in_list( + struct lbs_private *priv, + u8 mode) { u8 bestrssi = 0; struct bss_descriptor * iter_bss; @@ -1290,13 +1069,13 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad lbs_deb_enter(LBS_DEB_SCAN); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) break; @@ -1313,7 +1092,7 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad } } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); return best_bss; } @@ -1323,27 +1102,24 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad * * Used from association worker. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param pSSID A pointer to AP's ssid * * @return 0--success, otherwise--fail */ -int libertas_find_best_network_ssid(wlan_private * priv, +int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode) { - wlan_adapter *adapter = priv->adapter; int ret = -1; struct bss_descriptor * found; lbs_deb_enter(LBS_DEB_SCAN); - wlan_scan_networks(priv, NULL, 1); - if (adapter->surpriseremoved) + lbs_scan_networks(priv, NULL, 1); + if (priv->surpriseremoved) goto out; - wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); - - found = libertas_find_best_ssid_in_list(adapter, preferred_mode); + found = lbs_find_best_ssid_in_list(priv, preferred_mode); if (found && (found->ssid_len > 0)) { memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); *out_ssid_len = found->ssid_len; @@ -1356,57 +1132,24 @@ 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 libertas_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_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 * * Used in association code and from debugfs * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param ssid A pointer to the SSID to scan for * @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 */ -int libertas_send_specific_ssid_scan(wlan_private * priv, +int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, u8 ssid_len, u8 clear_ssid) { - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_user_scan_cfg scancfg; + struct lbs_ioctl_user_scan_cfg scancfg; int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", @@ -1420,12 +1163,11 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, scancfg.ssid_len = ssid_len; scancfg.clear_ssid = clear_ssid; - wlan_scan_networks(priv, &scancfg, 1); - if (adapter->surpriseremoved) { + lbs_scan_networks(priv, &scancfg, 1); + if (priv->surpriseremoved) { 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); @@ -1441,13 +1183,13 @@ out: /* */ /*********************************************************************/ + #define MAX_CUSTOM_LEN 64 -static inline char *libertas_translate_scan(wlan_private *priv, +static inline char *lbs_translate_scan(struct lbs_private *priv, char *start, char *stop, struct bss_descriptor *bss) { - wlan_adapter *adapter = priv->adapter; struct chan_freq_power *cfp; char *current_val; /* For rates */ struct iw_event iwe; /* Temporary buffer */ @@ -1459,14 +1201,14 @@ static inline char *libertas_translate_scan(wlan_private *priv, lbs_deb_enter(LBS_DEB_SCAN); - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel); if (!cfp) { lbs_deb_scan("Invalid channel number %d\n", bss->channel); start = NULL; 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); @@ -1502,25 +1244,25 @@ static inline char *libertas_translate_scan(wlan_private *priv, if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; - if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; } else { iwe.u.qual.noise = - CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); } /* Locally created ad-hoc BSSs won't have beacons if this is the * only station in the adhoc network; so get signal strength * from receive statistics. */ - if ((adapter->mode == IW_MODE_ADHOC) - && adapter->adhoccreate - && !libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + if ((priv->mode == IW_MODE_ADHOC) + && priv->adhoccreate + && !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len)) { int snr, nf; - snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; - nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; iwe.u.qual.level = CAL_RSSI(snr, nf); } start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); @@ -1549,10 +1291,10 @@ static inline char *libertas_translate_scan(wlan_private *priv, stop, &iwe, IW_EV_PARAM_LEN); } if ((bss->mode == IW_MODE_ADHOC) - && !libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + && !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len) - && adapter->adhoccreate) { + && priv->adhoccreate) { iwe.u.bitrate.value = 22 * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); @@ -1596,6 +1338,54 @@ 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; + + 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 */ + priv->last_scanned_channel = -1; + + if (priv->surpriseremoved) + return -EIO; + + lbs_deb_leave(LBS_DEB_SCAN); + return 0; +} + + /** * @brief Handle Retrieve scan table ioctl * @@ -1606,12 +1396,11 @@ out: * * @return 0 --success, otherwise fail */ -int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, +int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int err = 0; char *ev = extra; char *stop = ev + dwrq->length; @@ -1620,14 +1409,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_SCAN); + /* iwlist should wait until the current scan is finished */ + if (priv->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) { - libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } - mutex_lock(&adapter->lock); - list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { + mutex_lock(&priv->lock); + list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { char * next_ev; unsigned long stale_time; @@ -1644,18 +1437,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { list_move_tail (&iter_bss->list, - &adapter->network_free_list); + &priv->network_free_list); clear_bss_descriptor(iter_bss); continue; } /* Translate to WE format this entry */ - next_ev = libertas_translate_scan(priv, ev, stop, iter_bss); + next_ev = lbs_translate_scan(priv, ev, stop, iter_bss); if (next_ev == NULL) continue; ev = next_ev; } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); dwrq->length = (ev - extra); dwrq->flags = 0; @@ -1677,24 +1470,25 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, /** * @brief Prepare a scan command to be sent to the firmware * - * Called from libertas_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. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param cmd A pointer to cmd_ds_command structure to be sent to * firmware with the cmd_DS_801_11_SCAN structure - * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used + * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used * to set the fields/TLVs for the command sent to firmware * * @return 0 or -1 */ -int libertas_cmd_80211_scan(wlan_private * priv, - struct cmd_ds_command *cmd, void *pdata_buf) +int lbs_cmd_80211_scan(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) { struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct wlan_scan_cmd_config *pscancfg = pdata_buf; + struct lbs_scan_cmd_config *pscancfg = pdata_buf; lbs_deb_enter(LBS_DEB_SCAN); @@ -1703,32 +1497,14 @@ int libertas_cmd_80211_scan(wlan_private * priv, 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 * @@ -1750,14 +1526,13 @@ static inline int is_same_network(struct bss_descriptor *src, * | bufsize and sizeof the fixed fields above) | * .-----------------------------------------------------------. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param resp A pointer to cmd_ds_command * * @return 0 or -1 */ -int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) +int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_scan_rsp *pscan; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; @@ -1771,11 +1546,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) lbs_deb_enter(LBS_DEB_SCAN); /* Prune old entries from scan table */ - list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { + list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_before(jiffies, stale_time)) continue; - list_move_tail (&iter_bss->list, &adapter->network_free_list); + list_move_tail (&iter_bss->list, &priv->network_free_list); clear_bss_descriptor(iter_bss); } @@ -1789,12 +1564,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) goto done; } - bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize)); + bytesleft = le16_to_cpu(pscan->bssdescriptsize); 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", - pscan->nr_sets); + scanrespsize = le16_to_cpu(resp->size); + lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets); pbssinfo = pscan->bssdesc_and_tlvbuffer; @@ -1821,14 +1595,14 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); - if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) { + if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) { /* error parsing the scan response, skipped */ lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); continue; } /* Try to find this bss in the scan table */ - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { if (is_same_network(iter_bss, &new)) { found = iter_bss; break; @@ -1842,21 +1616,21 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) if (found) { /* found, clear it */ clear_bss_descriptor(found); - } else if (!list_empty(&adapter->network_free_list)) { + } else if (!list_empty(&priv->network_free_list)) { /* Pull one from the free list */ - found = list_entry(adapter->network_free_list.next, + found = list_entry(priv->network_free_list.next, struct bss_descriptor, list); - list_move_tail(&found->list, &adapter->network_list); + list_move_tail(&found->list, &priv->network_list); } else if (oldest) { /* If there are no more slots, expire the oldest */ found = oldest; clear_bss_descriptor(found); - list_move_tail(&found->list, &adapter->network_list); + list_move_tail(&found->list, &priv->network_list); } else { 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 */ |