Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 90561
b: refs/heads/master
c: 245bf20
h: refs/heads/master
i:
  90559: 8966984
v: v3
  • Loading branch information
Holger Schurig authored and John W. Linville committed Apr 8, 2008
1 parent 0b0526c commit e762ce2
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 425 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 697900ac14528e985b66f471ecb81082fc00baa9
refs/heads/master: 245bf20f9c159f8d35befbc038997096b759459c
352 changes: 352 additions & 0 deletions trunk/drivers/net/wireless/libertas/assoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "assoc.h"
#include "decl.h"
#include "host.h"
#include "scan.h"
#include "cmd.h"


Expand Down Expand Up @@ -170,6 +171,272 @@ int lbs_stop_adhoc_network(struct lbs_private *priv)
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)
{
Expand Down Expand Up @@ -617,6 +884,91 @@ static int should_stop_adhoc(struct lbs_private *priv,
}


/**
* @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,
Expand Down
Loading

0 comments on commit e762ce2

Please sign in to comment.