libertas: move association code from scan.c into assoc.c

Besides code moving, I did the following changes:

* made some functions static
* removed some unneeded #include's
* made patch checkpatch.pl clean

Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index e794e93..319b4f9 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -5,6 +5,7 @@
 #include "assoc.h"
 #include "decl.h"
 #include "host.h"
+#include "scan.h"
 #include "cmd.h"
 
 
@@ -170,6 +171,272 @@
 				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
+static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
+					struct bss_descriptor *match_bss)
+{
+	if (!secinfo->wep_enabled  && !secinfo->WPAenabled
+	    && !secinfo->WPA2enabled
+	    && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
+	    && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+	    && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
+				       struct bss_descriptor *match_bss)
+{
+	if (secinfo->wep_enabled && !secinfo->WPAenabled
+	    && !secinfo->WPA2enabled
+	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
+				struct bss_descriptor *match_bss)
+{
+	if (!secinfo->wep_enabled && secinfo->WPAenabled
+	    && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+	   )
+		return 1;
+	else
+		return 0;
+}
+
+static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
+				 struct bss_descriptor *match_bss)
+{
+	if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
+	    (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+	    (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
+	   )
+		return 1;
+	else
+		return 0;
+}
+
+static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
+					struct bss_descriptor *match_bss)
+{
+	if (!secinfo->wep_enabled && !secinfo->WPAenabled
+	    && !secinfo->WPA2enabled
+	    && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+	    && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @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(struct lbs_private *priv,
+				 struct bss_descriptor *bss, uint8_t mode)
+{
+	int matched = 0;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	if (bss->mode != mode)
+		goto done;
+
+	matched = match_bss_no_security(&priv->secinfo, bss);
+	if (matched)
+		goto done;
+	matched = match_bss_static_wep(&priv->secinfo, bss);
+	if (matched)
+		goto done;
+	matched = match_bss_wpa(&priv->secinfo, bss);
+	if (matched) {
+		lbs_deb_scan("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;
+	}
+	matched = match_bss_wpa2(&priv->secinfo, bss);
+	if (matched) {
+		lbs_deb_scan("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;
+	}
+	matched = match_bss_dynamic_wep(&priv->secinfo, bss);
+	if (matched) {
+		lbs_deb_scan("is_network_compatible() dynamic WEP: "
+			     "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;
+	}
+
+	/* bss security settings don't match those configured on card */
+	lbs_deb_scan("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],
+		     priv->secinfo.wep_enabled ? "e" : "d",
+		     priv->secinfo.WPAenabled ? "e" : "d",
+		     priv->secinfo.WPA2enabled ? "e" : "d",
+		     (bss->capability & WLAN_CAPABILITY_PRIVACY));
+
+done:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
+	return matched;
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  Used in association code
+ *
+ *  @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)
+ */
+static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
+					      uint8_t *bssid, uint8_t mode)
+{
+	struct bss_descriptor *iter_bss;
+	struct bss_descriptor *found_bss = NULL;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	if (!bssid)
+		goto out;
+
+	lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
+
+	/* Look through the scan table for a compatible match.  The loop will
+	 *   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(&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(priv, iter_bss, mode))
+				break;
+			found_bss = iter_bss;
+			break;
+		default:
+			found_bss = iter_bss;
+			break;
+		}
+	}
+	mutex_unlock(&priv->lock);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+	return found_bss;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  Used in association code
+ *
+ *  @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
+ */
+static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
+					     uint8_t *ssid, uint8_t ssid_len,
+					     uint8_t *bssid, uint8_t mode,
+					     int channel)
+{
+	u32 bestrssi = 0;
+	struct bss_descriptor *iter_bss = NULL;
+	struct bss_descriptor *found_bss = NULL;
+	struct bss_descriptor *tmp_oldest = NULL;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	mutex_lock(&priv->lock);
+
+	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 (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)
+			continue; /* bssid doesn't match */
+		if ((channel > 0) && (iter_bss->channel != channel))
+			continue; /* channel doesn't match */
+
+		switch (mode) {
+		case IW_MODE_INFRA:
+		case IW_MODE_ADHOC:
+			if (!is_network_compatible(priv, iter_bss, mode))
+				break;
+
+			if (bssid) {
+				/* Found requested BSSID */
+				found_bss = iter_bss;
+				goto out;
+			}
+
+			if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
+				bestrssi = SCAN_RSSI(iter_bss->rssi);
+				found_bss = iter_bss;
+			}
+			break;
+		case IW_MODE_AUTO:
+		default:
+			if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
+				bestrssi = SCAN_RSSI(iter_bss->rssi);
+				found_bss = iter_bss;
+			}
+			break;
+		}
+	}
+
+out:
+	mutex_unlock(&priv->lock);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
+	return found_bss;
+}
+
 static int assoc_helper_essid(struct lbs_private *priv,
                               struct assoc_request * assoc_req)
 {
@@ -617,6 +884,91 @@
 }
 
 
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param priv  A pointer to struct lbs_private
+ *
+ *  @return         index in BSSID list
+ */
+static struct bss_descriptor *lbs_find_best_ssid_in_list(
+	struct lbs_private *priv, uint8_t mode)
+{
+	uint8_t bestrssi = 0;
+	struct bss_descriptor *iter_bss;
+	struct bss_descriptor *best_bss = NULL;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	mutex_lock(&priv->lock);
+
+	list_for_each_entry(iter_bss, &priv->network_list, list) {
+		switch (mode) {
+		case IW_MODE_INFRA:
+		case IW_MODE_ADHOC:
+			if (!is_network_compatible(priv, iter_bss, mode))
+				break;
+			if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
+				break;
+			bestrssi = SCAN_RSSI(iter_bss->rssi);
+			best_bss = iter_bss;
+			break;
+		case IW_MODE_AUTO:
+		default:
+			if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
+				break;
+			bestrssi = SCAN_RSSI(iter_bss->rssi);
+			best_bss = iter_bss;
+			break;
+		}
+	}
+
+	mutex_unlock(&priv->lock);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
+	return best_bss;
+}
+
+/**
+ *  @brief Find the best AP
+ *
+ *  Used from association worker.
+ *
+ *  @param priv         A pointer to struct lbs_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             0--success, otherwise--fail
+ */
+static int lbs_find_best_network_ssid(struct lbs_private *priv,
+	uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
+	uint8_t *out_mode)
+{
+	int ret = -1;
+	struct bss_descriptor *found;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	priv->scan_ssid_len = 0;
+	lbs_scan_networks(priv, 1);
+	if (priv->surpriseremoved)
+		goto out;
+
+	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;
+		*out_mode = found->mode;
+		ret = 0;
+	}
+
+out:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+	return ret;
+}
+
+
 void lbs_association_worker(struct work_struct *work)
 {
 	struct lbs_private *priv = container_of(work, struct lbs_private,