diff options
author | Sven Eckelmann <seckelmann@datto.com> | 2019-07-24 12:33:56 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-07-26 10:14:12 -0400 |
commit | 60ad72da55ac74a67d0eae5fb57327d7b4967786 (patch) | |
tree | 34c98fd49b9ac309691239cd7a1fc681af46fd89 | |
parent | a0b4496a43681cbeec03a38e1b685c80c0d7405d (diff) |
mac80211: implement HE support for mesh
Implement the basics required for supporting high efficiency with mesh:
include HE information elements in beacons, probe responses, and peering
action frames, and check for compatible HE configurations when peering.
Signed-off-by: Sven Eckelmann <seckelmann@datto.com>
Forwarded: https://patchwork.kernel.org/patch/11029299/
Link: https://lore.kernel.org/r/20190724163359.3507-2-sven@narfation.org
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 | 62 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 4 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 12 | ||||
-rw-r--r-- | net/mac80211/util.c | 49 |
5 files changed, 128 insertions, 1 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 472c5a40317d..a5818ff0e2a4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -2136,9 +2136,11 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2136 | u32 cap); | 2136 | u32 cap); |
2137 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 2137 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
2138 | const struct cfg80211_chan_def *chandef); | 2138 | const struct cfg80211_chan_def *chandef); |
2139 | u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); | ||
2139 | u8 *ieee80211_ie_build_he_cap(u8 *pos, | 2140 | u8 *ieee80211_ie_build_he_cap(u8 *pos, |
2140 | const struct ieee80211_sta_he_cap *he_cap, | 2141 | const struct ieee80211_sta_he_cap *he_cap, |
2141 | u8 *end); | 2142 | u8 *end); |
2143 | u8 *ieee80211_ie_build_he_oper(u8 *pos); | ||
2142 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | 2144 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, |
2143 | const struct ieee80211_supported_band *sband, | 2145 | const struct ieee80211_supported_band *sband, |
2144 | const u8 *srates, int srates_len, u32 *rates); | 2146 | const u8 *srates, int srates_len, u32 *rates); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2e7fa743c892..d09b3c789314 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -532,6 +532,61 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, | |||
532 | return 0; | 532 | return 0; |
533 | } | 533 | } |
534 | 534 | ||
535 | int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, | ||
536 | struct sk_buff *skb, u8 ie_len) | ||
537 | { | ||
538 | const struct ieee80211_sta_he_cap *he_cap; | ||
539 | struct ieee80211_supported_band *sband; | ||
540 | u8 *pos; | ||
541 | |||
542 | sband = ieee80211_get_sband(sdata); | ||
543 | if (!sband) | ||
544 | return -EINVAL; | ||
545 | |||
546 | he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); | ||
547 | |||
548 | if (!he_cap || | ||
549 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | ||
550 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || | ||
551 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) | ||
552 | return 0; | ||
553 | |||
554 | if (skb_tailroom(skb) < ie_len) | ||
555 | return -ENOMEM; | ||
556 | |||
557 | pos = skb_put(skb, ie_len); | ||
558 | ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata, | ||
564 | struct sk_buff *skb) | ||
565 | { | ||
566 | const struct ieee80211_sta_he_cap *he_cap; | ||
567 | struct ieee80211_supported_band *sband; | ||
568 | u8 *pos; | ||
569 | |||
570 | sband = ieee80211_get_sband(sdata); | ||
571 | if (!sband) | ||
572 | return -EINVAL; | ||
573 | |||
574 | he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); | ||
575 | if (!he_cap || | ||
576 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | ||
577 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || | ||
578 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) | ||
579 | return 0; | ||
580 | |||
581 | if (skb_tailroom(skb) < 2 + 1 + sizeof(struct ieee80211_he_operation)) | ||
582 | return -ENOMEM; | ||
583 | |||
584 | pos = skb_put(skb, 2 + 1 + sizeof(struct ieee80211_he_operation)); | ||
585 | ieee80211_ie_build_he_oper(pos); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
535 | static void ieee80211_mesh_path_timer(struct timer_list *t) | 590 | static void ieee80211_mesh_path_timer(struct timer_list *t) |
536 | { | 591 | { |
537 | struct ieee80211_sub_if_data *sdata = | 592 | struct ieee80211_sub_if_data *sdata = |
@@ -677,6 +732,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
677 | struct ieee80211_chanctx_conf *chanctx_conf; | 732 | struct ieee80211_chanctx_conf *chanctx_conf; |
678 | struct mesh_csa_settings *csa; | 733 | struct mesh_csa_settings *csa; |
679 | enum nl80211_band band; | 734 | enum nl80211_band band; |
735 | u8 ie_len_he_cap; | ||
680 | u8 *pos; | 736 | u8 *pos; |
681 | struct ieee80211_sub_if_data *sdata; | 737 | struct ieee80211_sub_if_data *sdata; |
682 | int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon); | 738 | int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon); |
@@ -687,6 +743,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
687 | band = chanctx_conf->def.chan->band; | 743 | band = chanctx_conf->def.chan->band; |
688 | rcu_read_unlock(); | 744 | rcu_read_unlock(); |
689 | 745 | ||
746 | ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, | ||
747 | NL80211_IFTYPE_MESH_POINT); | ||
690 | head_len = hdr_len + | 748 | head_len = hdr_len + |
691 | 2 + /* NULL SSID */ | 749 | 2 + /* NULL SSID */ |
692 | /* Channel Switch Announcement */ | 750 | /* Channel Switch Announcement */ |
@@ -706,6 +764,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
706 | 2 + sizeof(__le16) + /* awake window */ | 764 | 2 + sizeof(__le16) + /* awake window */ |
707 | 2 + sizeof(struct ieee80211_vht_cap) + | 765 | 2 + sizeof(struct ieee80211_vht_cap) + |
708 | 2 + sizeof(struct ieee80211_vht_operation) + | 766 | 2 + sizeof(struct ieee80211_vht_operation) + |
767 | ie_len_he_cap + | ||
768 | 2 + 1 + sizeof(struct ieee80211_he_operation) + | ||
709 | ifmsh->ie_len; | 769 | ifmsh->ie_len; |
710 | 770 | ||
711 | bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); | 771 | bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); |
@@ -823,6 +883,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
823 | mesh_add_awake_window_ie(sdata, skb) || | 883 | mesh_add_awake_window_ie(sdata, skb) || |
824 | mesh_add_vht_cap_ie(sdata, skb) || | 884 | mesh_add_vht_cap_ie(sdata, skb) || |
825 | mesh_add_vht_oper_ie(sdata, skb) || | 885 | mesh_add_vht_oper_ie(sdata, skb) || |
886 | mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) || | ||
887 | mesh_add_he_oper_ie(sdata, skb) || | ||
826 | mesh_add_vendor_ies(sdata, skb)) | 888 | mesh_add_vendor_ies(sdata, skb)) |
827 | goto out_free; | 889 | goto out_free; |
828 | 890 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 94d57cce70da..953f720754e8 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -218,6 +218,10 @@ int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, | |||
218 | struct sk_buff *skb); | 218 | struct sk_buff *skb); |
219 | int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, | 219 | int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, |
220 | struct sk_buff *skb); | 220 | struct sk_buff *skb); |
221 | int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, | ||
222 | struct sk_buff *skb, u8 ie_len); | ||
223 | int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata, | ||
224 | struct sk_buff *skb); | ||
221 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 225 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
222 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); | 226 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); |
223 | void ieee80211s_init(void); | 227 | void ieee80211s_init(void); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index dd3aefd052a9..737c5f4dbf52 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -218,9 +218,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
218 | bool include_plid = false; | 218 | bool include_plid = false; |
219 | u16 peering_proto = 0; | 219 | u16 peering_proto = 0; |
220 | u8 *pos, ie_len = 4; | 220 | u8 *pos, ie_len = 4; |
221 | u8 ie_len_he_cap; | ||
221 | int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot); | 222 | int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot); |
222 | int err = -ENOMEM; | 223 | int err = -ENOMEM; |
223 | 224 | ||
225 | ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, | ||
226 | NL80211_IFTYPE_MESH_POINT); | ||
224 | skb = dev_alloc_skb(local->tx_headroom + | 227 | skb = dev_alloc_skb(local->tx_headroom + |
225 | hdr_len + | 228 | hdr_len + |
226 | 2 + /* capability info */ | 229 | 2 + /* capability info */ |
@@ -233,6 +236,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
233 | 2 + sizeof(struct ieee80211_ht_operation) + | 236 | 2 + sizeof(struct ieee80211_ht_operation) + |
234 | 2 + sizeof(struct ieee80211_vht_cap) + | 237 | 2 + sizeof(struct ieee80211_vht_cap) + |
235 | 2 + sizeof(struct ieee80211_vht_operation) + | 238 | 2 + sizeof(struct ieee80211_vht_operation) + |
239 | ie_len_he_cap + | ||
240 | 2 + 1 + sizeof(struct ieee80211_he_operation) + | ||
236 | 2 + 8 + /* peering IE */ | 241 | 2 + 8 + /* peering IE */ |
237 | sdata->u.mesh.ie_len); | 242 | sdata->u.mesh.ie_len); |
238 | if (!skb) | 243 | if (!skb) |
@@ -321,7 +326,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
321 | if (mesh_add_ht_cap_ie(sdata, skb) || | 326 | if (mesh_add_ht_cap_ie(sdata, skb) || |
322 | mesh_add_ht_oper_ie(sdata, skb) || | 327 | mesh_add_ht_oper_ie(sdata, skb) || |
323 | mesh_add_vht_cap_ie(sdata, skb) || | 328 | mesh_add_vht_cap_ie(sdata, skb) || |
324 | mesh_add_vht_oper_ie(sdata, skb)) | 329 | mesh_add_vht_oper_ie(sdata, skb) || |
330 | mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) || | ||
331 | mesh_add_he_oper_ie(sdata, skb)) | ||
325 | goto free; | 332 | goto free; |
326 | } | 333 | } |
327 | 334 | ||
@@ -433,6 +440,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
433 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 440 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
434 | elems->vht_cap_elem, sta); | 441 | elems->vht_cap_elem, sta); |
435 | 442 | ||
443 | ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, | ||
444 | elems->he_cap_len, sta); | ||
445 | |||
436 | if (bw != sta->sta.bandwidth) | 446 | if (bw != sta->sta.bandwidth) |
437 | changed |= IEEE80211_RC_BW_CHANGED; | 447 | changed |= IEEE80211_RC_BW_CHANGED; |
438 | 448 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3e2aeb1a75b4..caa317faee3c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2713,6 +2713,27 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2713 | return pos; | 2713 | return pos; |
2714 | } | 2714 | } |
2715 | 2715 | ||
2716 | u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) | ||
2717 | { | ||
2718 | const struct ieee80211_sta_he_cap *he_cap; | ||
2719 | struct ieee80211_supported_band *sband; | ||
2720 | u8 n; | ||
2721 | |||
2722 | sband = ieee80211_get_sband(sdata); | ||
2723 | if (!sband) | ||
2724 | return 0; | ||
2725 | |||
2726 | he_cap = ieee80211_get_he_iftype_cap(sband, iftype); | ||
2727 | if (!he_cap) | ||
2728 | return 0; | ||
2729 | |||
2730 | n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem); | ||
2731 | return 2 + 1 + | ||
2732 | sizeof(he_cap->he_cap_elem) + n + | ||
2733 | ieee80211_he_ppe_size(he_cap->ppe_thres[0], | ||
2734 | he_cap->he_cap_elem.phy_cap_info); | ||
2735 | } | ||
2736 | |||
2716 | u8 *ieee80211_ie_build_he_cap(u8 *pos, | 2737 | u8 *ieee80211_ie_build_he_cap(u8 *pos, |
2717 | const struct ieee80211_sta_he_cap *he_cap, | 2738 | const struct ieee80211_sta_he_cap *he_cap, |
2718 | u8 *end) | 2739 | u8 *end) |
@@ -2902,6 +2923,34 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2902 | return pos + sizeof(struct ieee80211_vht_operation); | 2923 | return pos + sizeof(struct ieee80211_vht_operation); |
2903 | } | 2924 | } |
2904 | 2925 | ||
2926 | u8 *ieee80211_ie_build_he_oper(u8 *pos) | ||
2927 | { | ||
2928 | struct ieee80211_he_operation *he_oper; | ||
2929 | u32 he_oper_params; | ||
2930 | |||
2931 | *pos++ = WLAN_EID_EXTENSION; | ||
2932 | *pos++ = 1 + sizeof(struct ieee80211_he_operation); | ||
2933 | *pos++ = WLAN_EID_EXT_HE_OPERATION; | ||
2934 | |||
2935 | he_oper_params = 0; | ||
2936 | he_oper_params |= u32_encode_bits(1023, /* disabled */ | ||
2937 | IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); | ||
2938 | he_oper_params |= u32_encode_bits(1, | ||
2939 | IEEE80211_HE_OPERATION_ER_SU_DISABLE); | ||
2940 | he_oper_params |= u32_encode_bits(1, | ||
2941 | IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED); | ||
2942 | |||
2943 | he_oper = (struct ieee80211_he_operation *)pos; | ||
2944 | he_oper->he_oper_params = cpu_to_le32(he_oper_params); | ||
2945 | |||
2946 | /* don't require special HE peer rates */ | ||
2947 | he_oper->he_mcs_nss_set = cpu_to_le16(0xffff); | ||
2948 | |||
2949 | /* TODO add VHT operational and 6GHz operational subelement? */ | ||
2950 | |||
2951 | return pos + sizeof(struct ieee80211_vht_operation); | ||
2952 | } | ||
2953 | |||
2905 | bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, | 2954 | bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, |
2906 | struct cfg80211_chan_def *chandef) | 2955 | struct cfg80211_chan_def *chandef) |
2907 | { | 2956 | { |