aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <sw@simonwunderlich.de>2017-05-23 11:00:42 -0400
committerJohannes Berg <johannes.berg@intel.com>2017-05-24 02:58:54 -0400
commit75d627d53e015027d0f85c928673d368807243cc (patch)
treebb3c83d7ec03ed07d2fd68a3456bf43fe704d1b7
parent3b23782f7d004f3d7fa655623ebca3137b442656 (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.h2
-rw-r--r--net/mac80211/mesh.c45
-rw-r--r--net/mac80211/util.c37
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,
2066u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 2066u8 *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);
2069void ieee80211_ie_build_wide_bw_cs(u8 *pos,
2070 const struct cfg80211_chan_def *chandef);
2069u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 2071u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
2070 u32 cap); 2072 u32 cap);
2071u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 2073u8 *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
2417void 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
2417u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 2446u8 *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}