aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-08-28 07:41:32 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-09-26 07:27:15 -0400
commit9449410f3b30a27824aa02adec485e18b740b756 (patch)
treee00b1a10768495f2ecdaafe2ae3616e5b0b65d93 /net/mac80211
parentcd7760e62c2ac8581f050b2d36501d1a60beaf83 (diff)
mac80211: send a CSA action frame when changing channel
IBSS members may not immediately be able to send out their beacon when performing CSA, therefore also send a CSA action frame. 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')
-rw-r--r--net/mac80211/ibss.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c0042136f1d8..5ea9b3ae303e 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -428,6 +428,60 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
428 tsf, false); 428 tsf, false);
429} 429}
430 430
431static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
432 struct cfg80211_csa_settings *csa_settings)
433{
434 struct sk_buff *skb;
435 struct ieee80211_mgmt *mgmt;
436 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
437 struct ieee80211_local *local = sdata->local;
438 int freq;
439 int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
440 sizeof(mgmt->u.action.u.chan_switch);
441 u8 *pos;
442
443 skb = dev_alloc_skb(local->tx_headroom + hdr_len +
444 5 + /* channel switch announcement element */
445 3); /* secondary channel offset element */
446 if (!skb)
447 return -1;
448
449 skb_reserve(skb, local->tx_headroom);
450 mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
451 memset(mgmt, 0, hdr_len);
452 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
453 IEEE80211_STYPE_ACTION);
454
455 eth_broadcast_addr(mgmt->da);
456 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
457 memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
458 mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
459 mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
460 pos = skb_put(skb, 5);
461 *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
462 *pos++ = 3; /* IE length */
463 *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
464 freq = csa_settings->chandef.chan->center_freq;
465 *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
466 *pos++ = csa_settings->count; /* count */
467
468 if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
469 enum nl80211_channel_type ch_type;
470
471 skb_put(skb, 3);
472 *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
473 *pos++ = 1; /* IE length */
474 ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
475 if (ch_type == NL80211_CHAN_HT40PLUS)
476 *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
477 else
478 *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
479 }
480
481 ieee80211_tx_skb(sdata, skb);
482 return 0;
483}
484
431int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, 485int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
432 struct cfg80211_csa_settings *csa_settings) 486 struct cfg80211_csa_settings *csa_settings)
433{ 487{
@@ -480,6 +534,12 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
480 if (old_presp) 534 if (old_presp)
481 kfree_rcu(old_presp, rcu_head); 535 kfree_rcu(old_presp, rcu_head);
482 536
537 /* it might not send the beacon for a while. send an action frame
538 * immediately to announce the channel switch.
539 */
540 if (csa_settings)
541 ieee80211_send_action_csa(sdata, csa_settings);
542
483 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 543 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
484 out: 544 out:
485 return ret; 545 return ret;