0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ieee80211_i.h"
0010
0011 static void
0012 ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
0013 struct link_sta_info *link_sta)
0014 {
0015 struct sta_info *sta = link_sta->sta;
0016 enum ieee80211_smps_mode smps_mode;
0017
0018 if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
0019 sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
0020 switch (le16_get_bits(he_6ghz_capa->capa,
0021 IEEE80211_HE_6GHZ_CAP_SM_PS)) {
0022 case WLAN_HT_CAP_SM_PS_INVALID:
0023 case WLAN_HT_CAP_SM_PS_STATIC:
0024 smps_mode = IEEE80211_SMPS_STATIC;
0025 break;
0026 case WLAN_HT_CAP_SM_PS_DYNAMIC:
0027 smps_mode = IEEE80211_SMPS_DYNAMIC;
0028 break;
0029 case WLAN_HT_CAP_SM_PS_DISABLED:
0030 smps_mode = IEEE80211_SMPS_OFF;
0031 break;
0032 }
0033
0034 sta->sta.smps_mode = smps_mode;
0035 } else {
0036 sta->sta.smps_mode = IEEE80211_SMPS_OFF;
0037 }
0038
0039 switch (le16_get_bits(he_6ghz_capa->capa,
0040 IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
0041 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
0042 sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
0043 break;
0044 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
0045 sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
0046 break;
0047 case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
0048 default:
0049 sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
0050 break;
0051 }
0052
0053 link_sta->pub->he_6ghz_capa = *he_6ghz_capa;
0054 }
0055
0056 static void ieee80211_he_mcs_disable(__le16 *he_mcs)
0057 {
0058 u32 i;
0059
0060 for (i = 0; i < 8; i++)
0061 *he_mcs |= cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
0062 }
0063
0064 static void ieee80211_he_mcs_intersection(__le16 *he_own_rx, __le16 *he_peer_rx,
0065 __le16 *he_own_tx, __le16 *he_peer_tx)
0066 {
0067 u32 i;
0068 u16 own_rx, own_tx, peer_rx, peer_tx;
0069
0070 for (i = 0; i < 8; i++) {
0071 own_rx = le16_to_cpu(*he_own_rx);
0072 own_rx = (own_rx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
0073
0074 own_tx = le16_to_cpu(*he_own_tx);
0075 own_tx = (own_tx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
0076
0077 peer_rx = le16_to_cpu(*he_peer_rx);
0078 peer_rx = (peer_rx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
0079
0080 peer_tx = le16_to_cpu(*he_peer_tx);
0081 peer_tx = (peer_tx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
0082
0083 if (peer_tx != IEEE80211_HE_MCS_NOT_SUPPORTED) {
0084 if (own_rx == IEEE80211_HE_MCS_NOT_SUPPORTED)
0085 peer_tx = IEEE80211_HE_MCS_NOT_SUPPORTED;
0086 else if (own_rx < peer_tx)
0087 peer_tx = own_rx;
0088 }
0089
0090 if (peer_rx != IEEE80211_HE_MCS_NOT_SUPPORTED) {
0091 if (own_tx == IEEE80211_HE_MCS_NOT_SUPPORTED)
0092 peer_rx = IEEE80211_HE_MCS_NOT_SUPPORTED;
0093 else if (own_tx < peer_rx)
0094 peer_rx = own_tx;
0095 }
0096
0097 *he_peer_rx &=
0098 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
0099 *he_peer_rx |= cpu_to_le16(peer_rx << i * 2);
0100
0101 *he_peer_tx &=
0102 ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
0103 *he_peer_tx |= cpu_to_le16(peer_tx << i * 2);
0104 }
0105 }
0106
0107 void
0108 ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
0109 struct ieee80211_supported_band *sband,
0110 const u8 *he_cap_ie, u8 he_cap_len,
0111 const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
0112 struct link_sta_info *link_sta)
0113 {
0114 struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
0115 struct ieee80211_sta_he_cap own_he_cap;
0116 struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
0117 u8 he_ppe_size;
0118 u8 mcs_nss_size;
0119 u8 he_total_size;
0120 bool own_160, peer_160, own_80p80, peer_80p80;
0121
0122 memset(he_cap, 0, sizeof(*he_cap));
0123
0124 if (!he_cap_ie ||
0125 !ieee80211_get_he_iftype_cap(sband,
0126 ieee80211_vif_type_p2p(&sdata->vif)))
0127 return;
0128
0129 own_he_cap = sband->iftype_data->he_cap;
0130
0131
0132 mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
0133 he_ppe_size =
0134 ieee80211_he_ppe_size(he_cap_ie[sizeof(he_cap->he_cap_elem) +
0135 mcs_nss_size],
0136 he_cap_ie_elem->phy_cap_info);
0137 he_total_size = sizeof(he_cap->he_cap_elem) + mcs_nss_size +
0138 he_ppe_size;
0139 if (he_cap_len < he_total_size)
0140 return;
0141
0142 memcpy(&he_cap->he_cap_elem, he_cap_ie, sizeof(he_cap->he_cap_elem));
0143
0144
0145 memcpy(&he_cap->he_mcs_nss_supp,
0146 &he_cap_ie[sizeof(he_cap->he_cap_elem)], mcs_nss_size);
0147
0148
0149 if (he_cap->he_cap_elem.phy_cap_info[6] &
0150 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
0151 memcpy(he_cap->ppe_thres,
0152 &he_cap_ie[sizeof(he_cap->he_cap_elem) + mcs_nss_size],
0153 he_ppe_size);
0154
0155 he_cap->has_he = true;
0156
0157 link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
0158 link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
0159
0160 if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa)
0161 ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);
0162
0163 ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80,
0164 &he_cap->he_mcs_nss_supp.rx_mcs_80,
0165 &own_he_cap.he_mcs_nss_supp.tx_mcs_80,
0166 &he_cap->he_mcs_nss_supp.tx_mcs_80);
0167
0168 own_160 = own_he_cap.he_cap_elem.phy_cap_info[0] &
0169 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
0170 peer_160 = he_cap->he_cap_elem.phy_cap_info[0] &
0171 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
0172
0173 if (peer_160 && own_160) {
0174 ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_160,
0175 &he_cap->he_mcs_nss_supp.rx_mcs_160,
0176 &own_he_cap.he_mcs_nss_supp.tx_mcs_160,
0177 &he_cap->he_mcs_nss_supp.tx_mcs_160);
0178 } else if (peer_160 && !own_160) {
0179 ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_160);
0180 ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_160);
0181 he_cap->he_cap_elem.phy_cap_info[0] &=
0182 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
0183 }
0184
0185 own_80p80 = own_he_cap.he_cap_elem.phy_cap_info[0] &
0186 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
0187 peer_80p80 = he_cap->he_cap_elem.phy_cap_info[0] &
0188 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
0189
0190 if (peer_80p80 && own_80p80) {
0191 ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80p80,
0192 &he_cap->he_mcs_nss_supp.rx_mcs_80p80,
0193 &own_he_cap.he_mcs_nss_supp.tx_mcs_80p80,
0194 &he_cap->he_mcs_nss_supp.tx_mcs_80p80);
0195 } else if (peer_80p80 && !own_80p80) {
0196 ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_80p80);
0197 ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_80p80);
0198 he_cap->he_cap_elem.phy_cap_info[0] &=
0199 ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
0200 }
0201 }
0202
0203 void
0204 ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
0205 const struct ieee80211_he_operation *he_op_ie)
0206 {
0207 memset(&vif->bss_conf.he_oper, 0, sizeof(vif->bss_conf.he_oper));
0208 if (!he_op_ie)
0209 return;
0210
0211 vif->bss_conf.he_oper.params = __le32_to_cpu(he_op_ie->he_oper_params);
0212 vif->bss_conf.he_oper.nss_set = __le16_to_cpu(he_op_ie->he_mcs_nss_set);
0213 }
0214
0215 void
0216 ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif,
0217 const struct ieee80211_he_spr *he_spr_ie_elem)
0218 {
0219 struct ieee80211_he_obss_pd *he_obss_pd =
0220 &vif->bss_conf.he_obss_pd;
0221 const u8 *data;
0222
0223 memset(he_obss_pd, 0, sizeof(*he_obss_pd));
0224
0225 if (!he_spr_ie_elem)
0226 return;
0227 data = he_spr_ie_elem->optional;
0228
0229 if (he_spr_ie_elem->he_sr_control &
0230 IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
0231 data++;
0232 if (he_spr_ie_elem->he_sr_control &
0233 IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) {
0234 he_obss_pd->max_offset = *data++;
0235 he_obss_pd->min_offset = *data++;
0236 he_obss_pd->enable = true;
0237 }
0238 }