summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Eckelmann <seckelmann@datto.com>2019-07-24 12:33:56 -0400
committerJohannes Berg <johannes.berg@intel.com>2019-07-26 10:14:12 -0400
commit60ad72da55ac74a67d0eae5fb57327d7b4967786 (patch)
tree34c98fd49b9ac309691239cd7a1fc681af46fd89
parenta0b4496a43681cbeec03a38e1b685c80c0d7405d (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.h2
-rw-r--r--net/mac80211/mesh.c62
-rw-r--r--net/mac80211/mesh.h4
-rw-r--r--net/mac80211/mesh_plink.c12
-rw-r--r--net/mac80211/util.c49
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);
2137u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, 2137u8 *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);
2139u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
2139u8 *ieee80211_ie_build_he_cap(u8 *pos, 2140u8 *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);
2143u8 *ieee80211_ie_build_he_oper(u8 *pos);
2142int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, 2144int 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
535int 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
563int 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
535static void ieee80211_mesh_path_timer(struct timer_list *t) 590static 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);
219int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, 219int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
220 struct sk_buff *skb); 220 struct sk_buff *skb);
221int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
222 struct sk_buff *skb, u8 ie_len);
223int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
224 struct sk_buff *skb);
221void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); 225void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
222int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); 226int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
223void ieee80211s_init(void); 227void 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
2716u8 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
2716u8 *ieee80211_ie_build_he_cap(u8 *pos, 2737u8 *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
2926u8 *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
2905bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper, 2954bool 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{