Commit eb8f7330 authored by Dan Williams's avatar Dan Williams Committed by John W. Linville

[PATCH] libertas: fix 'keep previous scan' behavior

Do not clear the scan list except under specific conditions, such as
when (a) user-requested, or (b) joining/starting an adhoc network.
Furthermore, only clear entries which match the SSID or BSSID of the
request, not the whole scan list.
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent fcdb53db
...@@ -25,7 +25,7 @@ static int assoc_helper_essid(wlan_private *priv, ...@@ -25,7 +25,7 @@ static int assoc_helper_essid(wlan_private *priv,
lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid); lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
if (assoc_req->mode == IW_MODE_INFRA) { if (assoc_req->mode == IW_MODE_INFRA) {
if (adapter->prescan) { if (adapter->prescan) {
libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1); libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
} }
bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
...@@ -44,7 +44,7 @@ static int assoc_helper_essid(wlan_private *priv, ...@@ -44,7 +44,7 @@ static int assoc_helper_essid(wlan_private *priv,
/* Scan for the network, do not save previous results. Stale /* Scan for the network, do not save previous results. Stale
* scan data will cause us to join a non-existant adhoc network * scan data will cause us to join a non-existant adhoc network
*/ */
libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0); libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
/* Search for the requested SSID in the scan table */ /* Search for the requested SSID in the scan table */
bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL, bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
......
...@@ -193,7 +193,7 @@ static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, ...@@ -193,7 +193,7 @@ static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1); memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
extscan_ssid.ssidlength = strlen(buf)-1; extscan_ssid.ssidlength = strlen(buf)-1;
libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1); libertas_send_specific_SSID_scan(priv, &extscan_ssid, 0);
memset(&wrqu, 0, sizeof(union iwreq_data)); memset(&wrqu, 0, sizeof(union iwreq_data));
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
...@@ -245,16 +245,13 @@ static void libertas_parse_bssid(char *buf, size_t count, ...@@ -245,16 +245,13 @@ static void libertas_parse_bssid(char *buf, size_t count,
{ {
char *hold; char *hold;
unsigned int mac[ETH_ALEN]; unsigned int mac[ETH_ALEN];
int i;
hold = strstr(buf, "bssid="); hold = strstr(buf, "bssid=");
if (!hold) if (!hold)
return; return;
hold += 6; hold += 6;
sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3, sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
mac+4, mac+5); memcpy(scan_cfg->bssid, mac, ETH_ALEN);
for(i=0;i<ETH_ALEN;i++)
scan_cfg->specificBSSID[i] = mac[i];
} }
static void libertas_parse_ssid(char *buf, size_t count, static void libertas_parse_ssid(char *buf, size_t count,
...@@ -272,28 +269,26 @@ static void libertas_parse_ssid(char *buf, size_t count, ...@@ -272,28 +269,26 @@ static void libertas_parse_ssid(char *buf, size_t count,
end = buf + count - 1; end = buf + count - 1;
size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold)); size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
strncpy(scan_cfg->specificSSID, hold, size); strncpy(scan_cfg->ssid, hold, size);
return; return;
} }
static void libertas_parse_keep(char *buf, size_t count, static int libertas_parse_clear(char *buf, size_t count, const char *tag)
struct wlan_ioctl_user_scan_cfg *scan_cfg)
{ {
char *hold; char *hold;
int val; int val;
hold = strstr(buf, "keep="); hold = strstr(buf, tag);
if (!hold) if (!hold)
return; return 0;
hold += 5; hold += strlen(tag);
sscanf(hold, "%d", &val); sscanf(hold, "%d", &val);
if (val != 0) if (val != 0)
val = 1; val = 1;
scan_cfg->keeppreviousscan = val; return val;
return;
} }
static int libertas_parse_dur(char *buf, size_t count, static int libertas_parse_dur(char *buf, size_t count,
...@@ -376,8 +371,9 @@ static ssize_t libertas_setuserscan(struct file *file, ...@@ -376,8 +371,9 @@ static ssize_t libertas_setuserscan(struct file *file,
dur = libertas_parse_dur(buf, count, scan_cfg); dur = libertas_parse_dur(buf, count, scan_cfg);
libertas_parse_chan(buf, count, scan_cfg, dur); libertas_parse_chan(buf, count, scan_cfg, dur);
libertas_parse_bssid(buf, count, scan_cfg); libertas_parse_bssid(buf, count, scan_cfg);
scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
libertas_parse_ssid(buf, count, scan_cfg); libertas_parse_ssid(buf, count, scan_cfg);
libertas_parse_keep(buf, count, scan_cfg); scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
libertas_parse_probes(buf, count, scan_cfg); libertas_parse_probes(buf, count, scan_cfg);
libertas_parse_type(buf, count, scan_cfg); libertas_parse_type(buf, count, scan_cfg);
......
...@@ -59,6 +59,9 @@ ...@@ -59,6 +59,9 @@
//! Scan time specified in the channel TLV for each channel for active scans //! Scan time specified in the channel TLV for each channel for active scans
#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static inline void clear_bss_descriptor (struct bss_descriptor * bss) static inline void clear_bss_descriptor (struct bss_descriptor * bss)
{ {
/* Don't blow away ->list, just BSS data */ /* Don't blow away ->list, just BSS data */
...@@ -409,13 +412,11 @@ wlan_scan_setup_scan_config(wlan_private * priv, ...@@ -409,13 +412,11 @@ wlan_scan_setup_scan_config(wlan_private * priv,
u8 * pscancurrentonly) u8 * pscancurrentonly)
{ {
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
struct mrvlietypes_numprobes *pnumprobestlv; struct mrvlietypes_numprobes *pnumprobestlv;
struct mrvlietypes_ssidparamset *pssidtlv; struct mrvlietypes_ssidparamset *pssidtlv;
struct wlan_scan_cmd_config * pscancfgout = NULL; struct wlan_scan_cmd_config * pscancfgout = NULL;
u8 *ptlvpos; u8 *ptlvpos;
u16 numprobes; u16 numprobes;
u16 ssidlen;
int chanidx; int chanidx;
int scantype; int scantype;
int scandur; int scandur;
...@@ -472,21 +473,18 @@ wlan_scan_setup_scan_config(wlan_private * priv, ...@@ -472,21 +473,18 @@ wlan_scan_setup_scan_config(wlan_private * priv,
* Set the BSSID filter to the incoming configuration, * Set the BSSID filter to the incoming configuration,
* if non-zero. If not set, it will remain disabled (all zeros). * if non-zero. If not set, it will remain disabled (all zeros).
*/ */
memcpy(pscancfgout->specificBSSID, memcpy(pscancfgout->bssid, puserscanin->bssid,
puserscanin->specificBSSID, sizeof(pscancfgout->bssid));
sizeof(pscancfgout->specificBSSID));
ssidlen = strlen(puserscanin->specificSSID);
if (ssidlen) { if (puserscanin->ssid_len) {
pssidtlv = pssidtlv =
(struct mrvlietypes_ssidparamset *) pscancfgout-> (struct mrvlietypes_ssidparamset *) pscancfgout->
tlvbuffer; tlvbuffer;
pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
pssidtlv->header.len = cpu_to_le16(ssidlen); pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
memcpy(pssidtlv->ssid, puserscanin->specificSSID, memcpy(pssidtlv->ssid, puserscanin->ssid,
ssidlen); puserscanin->ssid_len);
ptlvpos += sizeof(pssidtlv->header) + ssidlen; ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
} }
/* /*
...@@ -495,8 +493,8 @@ wlan_scan_setup_scan_config(wlan_private * priv, ...@@ -495,8 +493,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
* scan results. That is not an issue with an SSID or BSSID * scan results. That is not an issue with an SSID or BSSID
* filter applied to the scan results in the firmware. * filter applied to the scan results in the firmware.
*/ */
if (ssidlen || (memcmp(pscancfgout->specificBSSID, if ( puserscanin->ssid_len
&zeromac, sizeof(zeromac)) != 0)) { || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
*pfilteredscan = 1; *pfilteredscan = 1;
} }
...@@ -743,6 +741,53 @@ done: ...@@ -743,6 +741,53 @@ done:
return ret; return ret;
} }
static void
clear_selected_scan_list_entries(wlan_adapter * adapter,
const struct wlan_ioctl_user_scan_cfg * scan_cfg)
{
struct bss_descriptor * bss;
struct bss_descriptor * safe;
u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
if (!scan_cfg)
return;
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)
return;
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.ssidlength == scan_cfg->ssid_len)
&& !memcmp(bss->ssid.ssid, scan_cfg->ssid, bss->ssid.ssidlength))
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);
}
/** /**
* @brief Internal function used to start a scan based on an input config * @brief Internal function used to start a scan based on an input config
* *
...@@ -760,11 +805,10 @@ int wlan_scan_networks(wlan_private * priv, ...@@ -760,11 +805,10 @@ int wlan_scan_networks(wlan_private * priv,
const struct wlan_ioctl_user_scan_cfg * puserscanin, const struct wlan_ioctl_user_scan_cfg * puserscanin,
int full_scan) int full_scan)
{ {
wlan_adapter *adapter = priv->adapter; wlan_adapter * adapter = priv->adapter;
struct mrvlietypes_chanlistparamset *pchantlvout; struct mrvlietypes_chanlistparamset *pchantlvout;
struct chanscanparamset * scan_chan_list = NULL; struct chanscanparamset * scan_chan_list = NULL;
struct wlan_scan_cmd_config * scan_cfg = NULL; struct wlan_scan_cmd_config * scan_cfg = NULL;
u8 keeppreviousscan;
u8 filteredscan; u8 filteredscan;
u8 scancurrentchanonly; u8 scancurrentchanonly;
int maxchanperscan; int maxchanperscan;
...@@ -791,28 +835,7 @@ int wlan_scan_networks(wlan_private * priv, ...@@ -791,28 +835,7 @@ int wlan_scan_networks(wlan_private * priv,
goto out; goto out;
} }
keeppreviousscan = 0; clear_selected_scan_list_entries(adapter, puserscanin);
if (puserscanin) {
keeppreviousscan = puserscanin->keeppreviousscan;
}
if (adapter->last_scanned_channel)
keeppreviousscan = 1;
if (!keeppreviousscan) {
struct bss_descriptor * iter_bss;
struct bss_descriptor * safe;
mutex_lock(&adapter->lock);
list_for_each_entry_safe (iter_bss, safe,
&adapter->network_list, list) {
list_move_tail (&iter_bss->list,
&adapter->network_free_list);
clear_bss_descriptor(iter_bss);
}
mutex_unlock(&adapter->lock);
}
/* Keep the data path active if we are only scanning our current channel */ /* Keep the data path active if we are only scanning our current channel */
if (!scancurrentchanonly) { if (!scancurrentchanonly) {
...@@ -1434,30 +1457,30 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, ...@@ -1434,30 +1457,30 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
*/ */
int libertas_send_specific_SSID_scan(wlan_private * priv, int libertas_send_specific_SSID_scan(wlan_private * priv,
struct WLAN_802_11_SSID *prequestedssid, struct WLAN_802_11_SSID *prequestedssid,
u8 keeppreviousscan) u8 clear_ssid)
{ {
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
struct wlan_ioctl_user_scan_cfg scancfg; struct wlan_ioctl_user_scan_cfg scancfg;
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
if (prequestedssid == NULL) { if (prequestedssid == NULL)
return -1; goto out;
}
memset(&scancfg, 0x00, sizeof(scancfg)); memset(&scancfg, 0x00, sizeof(scancfg));
memcpy(scancfg.ssid, prequestedssid->ssid, prequestedssid->ssidlength);
memcpy(scancfg.specificSSID, prequestedssid->ssid, scancfg.ssid_len = prequestedssid->ssidlength;
prequestedssid->ssidlength); scancfg.clear_ssid = clear_ssid;
scancfg.keeppreviousscan = keeppreviousscan;
wlan_scan_networks(priv, &scancfg, 1); wlan_scan_networks(priv, &scancfg, 1);
if (adapter->surpriseremoved) if (adapter->surpriseremoved)
return -1; return -1;
wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
out:
lbs_deb_leave(LBS_DEB_ASSOC); lbs_deb_leave(LBS_DEB_ASSOC);
return 0; return ret;
} }
/** /**
...@@ -1469,19 +1492,18 @@ int libertas_send_specific_SSID_scan(wlan_private * priv, ...@@ -1469,19 +1492,18 @@ int libertas_send_specific_SSID_scan(wlan_private * priv,
* *
* @return 0-success, otherwise fail * @return 0-success, otherwise fail
*/ */
int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan) int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid)
{ {
struct wlan_ioctl_user_scan_cfg scancfg; struct wlan_ioctl_user_scan_cfg scancfg;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
if (bssid == NULL) { if (bssid == NULL)
return -1; goto out;
}
memset(&scancfg, 0x00, sizeof(scancfg)); memset(&scancfg, 0x00, sizeof(scancfg));
memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID)); memcpy(scancfg.bssid, bssid, ETH_ALEN);
scancfg.keeppreviousscan = keeppreviousscan; scancfg.clear_bssid = clear_bssid;
wlan_scan_networks(priv, &scancfg, 1); wlan_scan_networks(priv, &scancfg, 1);
if (priv->adapter->surpriseremoved) if (priv->adapter->surpriseremoved)
...@@ -1489,6 +1511,7 @@ int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppr ...@@ -1489,6 +1511,7 @@ int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppr
wait_event_interruptible(priv->adapter->cmd_pending, wait_event_interruptible(priv->adapter->cmd_pending,
!priv->adapter->nr_cmd_pending); !priv->adapter->nr_cmd_pending);
out:
lbs_deb_leave(LBS_DEB_ASSOC); lbs_deb_leave(LBS_DEB_ASSOC);
return 0; return 0;
} }
...@@ -1727,7 +1750,7 @@ int libertas_cmd_80211_scan(wlan_private * priv, ...@@ -1727,7 +1750,7 @@ int libertas_cmd_80211_scan(wlan_private * priv,
/* Set fixed field variables in scan command */ /* Set fixed field variables in scan command */
pscan->bsstype = pscancfg->bsstype; pscan->bsstype = pscancfg->bsstype;
memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID)); memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID));
memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
cmd->command = cpu_to_le16(cmd_802_11_scan); cmd->command = cpu_to_le16(cmd_802_11_scan);
......
...@@ -51,7 +51,7 @@ struct wlan_scan_cmd_config { ...@@ -51,7 +51,7 @@ struct wlan_scan_cmd_config {
/** /**
* @brief Specific BSSID used to filter scan results in the firmware * @brief Specific BSSID used to filter scan results in the firmware
*/ */
u8 specificBSSID[ETH_ALEN]; u8 bssid[ETH_ALEN];
/** /**
* @brief length of TLVs sent in command starting at tlvBuffer * @brief length of TLVs sent in command starting at tlvBuffer
...@@ -91,15 +91,6 @@ struct wlan_ioctl_user_scan_chan { ...@@ -91,15 +91,6 @@ struct wlan_ioctl_user_scan_chan {
* @sa libertas_set_user_scan_ioctl * @sa libertas_set_user_scan_ioctl
*/ */
struct wlan_ioctl_user_scan_cfg { struct wlan_ioctl_user_scan_cfg {
/**
* @brief Flag set to keep the previous scan table intact
*
* If set, the scan results will accumulate, replacing any previous
* matched entries for a BSS with the new scan data
*/
u8 keeppreviousscan; //!< Do not erase the existing scan results
/** /**
* @brief BSS type to be sent in the firmware command * @brief BSS type to be sent in the firmware command
* *
...@@ -117,15 +108,22 @@ struct wlan_ioctl_user_scan_cfg { ...@@ -117,15 +108,22 @@ struct wlan_ioctl_user_scan_cfg {
*/ */
u8 numprobes; u8 numprobes;
/** /**
* @brief BSSID filter sent in the firmware command to limit the results * @brief BSSID filter sent in the firmware command to limit the results
*/ */
u8 specificBSSID[ETH_ALEN]; u8 bssid[ETH_ALEN];
/** /* Clear existing scan results matching this BSSID */
* @brief SSID filter sent in the firmware command to limit the results u8 clear_bssid;
*/
char specificSSID[IW_ESSID_MAX_SIZE + 1]; /**
* @brief SSID filter sent in the firmware command to limit the results
*/
char ssid[IW_ESSID_MAX_SIZE];
u8 ssid_len;
/* Clear existing scan results matching this SSID */
u8 clear_ssid;
/** /**
* @brief Variable number (fixed maximum) of channels to scan up * @brief Variable number (fixed maximum) of channels to scan up
...@@ -194,9 +192,9 @@ int libertas_find_best_network_SSID(wlan_private * priv, ...@@ -194,9 +192,9 @@ int libertas_find_best_network_SSID(wlan_private * priv,
extern int libertas_send_specific_SSID_scan(wlan_private * priv, extern int libertas_send_specific_SSID_scan(wlan_private * priv,
struct WLAN_802_11_SSID *prequestedssid, struct WLAN_802_11_SSID *prequestedssid,
u8 keeppreviousscan); u8 clear_ssid);
extern int libertas_send_specific_BSSID_scan(wlan_private * priv, extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
u8 * bssid, u8 keeppreviousscan); u8 * bssid, u8 clear_bssid);
extern int libertas_cmd_80211_scan(wlan_private * priv, extern int libertas_cmd_80211_scan(wlan_private * priv,
struct cmd_ds_command *cmd, struct cmd_ds_command *cmd,
......
...@@ -234,7 +234,7 @@ static int changeadhocchannel(wlan_private * priv, int channel) ...@@ -234,7 +234,7 @@ static int changeadhocchannel(wlan_private * priv, int channel)
/* Scan for the network, do not save previous results. Stale /* Scan for the network, do not save previous results. Stale
* scan data will cause us to join a non-existant adhoc network * scan data will cause us to join a non-existant adhoc network
*/ */
libertas_send_specific_SSID_scan(priv, &curadhocssid, 0); libertas_send_specific_SSID_scan(priv, &curadhocssid, 1);
/* find out the BSSID that matches the current SSID */ /* find out the BSSID that matches the current SSID */
join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL, join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment