Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Add EHT capabilities to association/probe request

Add the EHT capabilities element to both probe request and
association request frames, if advertised by the driver.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Link: https://lore.kernel.org/r/20220214173004.2ec94388acee.I40d2ef06099cb091e9c2c01f8ef521b993a3d559@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ilan Peer and committed by
Johannes Berg
820acc81 5dca295d

+144 -2
+5
net/mac80211/ieee80211_i.h
··· 2520 2520 void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache); 2521 2521 void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache); 2522 2522 2523 + u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype); 2524 + u8 *ieee80211_ie_build_eht_cap(u8 *pos, 2525 + const struct ieee80211_sta_he_cap *he_cap, 2526 + const struct ieee80211_sta_eht_cap *eht_cap, 2527 + u8 *end); 2523 2528 #endif /* IEEE80211_I_H */
+13 -1
net/mac80211/main.c
··· 909 909 int result, i; 910 910 enum nl80211_band band; 911 911 int channels, max_bitrates; 912 - bool supp_ht, supp_vht, supp_he; 912 + bool supp_ht, supp_vht, supp_he, supp_eht; 913 913 struct cfg80211_chan_def dflt_chandef = {}; 914 914 915 915 if (ieee80211_hw_check(hw, QUEUE_CONTROL) && ··· 978 978 supp_ht = false; 979 979 supp_vht = false; 980 980 supp_he = false; 981 + supp_eht = false; 981 982 for (band = 0; band < NUM_NL80211_BANDS; band++) { 982 983 struct ieee80211_supported_band *sband; 983 984 ··· 1022 1021 iftd = &sband->iftype_data[i]; 1023 1022 1024 1023 supp_he = supp_he || iftd->he_cap.has_he; 1024 + supp_eht = supp_eht || iftd->eht_cap.has_eht; 1025 1025 } 1026 1026 1027 1027 /* HT, VHT, HE require QoS, thus >= 4 queues */ 1028 1028 if (WARN_ON(local->hw.queues < IEEE80211_NUM_ACS && 1029 1029 (supp_ht || supp_vht || supp_he))) 1030 + return -EINVAL; 1031 + 1032 + /* EHT requires HE support */ 1033 + if (WARN_ON(supp_eht && !supp_he)) 1030 1034 return -EINVAL; 1031 1035 1032 1036 if (!sband->ht_cap.ht_supported) ··· 1144 1138 3 + sizeof(struct ieee80211_he_cap_elem) + 1145 1139 sizeof(struct ieee80211_he_mcs_nss_supp) + 1146 1140 IEEE80211_HE_PPE_THRES_MAX_LEN; 1141 + 1142 + if (supp_eht) 1143 + local->scan_ies_len += 1144 + 3 + sizeof(struct ieee80211_eht_cap_elem) + 1145 + sizeof(struct ieee80211_eht_mcs_nss_supp) + 1146 + IEEE80211_EHT_PPE_THRES_MAX_LEN; 1147 1147 } 1148 1148 1149 1149 if (!local->ops->hw_scan) {
+47 -1
net/mac80211/mlme.c
··· 692 692 ieee80211_ie_build_he_6ghz_cap(sdata, skb); 693 693 } 694 694 695 + static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, 696 + struct sk_buff *skb, 697 + struct ieee80211_supported_band *sband) 698 + { 699 + u8 *pos; 700 + const struct ieee80211_sta_he_cap *he_cap; 701 + const struct ieee80211_sta_eht_cap *eht_cap; 702 + struct ieee80211_chanctx_conf *chanctx_conf; 703 + u8 eht_cap_size; 704 + bool reg_cap = false; 705 + 706 + rcu_read_lock(); 707 + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 708 + if (!WARN_ON_ONCE(!chanctx_conf)) 709 + reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, 710 + &chanctx_conf->def, 711 + IEEE80211_CHAN_NO_HE | 712 + IEEE80211_CHAN_NO_EHT); 713 + rcu_read_unlock(); 714 + 715 + he_cap = ieee80211_get_he_iftype_cap(sband, 716 + ieee80211_vif_type_p2p(&sdata->vif)); 717 + eht_cap = ieee80211_get_eht_iftype_cap(sband, 718 + ieee80211_vif_type_p2p(&sdata->vif)); 719 + 720 + /* 721 + * EHT capabilities element is only added if the HE capabilities element 722 + * was added so assume that 'he_cap' is valid and don't check it. 723 + */ 724 + if (WARN_ON(!he_cap || !eht_cap || !reg_cap)) 725 + return; 726 + 727 + eht_cap_size = 728 + 2 + 1 + sizeof(eht_cap->eht_cap_elem) + 729 + ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, 730 + &eht_cap->eht_cap_elem) + 731 + ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], 732 + eht_cap->eht_cap_elem.phy_cap_info); 733 + pos = skb_put(skb, eht_cap_size); 734 + ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size); 735 + } 736 + 695 737 static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) 696 738 { 697 739 struct ieee80211_local *local = sdata->local; ··· 1062 1020 ifmgd->flags |= IEEE80211_STA_DISABLE_HE | 1063 1021 IEEE80211_STA_DISABLE_EHT; 1064 1022 1065 - if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) 1023 + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) { 1066 1024 ieee80211_add_he_ie(sdata, skb, sband); 1025 + 1026 + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_EHT)) 1027 + ieee80211_add_eht_ie(sdata, skb, sband); 1028 + } 1067 1029 1068 1030 /* if present, add any custom non-vendor IEs that go after HE */ 1069 1031 if (assoc_data->ie_len) {
+79
net/mac80211/util.c
··· 1812 1812 struct ieee80211_local *local = sdata->local; 1813 1813 struct ieee80211_supported_band *sband; 1814 1814 const struct ieee80211_sta_he_cap *he_cap; 1815 + const struct ieee80211_sta_eht_cap *eht_cap; 1815 1816 u8 *pos = buffer, *end = buffer + buffer_len; 1816 1817 size_t noffset; 1817 1818 int supp_rates_len, i; ··· 1989 1988 cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), 1990 1989 IEEE80211_CHAN_NO_HE)) { 1991 1990 pos = ieee80211_ie_build_he_cap(0, pos, he_cap, end); 1991 + if (!pos) 1992 + goto out_err; 1993 + } 1994 + 1995 + eht_cap = ieee80211_get_eht_iftype_cap(sband, 1996 + ieee80211_vif_type_p2p(&sdata->vif)); 1997 + 1998 + if (eht_cap && 1999 + cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), 2000 + IEEE80211_CHAN_NO_HE | 2001 + IEEE80211_CHAN_NO_EHT)) { 2002 + pos = ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, end); 1992 2003 if (!pos) 1993 2004 goto out_err; 1994 2005 } ··· 4752 4739 FIELD_PREP(LISTEN_INT_UI, ui); 4753 4740 4754 4741 return (u16) listen_interval; 4742 + } 4743 + 4744 + u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype) 4745 + { 4746 + const struct ieee80211_sta_he_cap *he_cap; 4747 + const struct ieee80211_sta_eht_cap *eht_cap; 4748 + struct ieee80211_supported_band *sband; 4749 + u8 n; 4750 + 4751 + sband = ieee80211_get_sband(sdata); 4752 + if (!sband) 4753 + return 0; 4754 + 4755 + he_cap = ieee80211_get_he_iftype_cap(sband, iftype); 4756 + eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype); 4757 + if (!he_cap || !eht_cap) 4758 + return 0; 4759 + 4760 + n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, 4761 + &eht_cap->eht_cap_elem); 4762 + return 2 + 1 + 4763 + sizeof(he_cap->he_cap_elem) + n + 4764 + ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], 4765 + eht_cap->eht_cap_elem.phy_cap_info); 4766 + return 0; 4767 + } 4768 + 4769 + u8 *ieee80211_ie_build_eht_cap(u8 *pos, 4770 + const struct ieee80211_sta_he_cap *he_cap, 4771 + const struct ieee80211_sta_eht_cap *eht_cap, 4772 + u8 *end) 4773 + { 4774 + u8 mcs_nss_len, ppet_len; 4775 + u8 ie_len; 4776 + u8 *orig_pos = pos; 4777 + 4778 + /* Make sure we have place for the IE */ 4779 + if (!he_cap || !eht_cap) 4780 + return orig_pos; 4781 + 4782 + mcs_nss_len = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, 4783 + &eht_cap->eht_cap_elem); 4784 + ppet_len = ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], 4785 + eht_cap->eht_cap_elem.phy_cap_info); 4786 + 4787 + ie_len = 2 + 1 + sizeof(eht_cap->eht_cap_elem) + mcs_nss_len + ppet_len; 4788 + if ((end - pos) < ie_len) 4789 + return orig_pos; 4790 + 4791 + *pos++ = WLAN_EID_EXTENSION; 4792 + *pos++ = ie_len - 2; 4793 + *pos++ = WLAN_EID_EXT_EHT_CAPABILITY; 4794 + 4795 + /* Fixed data */ 4796 + memcpy(pos, &eht_cap->eht_cap_elem, sizeof(eht_cap->eht_cap_elem)); 4797 + pos += sizeof(eht_cap->eht_cap_elem); 4798 + 4799 + memcpy(pos, &eht_cap->eht_mcs_nss_supp, mcs_nss_len); 4800 + pos += mcs_nss_len; 4801 + 4802 + if (ppet_len) { 4803 + memcpy(pos, &eht_cap->eht_ppe_thres, ppet_len); 4804 + pos += ppet_len; 4805 + } 4806 + 4807 + return pos; 4755 4808 }