diff options
author | Simon Wunderlich <sw@simonwunderlich.de> | 2017-05-23 11:00:42 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2017-05-24 02:58:54 -0400 |
commit | 75d627d53e015027d0f85c928673d368807243cc (patch) | |
tree | bb3c83d7ec03ed07d2fd68a3456bf43fe704d1b7 | |
parent | 3b23782f7d004f3d7fa655623ebca3137b442656 (diff) |
mac80211: mesh: support sending wide bandwidth CSA
To support HT and VHT CSA, beacons and action frames must include the
corresponding IEs.
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
[make ieee80211_ie_build_wide_bw_cs() return void]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 45 | ||||
-rw-r--r-- | net/mac80211/util.c | 37 |
3 files changed, 82 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c960e4999380..a34abd8784d3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -2066,6 +2066,8 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
2066 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 2066 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
2067 | const struct cfg80211_chan_def *chandef, | 2067 | const struct cfg80211_chan_def *chandef, |
2068 | u16 prot_mode, bool rifs_mode); | 2068 | u16 prot_mode, bool rifs_mode); |
2069 | void ieee80211_ie_build_wide_bw_cs(u8 *pos, | ||
2070 | const struct cfg80211_chan_def *chandef); | ||
2069 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 2071 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
2070 | u32 cap); | 2072 | u32 cap); |
2071 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 2073 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2f189c59ae80..d6cc0080866d 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -690,6 +690,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
690 | 2 + sizeof(struct ieee80211_channel_sw_ie) + | 690 | 2 + sizeof(struct ieee80211_channel_sw_ie) + |
691 | /* Mesh Channel Switch Parameters */ | 691 | /* Mesh Channel Switch Parameters */ |
692 | 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) + | 692 | 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) + |
693 | /* Channel Switch Wrapper + Wide Bandwidth CSA IE */ | ||
694 | 2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie) + | ||
695 | 2 + sizeof(struct ieee80211_sec_chan_offs_ie) + | ||
693 | 2 + 8 + /* supported rates */ | 696 | 2 + 8 + /* supported rates */ |
694 | 2 + 3; /* DS params */ | 697 | 2 + 3; /* DS params */ |
695 | tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 698 | tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + |
@@ -736,8 +739,13 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
736 | rcu_read_lock(); | 739 | rcu_read_lock(); |
737 | csa = rcu_dereference(ifmsh->csa); | 740 | csa = rcu_dereference(ifmsh->csa); |
738 | if (csa) { | 741 | if (csa) { |
739 | pos = skb_put(skb, 13); | 742 | enum nl80211_channel_type ct; |
740 | memset(pos, 0, 13); | 743 | struct cfg80211_chan_def *chandef; |
744 | int ie_len = 2 + sizeof(struct ieee80211_channel_sw_ie) + | ||
745 | 2 + sizeof(struct ieee80211_mesh_chansw_params_ie); | ||
746 | |||
747 | pos = skb_put(skb, ie_len); | ||
748 | memset(pos, 0, ie_len); | ||
741 | *pos++ = WLAN_EID_CHANNEL_SWITCH; | 749 | *pos++ = WLAN_EID_CHANNEL_SWITCH; |
742 | *pos++ = 3; | 750 | *pos++ = 3; |
743 | *pos++ = 0x0; | 751 | *pos++ = 0x0; |
@@ -760,6 +768,39 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
760 | pos += 2; | 768 | pos += 2; |
761 | put_unaligned_le16(ifmsh->pre_value, pos); | 769 | put_unaligned_le16(ifmsh->pre_value, pos); |
762 | pos += 2; | 770 | pos += 2; |
771 | |||
772 | switch (csa->settings.chandef.width) { | ||
773 | case NL80211_CHAN_WIDTH_40: | ||
774 | ie_len = 2 + sizeof(struct ieee80211_sec_chan_offs_ie); | ||
775 | pos = skb_put(skb, ie_len); | ||
776 | memset(pos, 0, ie_len); | ||
777 | |||
778 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ | ||
779 | *pos++ = 1; /* len */ | ||
780 | ct = cfg80211_get_chandef_type(&csa->settings.chandef); | ||
781 | if (ct == NL80211_CHAN_HT40PLUS) | ||
782 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
783 | else | ||
784 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
785 | break; | ||
786 | case NL80211_CHAN_WIDTH_80: | ||
787 | case NL80211_CHAN_WIDTH_80P80: | ||
788 | case NL80211_CHAN_WIDTH_160: | ||
789 | /* Channel Switch Wrapper + Wide Bandwidth CSA IE */ | ||
790 | ie_len = 2 + 2 + | ||
791 | sizeof(struct ieee80211_wide_bw_chansw_ie); | ||
792 | pos = skb_put(skb, ie_len); | ||
793 | memset(pos, 0, ie_len); | ||
794 | |||
795 | *pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; /* EID */ | ||
796 | *pos++ = 5; /* len */ | ||
797 | /* put sub IE */ | ||
798 | chandef = &csa->settings.chandef; | ||
799 | ieee80211_ie_build_wide_bw_cs(pos, chandef); | ||
800 | break; | ||
801 | default: | ||
802 | break; | ||
803 | } | ||
763 | } | 804 | } |
764 | rcu_read_unlock(); | 805 | rcu_read_unlock(); |
765 | 806 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ac9ac6c35594..de0f1cdb64d4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2414,6 +2414,35 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
2414 | return pos + sizeof(struct ieee80211_ht_operation); | 2414 | return pos + sizeof(struct ieee80211_ht_operation); |
2415 | } | 2415 | } |
2416 | 2416 | ||
2417 | void ieee80211_ie_build_wide_bw_cs(u8 *pos, | ||
2418 | const struct cfg80211_chan_def *chandef) | ||
2419 | { | ||
2420 | *pos++ = WLAN_EID_WIDE_BW_CHANNEL_SWITCH; /* EID */ | ||
2421 | *pos++ = 3; /* IE length */ | ||
2422 | /* New channel width */ | ||
2423 | switch (chandef->width) { | ||
2424 | case NL80211_CHAN_WIDTH_80: | ||
2425 | *pos++ = IEEE80211_VHT_CHANWIDTH_80MHZ; | ||
2426 | break; | ||
2427 | case NL80211_CHAN_WIDTH_160: | ||
2428 | *pos++ = IEEE80211_VHT_CHANWIDTH_160MHZ; | ||
2429 | break; | ||
2430 | case NL80211_CHAN_WIDTH_80P80: | ||
2431 | *pos++ = IEEE80211_VHT_CHANWIDTH_80P80MHZ; | ||
2432 | break; | ||
2433 | default: | ||
2434 | *pos++ = IEEE80211_VHT_CHANWIDTH_USE_HT; | ||
2435 | } | ||
2436 | |||
2437 | /* new center frequency segment 0 */ | ||
2438 | *pos++ = ieee80211_frequency_to_channel(chandef->center_freq1); | ||
2439 | /* new center frequency segment 1 */ | ||
2440 | if (chandef->center_freq2) | ||
2441 | *pos++ = ieee80211_frequency_to_channel(chandef->center_freq2); | ||
2442 | else | ||
2443 | *pos++ = 0; | ||
2444 | } | ||
2445 | |||
2417 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 2446 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
2418 | const struct cfg80211_chan_def *chandef) | 2447 | const struct cfg80211_chan_def *chandef) |
2419 | { | 2448 | { |
@@ -2964,6 +2993,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
2964 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + | 2993 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + |
2965 | 5 + /* channel switch announcement element */ | 2994 | 5 + /* channel switch announcement element */ |
2966 | 3 + /* secondary channel offset element */ | 2995 | 3 + /* secondary channel offset element */ |
2996 | 5 + /* wide bandwidth channel switch announcement */ | ||
2967 | 8); /* mesh channel switch parameters element */ | 2997 | 8); /* mesh channel switch parameters element */ |
2968 | if (!skb) | 2998 | if (!skb) |
2969 | return -ENOMEM; | 2999 | return -ENOMEM; |
@@ -3022,6 +3052,13 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
3022 | pos += 2; | 3052 | pos += 2; |
3023 | } | 3053 | } |
3024 | 3054 | ||
3055 | if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_80 || | ||
3056 | csa_settings->chandef.width == NL80211_CHAN_WIDTH_80P80 || | ||
3057 | csa_settings->chandef.width == NL80211_CHAN_WIDTH_160) { | ||
3058 | skb_put(skb, 5); | ||
3059 | ieee80211_ie_build_wide_bw_cs(pos, &csa_settings->chandef); | ||
3060 | } | ||
3061 | |||
3025 | ieee80211_tx_skb(sdata, skb); | 3062 | ieee80211_tx_skb(sdata, skb); |
3026 | return 0; | 3063 | return 0; |
3027 | } | 3064 | } |