summaryrefslogtreecommitdiff
path: root/net/mac80211/ieee80211_sta.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r--net/mac80211/ieee80211_sta.c113
1 files changed, 72 insertions, 41 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 91b545c144c1..0d99b685df5f 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -25,7 +25,6 @@
#include <linux/wireless.h>
#include <linux/random.h>
#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
#include <net/iw_handler.h>
#include <asm/types.h>
@@ -76,33 +75,36 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
/* Parsed Information Elements */
struct ieee802_11_elems {
+ /* pointers to IEs */
u8 *ssid;
- u8 ssid_len;
u8 *supp_rates;
- u8 supp_rates_len;
u8 *fh_params;
- u8 fh_params_len;
u8 *ds_params;
- u8 ds_params_len;
u8 *cf_params;
- u8 cf_params_len;
u8 *tim;
- u8 tim_len;
u8 *ibss_params;
- u8 ibss_params_len;
u8 *challenge;
- u8 challenge_len;
u8 *wpa;
- u8 wpa_len;
u8 *rsn;
- u8 rsn_len;
u8 *erp_info;
- u8 erp_info_len;
u8 *ext_supp_rates;
- u8 ext_supp_rates_len;
u8 *wmm_info;
- u8 wmm_info_len;
u8 *wmm_param;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
u8 wmm_param_len;
};
@@ -311,6 +313,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
}
+static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+ if (use_protection != sdata->use_protection) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+ MAC_FMT ")\n",
+ dev->name,
+ use_protection ? "enabled" : "disabled",
+ MAC_ARG(ifsta->bssid));
+ }
+ sdata->use_protection = use_protection;
+ }
+}
+
+
static void ieee80211_sta_send_associnfo(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
@@ -366,6 +387,7 @@ static void ieee80211_set_associated(struct net_device *dev,
struct ieee80211_if_sta *ifsta, int assoc)
{
union iwreq_data wrqu;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (ifsta->associated == assoc)
return;
@@ -374,9 +396,18 @@ static void ieee80211_set_associated(struct net_device *dev,
if (assoc) {
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sta_bss *bss;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA)
return;
+
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ if (bss->has_erp_value)
+ ieee80211_handle_erp_ie(dev, bss->erp_value);
+ ieee80211_rx_bss_put(dev, bss);
+ }
+
netif_carrier_on(dev);
ifsta->prev_bssid_set = 1;
memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
@@ -384,6 +415,7 @@ static void ieee80211_set_associated(struct net_device *dev,
ieee80211_sta_send_associnfo(dev, ifsta);
} else {
netif_carrier_off(dev);
+ sdata->use_protection = 0;
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
}
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -1174,6 +1206,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
return;
}
+ /* it probably doesn't, but if the frame includes an ERP value then
+ * update our stored copy */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ struct ieee80211_sta_bss *bss
+ = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ ieee80211_rx_bss_put(dev, bss);
+ }
+ }
+
printk(KERN_DEBUG "%s: associated\n", dev->name);
ifsta->aid = aid;
ifsta->ap_capab = capab_info;
@@ -1282,10 +1326,9 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
if (!bss)
return NULL;
- memset(bss, 0, sizeof(*bss));
atomic_inc(&bss->users);
atomic_inc(&bss->users);
memcpy(bss->bssid, bssid, ETH_ALEN);
@@ -1496,6 +1539,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
return;
}
+ /* save the ERP value so that it is available at association time */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
@@ -1611,10 +1660,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
size_t len,
struct ieee80211_rx_status *rx_status)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_sta *ifsta;
- int use_protection;
size_t baselen;
struct ieee802_11_elems elems;
@@ -1638,23 +1685,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
&elems) == ParseFailed)
return;
- use_protection = 0;
- if (elems.erp_info && elems.erp_info_len >= 1) {
- use_protection =
- (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
- }
-
- if (use_protection != !!ifsta->use_protection) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
- MAC_FMT ")\n",
- dev->name,
- use_protection ? "enabled" : "disabled",
- MAC_ARG(ifsta->bssid));
- }
- ifsta->use_protection = use_protection ? 1 : 0;
- local->cts_protect_erp_frames = use_protection;
- }
+ if (elems.erp_info && elems.erp_info_len >= 1)
+ ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
if (elems.wmm_param && ifsta->wmm_enabled) {
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
@@ -2073,12 +2105,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_sta_bss *bss, *selected = NULL;
int top_rssi = 0, freq;
- rtnl_lock();
-
if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
!ifsta->auto_ssid_sel) {
ifsta->state = IEEE80211_AUTHENTICATE;
- rtnl_unlock();
ieee80211_sta_reset_auth(dev, ifsta);
return 0;
}
@@ -2121,18 +2150,20 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
ieee80211_sta_set_bssid(dev, selected->bssid);
ieee80211_rx_bss_put(dev, selected);
ifsta->state = IEEE80211_AUTHENTICATE;
- rtnl_unlock();
ieee80211_sta_reset_auth(dev, ifsta);
return 0;
} else {
if (ifsta->state != IEEE80211_AUTHENTICATE) {
- ieee80211_sta_start_scan(dev, NULL, 0);
+ if (ifsta->auto_ssid_sel)
+ ieee80211_sta_start_scan(dev, NULL, 0);
+ else
+ ieee80211_sta_start_scan(dev, ifsta->ssid,
+ ifsta->ssid_len);
ifsta->state = IEEE80211_AUTHENTICATE;
set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
} else
ifsta->state = IEEE80211_DISABLED;
}
- rtnl_unlock();
return -1;
}