diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-08-28 07:41:32 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-09-26 07:27:15 -0400 |
commit | 9449410f3b30a27824aa02adec485e18b740b756 (patch) | |
tree | e00b1a10768495f2ecdaafe2ae3616e5b0b65d93 /net/mac80211 | |
parent | cd7760e62c2ac8581f050b2d36501d1a60beaf83 (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.c | 60 |
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 | ||
431 | static 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 | |||
431 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | 485 | int 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; |