mac80211: add channel switch command and beacon callbacks
The count field in CSA must be decremented with each beacon transmitted. This patch implements the functionality for drivers using ieee80211_beacon_get(). Other drivers must call back manually after reaching count == 0. This patch also contains the handling and finish worker for the channel switch command, and mac80211/chanctx code to allow to change a channel definition of an active channel context. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> [small cleanups, catch identical chandef] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
16ef1fe272
commit
73da7d5bab
@@ -2338,6 +2338,81 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_csa_finish(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw,
|
||||
&sdata->csa_finalize_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_finish);
|
||||
|
||||
static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *beacon)
|
||||
{
|
||||
struct probe_resp *resp;
|
||||
int counter_offset_beacon = sdata->csa_counter_offset_beacon;
|
||||
int counter_offset_presp = sdata->csa_counter_offset_presp;
|
||||
|
||||
/* warn if the driver did not check for/react to csa completeness */
|
||||
if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
|
||||
return;
|
||||
|
||||
((u8 *)beacon->tail)[counter_offset_beacon]--;
|
||||
|
||||
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]--;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct beacon_data *beacon = NULL;
|
||||
u8 *beacon_data;
|
||||
size_t beacon_data_len;
|
||||
int counter_beacon = sdata->csa_counter_offset_beacon;
|
||||
int ret = false;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
struct ieee80211_if_ap *ap = &sdata->u.ap;
|
||||
|
||||
beacon = rcu_dereference(ap->beacon);
|
||||
if (WARN_ON(!beacon || !beacon->tail))
|
||||
goto out;
|
||||
beacon_data = beacon->tail;
|
||||
beacon_data_len = beacon->tail_len;
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WARN_ON(counter_beacon > beacon_data_len))
|
||||
goto out;
|
||||
|
||||
if (beacon_data[counter_beacon] == 0)
|
||||
ret = true;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_is_complete);
|
||||
|
||||
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u16 *tim_offset, u16 *tim_length)
|
||||
@@ -2368,6 +2443,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||
struct beacon_data *beacon = rcu_dereference(ap->beacon);
|
||||
|
||||
if (beacon) {
|
||||
if (sdata->vif.csa_active)
|
||||
ieee80211_update_csa(sdata, beacon);
|
||||
|
||||
/*
|
||||
* headroom, head length,
|
||||
* tail length and maximum TIM length
|
||||
|
||||
Reference in New Issue
Block a user