diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-07-11 10:09:06 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-08-01 12:30:33 -0400 |
commit | 73da7d5bab79ad7e16ff44d67c3fe8b9c0b33e5b (patch) | |
tree | cb4eee7b96aae1d31a4841167a3f36c638bd0a11 /net/mac80211/tx.c | |
parent | 16ef1fe272332b2f7fd99236017b891db48d9cd6 (diff) |
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>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f65873f0c89f..0e42322aa6b1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2338,6 +2338,81 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
2338 | return 0; | 2338 | return 0; |
2339 | } | 2339 | } |
2340 | 2340 | ||
2341 | void ieee80211_csa_finish(struct ieee80211_vif *vif) | ||
2342 | { | ||
2343 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2344 | |||
2345 | ieee80211_queue_work(&sdata->local->hw, | ||
2346 | &sdata->csa_finalize_work); | ||
2347 | } | ||
2348 | EXPORT_SYMBOL(ieee80211_csa_finish); | ||
2349 | |||
2350 | static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | ||
2351 | struct beacon_data *beacon) | ||
2352 | { | ||
2353 | struct probe_resp *resp; | ||
2354 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; | ||
2355 | int counter_offset_presp = sdata->csa_counter_offset_presp; | ||
2356 | |||
2357 | /* warn if the driver did not check for/react to csa completeness */ | ||
2358 | if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0)) | ||
2359 | return; | ||
2360 | |||
2361 | ((u8 *)beacon->tail)[counter_offset_beacon]--; | ||
2362 | |||
2363 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
2364 | counter_offset_presp) { | ||
2365 | rcu_read_lock(); | ||
2366 | resp = rcu_dereference(sdata->u.ap.probe_resp); | ||
2367 | |||
2368 | /* if nl80211 accepted the offset, this should not happen. */ | ||
2369 | if (WARN_ON(!resp)) { | ||
2370 | rcu_read_unlock(); | ||
2371 | return; | ||
2372 | } | ||
2373 | resp->data[counter_offset_presp]--; | ||
2374 | rcu_read_unlock(); | ||
2375 | } | ||
2376 | } | ||
2377 | |||
2378 | bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | ||
2379 | { | ||
2380 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2381 | struct beacon_data *beacon = NULL; | ||
2382 | u8 *beacon_data; | ||
2383 | size_t beacon_data_len; | ||
2384 | int counter_beacon = sdata->csa_counter_offset_beacon; | ||
2385 | int ret = false; | ||
2386 | |||
2387 | if (!ieee80211_sdata_running(sdata)) | ||
2388 | return false; | ||
2389 | |||
2390 | rcu_read_lock(); | ||
2391 | if (vif->type == NL80211_IFTYPE_AP) { | ||
2392 | struct ieee80211_if_ap *ap = &sdata->u.ap; | ||
2393 | |||
2394 | beacon = rcu_dereference(ap->beacon); | ||
2395 | if (WARN_ON(!beacon || !beacon->tail)) | ||
2396 | goto out; | ||
2397 | beacon_data = beacon->tail; | ||
2398 | beacon_data_len = beacon->tail_len; | ||
2399 | } else { | ||
2400 | WARN_ON(1); | ||
2401 | goto out; | ||
2402 | } | ||
2403 | |||
2404 | if (WARN_ON(counter_beacon > beacon_data_len)) | ||
2405 | goto out; | ||
2406 | |||
2407 | if (beacon_data[counter_beacon] == 0) | ||
2408 | ret = true; | ||
2409 | out: | ||
2410 | rcu_read_unlock(); | ||
2411 | |||
2412 | return ret; | ||
2413 | } | ||
2414 | EXPORT_SYMBOL(ieee80211_csa_is_complete); | ||
2415 | |||
2341 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | 2416 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, |
2342 | struct ieee80211_vif *vif, | 2417 | struct ieee80211_vif *vif, |
2343 | u16 *tim_offset, u16 *tim_length) | 2418 | u16 *tim_offset, u16 *tim_length) |
@@ -2368,6 +2443,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2368 | struct beacon_data *beacon = rcu_dereference(ap->beacon); | 2443 | struct beacon_data *beacon = rcu_dereference(ap->beacon); |
2369 | 2444 | ||
2370 | if (beacon) { | 2445 | if (beacon) { |
2446 | if (sdata->vif.csa_active) | ||
2447 | ieee80211_update_csa(sdata, beacon); | ||
2448 | |||
2371 | /* | 2449 | /* |
2372 | * headroom, head length, | 2450 | * headroom, head length, |
2373 | * tail length and maximum TIM length | 2451 | * tail length and maximum TIM length |