aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-07-11 10:09:06 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-08-01 12:30:33 -0400
commit73da7d5bab79ad7e16ff44d67c3fe8b9c0b33e5b (patch)
treecb4eee7b96aae1d31a4841167a3f36c638bd0a11 /net/mac80211/tx.c
parent16ef1fe272332b2f7fd99236017b891db48d9cd6 (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.c78
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
2341void 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}
2348EXPORT_SYMBOL(ieee80211_csa_finish);
2349
2350static 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
2378bool 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}
2414EXPORT_SYMBOL(ieee80211_csa_is_complete);
2415
2341struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, 2416struct 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