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

[PATCH] libertas: make scan result handling more flexible

- use a linked list for scan results
- age scan results
- pass bss_descriptors around instead of indexes into the scan table
- lock access to the scan results
- stop returning EAGAIN from SIOCGIWSCAN handler
Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 90e8eafc
...@@ -18,7 +18,7 @@ static int assoc_helper_essid(wlan_private *priv, ...@@ -18,7 +18,7 @@ static int assoc_helper_essid(wlan_private *priv,
{ {
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
int ret = 0; int ret = 0;
int i; struct bss_descriptor * bss;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
...@@ -28,17 +28,13 @@ static int assoc_helper_essid(wlan_private *priv, ...@@ -28,17 +28,13 @@ static int assoc_helper_essid(wlan_private *priv,
libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1); libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
} }
i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
NULL, IW_MODE_INFRA); NULL, IW_MODE_INFRA);
if (i >= 0) { if (bss != NULL) {
lbs_deb_assoc( lbs_deb_assoc("SSID found in scan list, associating\n");
"SSID found in scan list ... associating...\n"); ret = wlan_associate(priv, bss);
ret = wlan_associate(priv, &adapter->scantable[i]);
if (ret == 0) { if (ret == 0) {
memcpy(&assoc_req->bssid, memcpy(&assoc_req->bssid, bss->bssid, ETH_ALEN);
&adapter->scantable[i].bssid,
ETH_ALEN);
} }
} else { } else {
lbs_deb_assoc("SSID '%s' not found; cannot associate\n", lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
...@@ -51,11 +47,11 @@ static int assoc_helper_essid(wlan_private *priv, ...@@ -51,11 +47,11 @@ static int assoc_helper_essid(wlan_private *priv,
libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0); libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
/* Search for the requested SSID in the scan table */ /* Search for the requested SSID in the scan table */
i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL, bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
IW_MODE_ADHOC); IW_MODE_ADHOC);
if (i >= 0) { if (bss != NULL) {
lbs_deb_assoc("SSID found at %d in List, so join\n", ret); lbs_deb_assoc("SSID found joining\n");
libertas_join_adhoc_network(priv, &adapter->scantable[i]); libertas_join_adhoc_network(priv, bss);
} else { } else {
/* else send START command */ /* else send START command */
lbs_deb_assoc("SSID not found in list, so creating adhoc" lbs_deb_assoc("SSID not found in list, so creating adhoc"
...@@ -74,28 +70,28 @@ static int assoc_helper_bssid(wlan_private *priv, ...@@ -74,28 +70,28 @@ static int assoc_helper_bssid(wlan_private *priv,
struct assoc_request * assoc_req) struct assoc_request * assoc_req)
{ {
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
int i, ret = 0; int ret = 0;
struct bss_descriptor * bss;
lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n", lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n",
MAC_ARG(assoc_req->bssid)); MAC_ARG(assoc_req->bssid));
/* Search for index position in list for requested MAC */ /* Search for index position in list for requested MAC */
i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid, bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
assoc_req->mode); assoc_req->mode);
if (i < 0) { if (bss == NULL) {
lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, " lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
"cannot associate.\n", MAC_ARG(assoc_req->bssid)); "cannot associate.\n", MAC_ARG(assoc_req->bssid));
goto out; goto out;
} }
if (assoc_req->mode == IW_MODE_INFRA) { if (assoc_req->mode == IW_MODE_INFRA) {
ret = wlan_associate(priv, &adapter->scantable[i]); ret = wlan_associate(priv, bss);
lbs_deb_assoc("ASSOC: return from wlan_associate(bssd) was %d\n", ret); lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
} else if (assoc_req->mode == IW_MODE_ADHOC) { } else if (assoc_req->mode == IW_MODE_ADHOC) {
libertas_join_adhoc_network(priv, &adapter->scantable[i]); libertas_join_adhoc_network(priv, bss);
} }
memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid, memcpy(&assoc_req->ssid, &bss->ssid, sizeof(struct WLAN_802_11_SSID));
sizeof(struct WLAN_802_11_SSID));
out: out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
......
...@@ -63,35 +63,34 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, ...@@ -63,35 +63,34 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
int numscansdone = 0, res; int numscansdone = 0, res;
unsigned long addr = get_zeroed_page(GFP_KERNEL); unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr; char *buf = (char *)addr;
struct bss_descriptor * iter_bss;
pos += snprintf(buf+pos, len-pos, pos += snprintf(buf+pos, len-pos,
"# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
while (numscansdone < priv->adapter->numinscantable) { mutex_lock(&priv->adapter->lock);
struct bss_descriptor *pbssinfo; list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
u16 cap; u16 cap;
pbssinfo = &priv->adapter->scantable[numscansdone]; memcpy(&cap, &iter_bss->cap, sizeof(cap));
memcpy(&cap, &pbssinfo->cap, sizeof(cap));
pos += snprintf(buf+pos, len-pos, pos += snprintf(buf+pos, len-pos,
"%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |", "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
numscansdone, pbssinfo->channel, pbssinfo->rssi, numscansdone, iter_bss->channel, iter_bss->rssi,
pbssinfo->bssid[0], pbssinfo->bssid[1], iter_bss->bssid[0], iter_bss->bssid[1],
pbssinfo->bssid[2], pbssinfo->bssid[3], iter_bss->bssid[2], iter_bss->bssid[3],
pbssinfo->bssid[4], pbssinfo->bssid[5]); iter_bss->bssid[4], iter_bss->bssid[5]);
pos += snprintf(buf+pos, len-pos, " %04x-", cap); pos += snprintf(buf+pos, len-pos, " %04x-", cap);
pos += snprintf(buf+pos, len-pos, "%c%c%c |", pos += snprintf(buf+pos, len-pos, "%c%c%c |",
pbssinfo->cap.ibss ? 'A' : 'I', iter_bss->cap.ibss ? 'A' : 'I',
pbssinfo->cap.privacy ? 'P' : ' ', iter_bss->cap.privacy ? 'P' : ' ',
pbssinfo->cap.spectrummgmt ? 'S' : ' '); iter_bss->cap.spectrummgmt ? 'S' : ' ');
pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf); pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
pos += snprintf(buf+pos, len-pos, " %d |", pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", iter_bss->ssid.ssid);
pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
numscansdone++; numscansdone++;
} }
mutex_unlock(&priv->adapter->lock);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
......
...@@ -127,7 +127,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) ...@@ -127,7 +127,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
#define MRVDRV_NUM_OF_CMD_BUFFER 10 #define MRVDRV_NUM_OF_CMD_BUFFER 10
#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) #define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
#define MRVDRV_MAX_CHANNEL_SIZE 14 #define MRVDRV_MAX_CHANNEL_SIZE 14
#define MRVDRV_MAX_BSSID_LIST 64
#define MRVDRV_ASSOCIATION_TIME_OUT 255 #define MRVDRV_ASSOCIATION_TIME_OUT 255
#define MRVDRV_SNAP_HEADER_LEN 8 #define MRVDRV_SNAP_HEADER_LEN 8
......
...@@ -257,8 +257,10 @@ struct _wlan_adapter { ...@@ -257,8 +257,10 @@ struct _wlan_adapter {
struct WLAN_802_11_SSID previousssid; struct WLAN_802_11_SSID previousssid;
u8 previousbssid[ETH_ALEN]; u8 previousbssid[ETH_ALEN];
struct bss_descriptor *scantable; /* Scan results list */
u32 numinscantable; struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
u8 scantype; u8 scantype;
u32 scanmode; u32 scanmode;
......
...@@ -126,18 +126,17 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) ...@@ -126,18 +126,17 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name)
static int wlan_allocate_adapter(wlan_private * priv) static int wlan_allocate_adapter(wlan_private * priv)
{ {
u32 ulbufsize; size_t bufsize;
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
struct bss_descriptor *ptempscantable;
/* Allocate buffer to store the BSSID list */ /* Allocate buffer to store the BSSID list */
ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
if (!(ptempscantable = kzalloc(ulbufsize, GFP_KERNEL))) { adapter->networks = kzalloc(bufsize, GFP_KERNEL);
if (!adapter->networks) {
lbs_pr_err("Out of memory allocating beacons\n");
libertas_free_adapter(priv); libertas_free_adapter(priv);
return -1; return -ENOMEM;
} }
adapter->scantable = ptempscantable;
/* Allocate the command buffers */ /* Allocate the command buffers */
libertas_allocate_cmd_buffer(priv); libertas_allocate_cmd_buffer(priv);
...@@ -188,7 +187,14 @@ static void wlan_init_adapter(wlan_private * priv) ...@@ -188,7 +187,14 @@ static void wlan_init_adapter(wlan_private * priv)
adapter->assoc_req = NULL; adapter->assoc_req = NULL;
adapter->numinscantable = 0; /* Initialize scan result lists */
INIT_LIST_HEAD(&adapter->network_free_list);
INIT_LIST_HEAD(&adapter->network_list);
for (i = 0; i < MAX_NETWORK_COUNT; i++) {
list_add_tail(&adapter->networks[i].list,
&adapter->network_free_list);
}
adapter->pattemptedbssdesc = NULL; adapter->pattemptedbssdesc = NULL;
mutex_init(&adapter->lock); mutex_init(&adapter->lock);
...@@ -291,11 +297,9 @@ void libertas_free_adapter(wlan_private * priv) ...@@ -291,11 +297,9 @@ void libertas_free_adapter(wlan_private * priv)
lbs_deb_fw("free command_timer\n"); lbs_deb_fw("free command_timer\n");
del_timer(&adapter->command_timer); del_timer(&adapter->command_timer);
lbs_deb_fw("free scantable\n"); lbs_deb_fw("free scan results table\n");
if (adapter->scantable) { kfree(adapter->networks);
kfree(adapter->scantable); adapter->networks = NULL;
adapter->scantable = NULL;
}
/* Free the adapter object itself */ /* Free the adapter object itself */
lbs_deb_fw("free adapter\n"); lbs_deb_fw("free adapter\n");
......
This diff is collapsed.
...@@ -156,9 +156,9 @@ struct bss_descriptor { ...@@ -156,9 +156,9 @@ struct bss_descriptor {
u8 mode; u8 mode;
u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
int extra_ie;
u8 timestamp[8]; //!< TSF value included in the beacon/probe response u8 timestamp[8]; //!< TSF value included in the beacon/probe response
unsigned long last_scanned;
union ieeetypes_phyparamset phyparamset; union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset; union IEEEtypes_ssparamset ssparamset;
struct ieeetypes_capinfo cap; struct ieeetypes_capinfo cap;
...@@ -172,14 +172,21 @@ struct bss_descriptor { ...@@ -172,14 +172,21 @@ struct bss_descriptor {
size_t wpa_ie_len; size_t wpa_ie_len;
u8 rsn_ie[MAX_WPA_IE_LEN]; u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len; size_t rsn_ie_len;
struct list_head list;
}; };
extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
struct WLAN_802_11_SSID *ssid2); struct WLAN_802_11_SSID *ssid2);
extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
u8 * bssid, u8 mode); struct bss_descriptor * libertas_find_SSID_in_list(wlan_adapter * adapter,
int libertas_find_best_SSID_in_list(wlan_adapter * adapter, u8 mode); struct WLAN_802_11_SSID *ssid, u8 * bssid, u8 mode);
extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode);
struct bss_descriptor * libertas_find_best_SSID_in_list(wlan_adapter * adapter,
u8 mode);
extern struct bss_descriptor * libertas_find_BSSID_in_list(wlan_adapter * adapter,
u8 * bssid, u8 mode);
int libertas_find_best_network_SSID(wlan_private * priv, int libertas_find_best_network_SSID(wlan_private * priv,
struct WLAN_802_11_SSID *pSSID, struct WLAN_802_11_SSID *pSSID,
......
...@@ -189,6 +189,8 @@ static int setcurrentchannel(wlan_private * priv, int channel) ...@@ -189,6 +189,8 @@ static int setcurrentchannel(wlan_private * priv, int channel)
static int changeadhocchannel(wlan_private * priv, int channel) static int changeadhocchannel(wlan_private * priv, int channel)
{ {
int ret = 0; int ret = 0;
struct WLAN_802_11_SSID curadhocssid;
struct bss_descriptor * join_bss = NULL;
wlan_adapter *adapter = priv->adapter; wlan_adapter *adapter = priv->adapter;
adapter->adhocchannel = channel; adapter->adhocchannel = channel;
...@@ -214,43 +216,38 @@ static int changeadhocchannel(wlan_private * priv, int channel) ...@@ -214,43 +216,38 @@ static int changeadhocchannel(wlan_private * priv, int channel)
goto out; goto out;
} }
if (adapter->connect_status == libertas_connected) { if (adapter->connect_status != libertas_connected)
int i; goto out;
struct WLAN_802_11_SSID curadhocssid;
lbs_deb_wext("channel changed while in IBSS\n");
/* Copy the current ssid */ lbs_deb_wext("channel changed while in IBSS\n");
memcpy(&curadhocssid, &adapter->curbssparams.ssid,
sizeof(struct WLAN_802_11_SSID));
/* Exit Adhoc mode */ /* Copy the current ssid */
lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n"); memcpy(&curadhocssid, &adapter->curbssparams.ssid,
ret = libertas_stop_adhoc_network(priv); sizeof(struct WLAN_802_11_SSID));
if (ret) /* Exit Adhoc mode */
goto out; lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n");
ret = libertas_stop_adhoc_network(priv);
if (ret)
goto out;
/* 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, 0);
// find out the BSSID that matches the current SSID /* find out the BSSID that matches the current SSID */
i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL, join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
IW_MODE_ADHOC); IW_MODE_ADHOC);
if (i >= 0) { if (join_bss) {
lbs_deb_wext("SSID found at %d in list," lbs_deb_wext("SSID found in list, so join\n");
"so join\n", i); libertas_join_adhoc_network(priv, join_bss);
libertas_join_adhoc_network(priv, &adapter->scantable[i]); } else {
} else { lbs_deb_wext("SSID not found in list, "
// else send START command "creating AdHoc with SSID '%s'\n",
lbs_deb_wext("SSID not found in list, " curadhocssid.ssid);
"creating AdHoc with SSID '%s'\n", libertas_start_adhoc_network(priv, &curadhocssid);
curadhocssid.ssid);
libertas_start_adhoc_network(priv, &curadhocssid);
} // end of else (START command)
} }
out: out:
......
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