diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 144 |
1 files changed, 97 insertions, 47 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bdaab1391d4..6b75cb6c630 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -350,14 +350,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, } } - -static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, - u8 erp_value) +static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, + bool use_protection, + bool use_short_preamble) { struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; struct ieee80211_if_sta *ifsta = &sdata->u.sta; - bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; DECLARE_MAC_BUF(mac); u32 changed = 0; @@ -388,6 +386,32 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, return changed; } +static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, + u8 erp_value) +{ + bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; + + return ieee80211_handle_protect_preamb(sdata, + use_protection, use_short_preamble); +} + +static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta_bss *bss) +{ + u32 changed = 0; + + if (bss->has_erp_value) + changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value); + else { + u16 capab = bss->capability; + changed |= ieee80211_handle_protect_preamb(sdata, false, + (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + } + + return changed; +} + int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, struct ieee80211_ht_info *ht_info) { @@ -511,9 +535,7 @@ static void ieee80211_set_associated(struct net_device *dev, sdata->bss_conf.beacon_int = bss->beacon_int; sdata->bss_conf.timestamp = bss->timestamp; - if (bss->has_erp_value) - changed |= ieee80211_handle_erp_ie( - sdata, bss->erp_value); + changed |= ieee80211_handle_bss_capability(sdata, bss); ieee80211_rx_bss_put(dev, bss); } @@ -2566,22 +2588,29 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } - bss->band = rx_status->band; - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - bss->probe_resp && beacon) { - /* STA mode: - * Do not allow beacon to override data from Probe Response. */ - ieee80211_rx_bss_put(dev, bss); - 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; } + if (elems.ht_cap_elem && + (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || + memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { + kfree(bss->ht_ie); + bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); + if (bss->ht_ie) { + memcpy(bss->ht_ie, elems.ht_cap_elem - 2, + elems.ht_cap_elem_len + 2); + bss->ht_ie_len = elems.ht_cap_elem_len + 2; + } else + bss->ht_ie_len = 0; + } else if (!elems.ht_cap_elem && bss->ht_ie) { + kfree(bss->ht_ie); + bss->ht_ie = NULL; + bss->ht_ie_len = 0; + } + bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); @@ -2603,6 +2632,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->supp_rates_len += clen; } + bss->band = rx_status->band; + + bss->timestamp = beacon_timestamp; + bss->last_update = jiffies; + bss->rssi = rx_status->ssi; + bss->signal = rx_status->signal; + bss->noise = rx_status->noise; + if (!beacon && !bss->probe_resp) + bss->probe_resp = true; + + /* + * In STA mode, the remaining parameters should not be overridden + * by beacons because they're not necessarily accurate there. + */ + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + bss->probe_resp && beacon) { + ieee80211_rx_bss_put(dev, bss); + return; + } + if (elems.wpa && (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { @@ -2635,6 +2684,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->rsn_ie_len = 0; } + /* + * Cf. + * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC + * + * quoting: + * + * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia + * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi + * Alliance (September 1, 2004) is incorporated by reference herein. + * The inclusion of the WMM Parameters in probe responses and + * association responses is mandatory for WMM enabled networks. The + * inclusion of the WMM Parameters in beacons, however, is optional. + */ + if (elems.wmm_param && (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { @@ -2651,30 +2714,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->wmm_ie = NULL; bss->wmm_ie_len = 0; } - if (elems.ht_cap_elem && - (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || - memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { - kfree(bss->ht_ie); - bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); - if (bss->ht_ie) { - memcpy(bss->ht_ie, elems.ht_cap_elem - 2, - elems.ht_cap_elem_len + 2); - bss->ht_ie_len = elems.ht_cap_elem_len + 2; - } else - bss->ht_ie_len = 0; - } else if (!elems.ht_cap_elem && bss->ht_ie) { - kfree(bss->ht_ie); - bss->ht_ie = NULL; - bss->ht_ie_len = 0; - } - - bss->timestamp = beacon_timestamp; - bss->last_update = jiffies; - bss->rssi = rx_status->ssi; - bss->signal = rx_status->signal; - bss->noise = rx_status->noise; - if (!beacon) - bss->probe_resp++; /* check if we need to merge IBSS */ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && @@ -2775,8 +2814,24 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); + } + + /* Do not send changes to driver if we are scanning. This removes + * requirement that driver's bss_info_changed function needs to be + * atomic. */ + if (local->sta_sw_scanning || local->sta_hw_scanning) + return; + if (elems.erp_info && elems.erp_info_len >= 1) changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); + else { + u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info); + changed |= ieee80211_handle_protect_preamb(sdata, false, + (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + } if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { @@ -2789,11 +2844,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, &bss_info); } - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } - ieee80211_bss_info_change_notify(sdata, changed); } |