Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ static int assoc_helper_essid(wlan_private *priv,
	lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
	if (assoc_req->mode == IW_MODE_INFRA) {
		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,
@@ -44,7 +44,7 @@ static int assoc_helper_essid(wlan_private *priv,
		/* Scan for the network, do not save previous results.  Stale
		 *   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 */
		bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+11 −15
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
	memcpy(&extscan_ssid.ssid, buf, 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));
	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -245,16 +245,13 @@ static void libertas_parse_bssid(char *buf, size_t count,
{
	char *hold;
	unsigned int mac[ETH_ALEN];
	int i;

	hold = strstr(buf, "bssid=");
	if (!hold)
		return;
	hold += 6;
	sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
			mac+4, mac+5);
	for(i=0;i<ETH_ALEN;i++)
		scan_cfg->specificBSSID[i] = mac[i];
	sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
	memcpy(scan_cfg->bssid, mac, ETH_ALEN);
}

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;

	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;
}

static void libertas_parse_keep(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
static int libertas_parse_clear(char *buf, size_t count, const char *tag)
{
	char *hold;
	int val;

	hold = strstr(buf, "keep=");
	hold = strstr(buf, tag);
	if (!hold)
		return;
	hold += 5;
		return 0;
	hold += strlen(tag);
	sscanf(hold, "%d", &val);

	if (val != 0)
		val = 1;

	scan_cfg->keeppreviousscan = val;
	return;
	return val;
}

static int libertas_parse_dur(char *buf, size_t count,
@@ -376,8 +371,9 @@ static ssize_t libertas_setuserscan(struct file *file,
	dur = libertas_parse_dur(buf, count, scan_cfg);
	libertas_parse_chan(buf, count, scan_cfg, dur);
	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_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_type(buf, count, scan_cfg);

+77 −54
Original line number Diff line number Diff line
@@ -59,6 +59,9 @@
//! Scan time specified in the channel TLV for each channel for active scans
#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)
{
	/* Don't blow away ->list, just BSS data */
@@ -409,13 +412,11 @@ wlan_scan_setup_scan_config(wlan_private * priv,
			    u8 * pscancurrentonly)
{
	wlan_adapter *adapter = priv->adapter;
	const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
	struct mrvlietypes_numprobes *pnumprobestlv;
	struct mrvlietypes_ssidparamset *pssidtlv;
	struct wlan_scan_cmd_config * pscancfgout = NULL;
	u8 *ptlvpos;
	u16 numprobes;
	u16 ssidlen;
	int chanidx;
	int scantype;
	int scandur;
@@ -472,21 +473,18 @@ wlan_scan_setup_scan_config(wlan_private * priv,
		 * Set the BSSID filter to the incoming configuration,
		 *   if non-zero.  If not set, it will remain disabled (all zeros).
		 */
		memcpy(pscancfgout->specificBSSID,
		       puserscanin->specificBSSID,
		       sizeof(pscancfgout->specificBSSID));

		ssidlen = strlen(puserscanin->specificSSID);
		memcpy(pscancfgout->bssid, puserscanin->bssid,
		       sizeof(pscancfgout->bssid));

		if (ssidlen) {
		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(ssidlen);
			memcpy(pssidtlv->ssid, puserscanin->specificSSID,
			       ssidlen);
			ptlvpos += sizeof(pssidtlv->header) + ssidlen;
			pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
			memcpy(pssidtlv->ssid, puserscanin->ssid,
			       puserscanin->ssid_len);
			ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
		}

		/*
@@ -495,8 +493,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
		 *    scan results.  That is not an issue with an SSID or BSSID
		 *    filter applied to the scan results in the firmware.
		 */
		if (ssidlen || (memcmp(pscancfgout->specificBSSID,
				       &zeromac, sizeof(zeromac)) != 0)) {
		if (   puserscanin->ssid_len
		    || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
			*pfilteredscan = 1;
		}
@@ -743,6 +741,53 @@ static int wlan_scan_channel_list(wlan_private * priv,
	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
 *
@@ -764,7 +809,6 @@ int wlan_scan_networks(wlan_private * priv,
	struct mrvlietypes_chanlistparamset *pchantlvout;
	struct chanscanparamset * scan_chan_list = NULL;
	struct wlan_scan_cmd_config * scan_cfg = NULL;
	u8 keeppreviousscan;
	u8 filteredscan;
	u8 scancurrentchanonly;
	int maxchanperscan;
@@ -791,28 +835,7 @@ int wlan_scan_networks(wlan_private * priv,
		goto out;
	}

	keeppreviousscan = 0;

	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);
	}
	clear_selected_scan_list_entries(adapter, puserscanin);

	/* Keep the data path active if we are only scanning our current channel */
	if (!scancurrentchanonly) {
@@ -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,
			 struct WLAN_802_11_SSID *prequestedssid,
			 u8 keeppreviousscan)
			 u8 clear_ssid)
{
	wlan_adapter *adapter = priv->adapter;
	struct wlan_ioctl_user_scan_cfg scancfg;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_ASSOC);

	if (prequestedssid == NULL) {
		return -1;
	}
	if (prequestedssid == NULL)
		goto out;

	memset(&scancfg, 0x00, sizeof(scancfg));

	memcpy(scancfg.specificSSID, prequestedssid->ssid,
	       prequestedssid->ssidlength);
	scancfg.keeppreviousscan = keeppreviousscan;
	memcpy(scancfg.ssid, prequestedssid->ssid, prequestedssid->ssidlength);
	scancfg.ssid_len = prequestedssid->ssidlength;
	scancfg.clear_ssid = clear_ssid;

	wlan_scan_networks(priv, &scancfg, 1);
	if (adapter->surpriseremoved)
		return -1;
	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);

out:
	lbs_deb_leave(LBS_DEB_ASSOC);
	return 0;
	return ret;
}

/**
@@ -1469,19 +1492,18 @@ int libertas_send_specific_SSID_scan(wlan_private * priv,
 *
 *  @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;

	lbs_deb_enter(LBS_DEB_ASSOC);

	if (bssid == NULL) {
		return -1;
	}
	if (bssid == NULL)
		goto out;

	memset(&scancfg, 0x00, sizeof(scancfg));
	memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
	scancfg.keeppreviousscan = keeppreviousscan;
	memcpy(scancfg.bssid, bssid, ETH_ALEN);
	scancfg.clear_bssid = clear_bssid;

	wlan_scan_networks(priv, &scancfg, 1);
	if (priv->adapter->surpriseremoved)
@@ -1489,6 +1511,7 @@ int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppr
	wait_event_interruptible(priv->adapter->cmd_pending,
		!priv->adapter->nr_cmd_pending);

out:
	lbs_deb_leave(LBS_DEB_ASSOC);
	return 0;
}
@@ -1727,7 +1750,7 @@ int libertas_cmd_80211_scan(wlan_private * priv,

	/* Set fixed field variables in scan command */
	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);

	cmd->command = cpu_to_le16(cmd_802_11_scan);
+18 −20
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ struct wlan_scan_cmd_config {
    /**
     *  @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
@@ -91,15 +91,6 @@ struct wlan_ioctl_user_scan_chan {
 *  @sa libertas_set_user_scan_ioctl
 */
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
     *
@@ -120,12 +111,19 @@ struct wlan_ioctl_user_scan_cfg {
	/**
	 *  @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 */
	u8 clear_bssid;

	/**
	 *  @brief SSID filter sent in the firmware command to limit the results
	 */
	char specificSSID[IW_ESSID_MAX_SIZE + 1];
	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
@@ -194,9 +192,9 @@ int libertas_find_best_network_SSID(wlan_private * priv,

extern int libertas_send_specific_SSID_scan(wlan_private * priv,
				struct WLAN_802_11_SSID *prequestedssid,
				u8 keeppreviousscan);
				u8 clear_ssid);
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,
				struct cmd_ds_command *cmd,
+1 −1
Original line number Diff line number Diff line
@@ -234,7 +234,7 @@ static int changeadhocchannel(wlan_private * priv, int channel)
	/* Scan for the network, do not save previous results.  Stale
	 *   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 */
	join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,