diff options
author | Sara Sharon <sara.sharon@intel.com> | 2019-01-16 18:22:56 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-02-08 13:56:37 +0100 |
commit | 78ac51f81532c1e361a31ac112c1fea470ea9036 (patch) | |
tree | 902a6460da1d4ee980bba2220151b931b520a6a9 /net/mac80211/mlme.c | |
parent | 0cd01efb03396c5368b1a32eed0ccb2aa453bdc8 (diff) | |
download | linux-78ac51f81532c1e361a31ac112c1fea470ea9036.tar.gz linux-78ac51f81532c1e361a31ac112c1fea470ea9036.tar.bz2 linux-78ac51f81532c1e361a31ac112c1fea470ea9036.zip |
mac80211: support multi-bssid
Add support for multi-bssid.
This includes:
- Parsing multi-bssid element
- Overriding DTIM values
- Taking into account in various places the inner BSSID instead of
transmitter BSSID
- Save aside some multi-bssid properties needed by drivers
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 125 |
1 files changed, 88 insertions, 37 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1f41f760bd22..64b6ddb67456 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3308,6 +3308,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, /* TODO: OPEN: what happens if BSS color disable is set? */ } + if (cbss->transmitted_bss) { + bss_conf->nontransmitted = true; + ether_addr_copy(bss_conf->transmitter_bssid, + cbss->transmitted_bss->bssid); + bss_conf->bssid_indicator = cbss->max_bssid_indicator; + bss_conf->bssid_index = cbss->bssid_index; + } + /* * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data * in their association response, so ignore that data for our own @@ -3692,6 +3700,16 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata, } } +static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, + struct cfg80211_bss *bss) +{ + if (ether_addr_equal(tx_bssid, bss->bssid)) + return true; + if (!bss->transmitted_bss) + return false; + return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid); +} + static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) @@ -3733,17 +3751,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && - ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { + ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) { ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, false, &elems, mgmt->bssid, ifmgd->assoc_data->bss->bssid); ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); - if (elems.tim && !elems.parse_error) { - const struct ieee80211_tim_ie *tim_ie = elems.tim; - ifmgd->dtim_period = tim_ie->dtim_period; - } + + if (elems.dtim_period) + ifmgd->dtim_period = elems.dtim_period; ifmgd->have_beacon = true; ifmgd->assoc_data->need_beacon = false; if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { @@ -3751,12 +3768,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, le64_to_cpu(mgmt->u.beacon.timestamp); sdata->vif.bss_conf.sync_device_ts = rx_status->device_timestamp; - if (elems.tim) - sdata->vif.bss_conf.sync_dtim_count = - elems.tim->dtim_count; - else - sdata->vif.bss_conf.sync_dtim_count = 0; + sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; } + + if (elems.mbssid_config_ie) + bss_conf->profile_periodicity = + elems.mbssid_config_ie->profile_periodicity; + + if (elems.ext_capab_len >= 11 && + (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + bss_conf->ema_ap = true; + /* continue assoc process */ ifmgd->assoc_data->timeout = jiffies; ifmgd->assoc_data->timeout_started = true; @@ -3765,7 +3787,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (!ifmgd->associated || - !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) + !ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->associated)) return; bssid = ifmgd->associated->bssid; @@ -3861,11 +3883,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, le64_to_cpu(mgmt->u.beacon.timestamp); sdata->vif.bss_conf.sync_device_ts = rx_status->device_timestamp; - if (elems.tim) - sdata->vif.bss_conf.sync_dtim_count = - elems.tim->dtim_count; - else - sdata->vif.bss_conf.sync_dtim_count = 0; + sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; } if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) @@ -3891,10 +3909,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, */ if (!ifmgd->have_beacon) { /* a few bogus AP send dtim_period = 0 or no TIM IE */ - if (elems.tim) - bss_conf->dtim_period = elems.tim->dtim_period ?: 1; - else - bss_conf->dtim_period = 1; + bss_conf->dtim_period = elems.dtim_period ?: 1; changed |= BSS_CHANGED_BEACON_INFO; ifmgd->have_beacon = true; @@ -4761,6 +4776,40 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, return ret; } +static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies, + u8 *dtim_count, u8 *dtim_period) +{ + const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data, + ies->len); + const struct ieee80211_tim_ie *tim = NULL; + const struct ieee80211_bssid_index *idx; + bool valid = tim_ie && tim_ie[1] >= 2; + + if (valid) + tim = (void *)(tim_ie + 2); + + if (dtim_count) + *dtim_count = valid ? tim->dtim_count : 0; + + if (dtim_period) + *dtim_period = valid ? tim->dtim_period : 0; + + /* Check if value is overridden by non-transmitted profile */ + if (!idx_ie || idx_ie[1] < 3) + return valid; + + idx = (void *)(idx_ie + 2); + + if (dtim_count) + *dtim_count = idx->dtim_count; + + if (dtim_period) + *dtim_period = idx->dtim_period; + + return true; +} + static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *cbss, bool assoc, bool override) @@ -4852,17 +4901,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); ies = rcu_dereference(cbss->beacon_ies); if (ies) { - const u8 *tim_ie; - sdata->vif.bss_conf.sync_tsf = ies->tsf; sdata->vif.bss_conf.sync_device_ts = bss->device_ts_beacon; - tim_ie = cfg80211_find_ie(WLAN_EID_TIM, - ies->data, ies->len); - if (tim_ie && tim_ie[1] >= 2) - sdata->vif.bss_conf.sync_dtim_count = tim_ie[2]; - else - sdata->vif.bss_conf.sync_dtim_count = 0; + + ieee80211_get_dtim(ies, + &sdata->vif.bss_conf.sync_dtim_count, + NULL); } else if (!ieee80211_hw_check(&sdata->local->hw, TIMING_BEACON_ONLY)) { ies = rcu_dereference(cbss->proberesp_ies); @@ -5332,17 +5377,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->timeout_started = true; assoc_data->need_beacon = true; } else if (beacon_ies) { - const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, - beacon_ies->data, - beacon_ies->len); + const u8 *ie; u8 dtim_count = 0; - if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) { - const struct ieee80211_tim_ie *tim; - tim = (void *)(tim_ie + 2); - ifmgd->dtim_period = tim->dtim_period; - dtim_count = tim->dtim_count; - } + ieee80211_get_dtim(beacon_ies, &dtim_count, + &ifmgd->dtim_period); + ifmgd->have_beacon = true; assoc_data->timeout = jiffies; assoc_data->timeout_started = true; @@ -5353,6 +5393,17 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, bss->device_ts_beacon; sdata->vif.bss_conf.sync_dtim_count = dtim_count; } + + ie = cfg80211_find_ext_ie(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION, + beacon_ies->data, beacon_ies->len); + if (ie && ie[1] >= 3) + sdata->vif.bss_conf.profile_periodicity = ie[4]; + + ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, + beacon_ies->data, beacon_ies->len); + if (ie && ie[1] >= 11 && + (ie[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + sdata->vif.bss_conf.ema_ap = true; } else { assoc_data->timeout = jiffies; assoc_data->timeout_started = true; |