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: Andrei Otcheretianski <andrei.otcheretianski@intel.com> Signed-off-by: Luciano Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
9a774c78e2
commit
0d06d9ba93
6 changed files with 65 additions and 37 deletions
|
@ -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, ¶ms->beacon_csa);
|
err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
#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 {
|
||||||
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)
|
||||||
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)
|
||||||
*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,
|
||||||
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,
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (WARN_ON(counter_offset_beacon >= beacon_data_len))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Warn if the driver did not check for/react to csa
|
for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
|
||||||
* completeness. A beacon with CSA counter set to 0 should
|
u16 counter_offset_beacon =
|
||||||
* never occur, because a counter of 1 means switch just
|
sdata->csa_counter_offset_beacon[i];
|
||||||
* before the next beacon.
|
u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
|
||||||
*/
|
|
||||||
if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
|
if (counter_offset_beacon) {
|
||||||
return;
|
if (WARN_ON(counter_offset_beacon >= beacon_data_len))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Warn if the driver did not check for/react to csa
|
||||||
|
* completeness. A beacon with CSA counter set to 0
|
||||||
|
* should never occur, because a counter of 1 means
|
||||||
|
* switch just before the next beacon.
|
||||||
|
*/
|
||||||
|
if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
beacon_data[counter_offset_beacon] =
|
||||||
|
sdata->csa_current_counter - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdata->vif.type == NL80211_IFTYPE_AP &&
|
||||||
|
counter_offset_presp) {
|
||||||
|
rcu_read_lock();
|
||||||
|
resp = rcu_dereference(sdata->u.ap.probe_resp);
|
||||||
|
|
||||||
|
/* If nl80211 accepted the offset, this should
|
||||||
|
* not happen.
|
||||||
|
*/
|
||||||
|
if (WARN_ON(!resp)) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resp->data[counter_offset_presp] =
|
||||||
|
sdata->csa_current_counter - 1;
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sdata->csa_current_counter--;
|
sdata->csa_current_counter--;
|
||||||
beacon_data[counter_offset_beacon] = sdata->csa_current_counter;
|
|
||||||
|
|
||||||
if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
|
|
||||||
rcu_read_lock();
|
|
||||||
resp = rcu_dereference(sdata->u.ap.probe_resp);
|
|
||||||
|
|
||||||
/* if nl80211 accepted the offset, this should not happen. */
|
|
||||||
if (WARN_ON(!resp)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resp->data[counter_offset_presp] = sdata->csa_current_counter;
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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))
|
||||||
|
|
Loading…
Add table
Reference in a new issue