summaryrefslogtreecommitdiff
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-08-28 13:41:31 +0200
committerJohannes Berg <johannes.berg@intel.com>2013-09-26 13:27:14 +0200
commitcd7760e62c2ac8581f050b2d36501d1a60beaf83 (patch)
tree1f4e9fb22e3b952c68c2e055a5381f5f9c5a2f94 /net/mac80211/tx.c
parent871a4180b8b62dbed54cd203c33bdab7fce24e6f (diff)
mac80211: add support for CSA in IBSS mode
This function adds the channel switch announcement implementation for the IBSS code. It is triggered by userspace (mac80211/cfg) or by external channel switch announcement, which have to be adopted. Both CSAs in beacons and action frames are supported. As for AP mode, the channel switch is applied after some time. However in IBSS mode, the channel switch IEs are generated in the kernel. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 102ce8adf2d1..4fcbf634b548 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2357,15 +2357,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
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;
+ size_t beacon_data_len;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ beacon_data = beacon->tail;
+ beacon_data_len = beacon->tail_len;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
+ break;
+ default:
+ return;
+ }
+ if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+ return;
/* warn if the driver did not check for/react to csa completeness */
- if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
+ if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
return;
- ((u8 *)beacon->tail)[counter_offset_beacon]--;
+ beacon_data[counter_offset_beacon]--;
- if (sdata->vif.type == NL80211_IFTYPE_AP &&
- counter_offset_presp) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
rcu_read_lock();
resp = rcu_dereference(sdata->u.ap.probe_resp);
@@ -2400,6 +2416,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
goto out;
beacon_data = beacon->tail;
beacon_data_len = beacon->tail_len;
+ } else if (vif->type == NL80211_IFTYPE_ADHOC) {
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ beacon = rcu_dereference(ifibss->presp);
+ if (!beacon)
+ goto out;
+
+ beacon_data = beacon->head;
+ beacon_data_len = beacon->head_len;
} else {
WARN_ON(1);
goto out;
@@ -2484,6 +2509,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!presp)
goto out;
+ if (sdata->vif.csa_active)
+ ieee80211_update_csa(sdata, presp);
+
+
skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
if (!skb)
goto out;