Commit 0d06d9ba authored by Andrei Otcheretianski's avatar Andrei Otcheretianski Committed by Johannes Berg

mac80211: Support multiple CSA counters

Support up to IEEE80211_MAX_CSA_COUNTERS_NUM csa counters.
This is defined to be 2 now, to support both CSA and eCSA
counters.
Signed-off-by: default avatarAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 9a774c78
...@@ -3191,14 +3191,24 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -3191,14 +3191,24 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (params->count <= 1) if (params->count <= 1)
break; break;
sdata->csa_counter_offset_beacon = if ((params->n_counter_offsets_beacon >
params->counter_offsets_beacon[0]; IEEE80211_MAX_CSA_COUNTERS_NUM) ||
(params->n_counter_offsets_presp >
IEEE80211_MAX_CSA_COUNTERS_NUM))
return -EINVAL;
if (params->n_counter_offsets_presp) /* make sure we don't have garbage in other counters */
sdata->csa_counter_offset_presp = memset(sdata->csa_counter_offset_beacon, 0,
params->counter_offsets_presp[0]; sizeof(sdata->csa_counter_offset_beacon));
else memset(sdata->csa_counter_offset_presp, 0,
sdata->csa_counter_offset_presp = 0; sizeof(sdata->csa_counter_offset_presp));
memcpy(sdata->csa_counter_offset_beacon,
params->counter_offsets_beacon,
params->n_counter_offsets_beacon * sizeof(u16));
memcpy(sdata->csa_counter_offset_presp,
params->counter_offsets_presp,
params->n_counter_offsets_presp * sizeof(u16));
err = ieee80211_assign_beacon(sdata, &params->beacon_csa); err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
if (err < 0) { if (err < 0) {
......
...@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, ...@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
*pos++ = csa_settings->block_tx ? 1 : 0; *pos++ = csa_settings->block_tx ? 1 : 0;
*pos++ = ieee80211_frequency_to_channel( *pos++ = ieee80211_frequency_to_channel(
csa_settings->chandef.chan->center_freq); csa_settings->chandef.chan->center_freq);
sdata->csa_counter_offset_beacon = (pos - presp->head); sdata->csa_counter_offset_beacon[0] = (pos - presp->head);
*pos++ = csa_settings->count; *pos++ = csa_settings->count;
} }
......
...@@ -70,6 +70,8 @@ struct ieee80211_local; ...@@ -70,6 +70,8 @@ struct ieee80211_local;
#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
#define IEEE80211_MAX_CSA_COUNTERS_NUM 2
struct ieee80211_fragment_entry { struct ieee80211_fragment_entry {
unsigned long first_frag_time; unsigned long first_frag_time;
unsigned int seq; unsigned int seq;
...@@ -753,8 +755,8 @@ struct ieee80211_sub_if_data { ...@@ -753,8 +755,8 @@ struct ieee80211_sub_if_data {
struct mac80211_qos_map __rcu *qos_map; struct mac80211_qos_map __rcu *qos_map;
struct work_struct csa_finalize_work; struct work_struct csa_finalize_work;
int csa_counter_offset_beacon; u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM];
int csa_counter_offset_presp; u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM];
bool csa_radar_required; bool csa_radar_required;
bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
struct cfg80211_chan_def csa_chandef; struct cfg80211_chan_def csa_chandef;
......
...@@ -954,6 +954,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -954,6 +954,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
result = wiphy_register(local->hw.wiphy); result = wiphy_register(local->hw.wiphy);
if (result < 0) if (result < 0)
goto fail_wiphy_register; goto fail_wiphy_register;
......
...@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) ...@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
*pos++ = 0x0; *pos++ = 0x0;
*pos++ = ieee80211_frequency_to_channel( *pos++ = ieee80211_frequency_to_channel(
csa->settings.chandef.chan->center_freq); csa->settings.chandef.chan->center_freq);
sdata->csa_counter_offset_beacon = hdr_len + 6; sdata->csa_counter_offset_beacon[0] = hdr_len + 6;
*pos++ = csa->settings.count; *pos++ = csa->settings.count;
*pos++ = WLAN_EID_CHAN_SWITCH_PARAM; *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
*pos++ = 6; *pos++ = 6;
......
...@@ -2417,10 +2417,9 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, ...@@ -2417,10 +2417,9 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
struct beacon_data *beacon) struct beacon_data *beacon)
{ {
struct probe_resp *resp; struct probe_resp *resp;
int counter_offset_beacon = sdata->csa_counter_offset_beacon;
int counter_offset_presp = sdata->csa_counter_offset_presp;
u8 *beacon_data; u8 *beacon_data;
size_t beacon_data_len; size_t beacon_data_len;
int i;
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -2438,32 +2437,47 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, ...@@ -2438,32 +2437,47 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
default: default:
return; return;
} }
for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
u16 counter_offset_beacon =
sdata->csa_counter_offset_beacon[i];
u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
if (counter_offset_beacon) {
if (WARN_ON(counter_offset_beacon >= beacon_data_len)) if (WARN_ON(counter_offset_beacon >= beacon_data_len))
return; return;
/* Warn if the driver did not check for/react to csa /* Warn if the driver did not check for/react to csa
* completeness. A beacon with CSA counter set to 0 should * completeness. A beacon with CSA counter set to 0
* never occur, because a counter of 1 means switch just * should never occur, because a counter of 1 means
* before the next beacon. * switch just before the next beacon.
*/ */
if (WARN_ON(beacon_data[counter_offset_beacon] == 1)) if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
return; return;
sdata->csa_current_counter--; beacon_data[counter_offset_beacon] =
beacon_data[counter_offset_beacon] = sdata->csa_current_counter; sdata->csa_current_counter - 1;
}
if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) { if (sdata->vif.type == NL80211_IFTYPE_AP &&
counter_offset_presp) {
rcu_read_lock(); rcu_read_lock();
resp = rcu_dereference(sdata->u.ap.probe_resp); resp = rcu_dereference(sdata->u.ap.probe_resp);
/* if nl80211 accepted the offset, this should not happen. */ /* If nl80211 accepted the offset, this should
* not happen.
*/
if (WARN_ON(!resp)) { if (WARN_ON(!resp)) {
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
resp->data[counter_offset_presp] = sdata->csa_current_counter; resp->data[counter_offset_presp] =
sdata->csa_current_counter - 1;
rcu_read_unlock(); rcu_read_unlock();
} }
}
sdata->csa_current_counter--;
} }
bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
...@@ -2472,7 +2486,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) ...@@ -2472,7 +2486,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
struct beacon_data *beacon = NULL; struct beacon_data *beacon = NULL;
u8 *beacon_data; u8 *beacon_data;
size_t beacon_data_len; size_t beacon_data_len;
int counter_beacon = sdata->csa_counter_offset_beacon; int counter_beacon = sdata->csa_counter_offset_beacon[0];
int ret = false; int ret = false;
if (!ieee80211_sdata_running(sdata)) if (!ieee80211_sdata_running(sdata))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment