| @@ -336,6 +336,13 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { · 335 unmodified lines |
| 336 | .len = NL80211_MAX_SUPP_HT_RATES }, | 336 | .len = NL80211_MAX_SUPP_HT_RATES }, |
| 337 | [NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)), | 337 | [NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)), |
| 338 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, | 338 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, |
| | 339 | [NL80211_TXRATE_HE] = NLA_POLICY_EXACT_LEN(sizeof(struct nl80211_txrate_he)), |
| | 340 | [NL80211_TXRATE_HE_GI] = NLA_POLICY_RANGE(NLA_U8, |
| | 341 | NL80211_RATE_INFO_HE_GI_0_8, |
| | 342 | NL80211_RATE_INFO_HE_GI_3_2), |
| | 343 | [NL80211_TXRATE_HE_LTF] = NLA_POLICY_RANGE(NLA_U8, |
| | 344 | NL80211_RATE_INFO_HE_1XLTF, |
| | 345 | NL80211_RATE_INFO_HE_4XLTF), |
| 339 | }; | 346 | }; |
| 340 | | 347 | |
| 341 | static const struct nla_policy | 348 | static const struct nla_policy |
| @@ -4430,21 +4437,106 @@ static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband, · 4088 unmodified lines |
| 4430 | return true; | 4437 | return true; |
| 4431 | } | 4438 | } |
| 4432 | | 4439 | |
| | 4440 | static u16 he_mcs_map_to_mcs_mask(u8 he_mcs_map) |
| | 4441 | { |
| | 4442 | switch (he_mcs_map) { |
| | 4443 | case IEEE80211_HE_MCS_NOT_SUPPORTED: |
| | 4444 | return 0; |
| | 4445 | case IEEE80211_HE_MCS_SUPPORT_0_7: |
| | 4446 | return 0x00FF; |
| | 4447 | case IEEE80211_HE_MCS_SUPPORT_0_9: |
| | 4448 | return 0x03FF; |
| | 4449 | case IEEE80211_HE_MCS_SUPPORT_0_11: |
| | 4450 | return 0xFFF; |
| | 4451 | default: |
| | 4452 | break; |
| | 4453 | } |
| | 4454 | return 0; |
| | 4455 | } |
| | 4456 | |
| | 4457 | static void he_build_mcs_mask(u16 he_mcs_map, |
| | 4458 | u16 he_mcs_mask[NL80211_HE_NSS_MAX]) |
| | 4459 | { |
| | 4460 | u8 nss; |
| | 4461 | |
| | 4462 | for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { |
| | 4463 | he_mcs_mask[nss] = he_mcs_map_to_mcs_mask(he_mcs_map & 0x03); |
| | 4464 | he_mcs_map >>= 2; |
| | 4465 | } |
| | 4466 | } |
| | 4467 | |
| | 4468 | static u16 he_get_txmcsmap(struct genl_info *info, |
| | 4469 | const struct ieee80211_sta_he_cap *he_cap) |
| | 4470 | { |
| | 4471 | struct net_device *dev = info->user_ptr[1]; |
| | 4472 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| | 4473 | __le16 tx_mcs; |
| | 4474 | |
| | 4475 | switch (wdev->chandef.width) { |
| | 4476 | case NL80211_CHAN_WIDTH_80P80: |
| | 4477 | tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80p80; |
| | 4478 | break; |
| | 4479 | case NL80211_CHAN_WIDTH_160: |
| | 4480 | tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_160; |
| | 4481 | break; |
| | 4482 | default: |
| | 4483 | tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80; |
| | 4484 | break; |
| | 4485 | } |
| | 4486 | return le16_to_cpu(tx_mcs); |
| | 4487 | } |
| | 4488 | |
| | 4489 | static bool he_set_mcs_mask(struct genl_info *info, |
| | 4490 | struct wireless_dev *wdev, |
| | 4491 | struct ieee80211_supported_band *sband, |
| | 4492 | struct nl80211_txrate_he *txrate, |
| | 4493 | u16 mcs[NL80211_HE_NSS_MAX]) |
| | 4494 | { |
| | 4495 | const struct ieee80211_sta_he_cap *he_cap; |
| | 4496 | u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {}; |
| | 4497 | u16 tx_mcs_map = 0; |
| | 4498 | u8 i; |
| | 4499 | |
| | 4500 | he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype); |
| | 4501 | if (!he_cap) |
| | 4502 | return false; |
| | 4503 | |
| | 4504 | memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX); |
| | 4505 | |
| | 4506 | tx_mcs_map = he_get_txmcsmap(info, he_cap); |
| | 4507 | |
| | 4508 | /* Build he_mcs_mask from HE capabilities */ |
| | 4509 | he_build_mcs_mask(tx_mcs_map, tx_mcs_mask); |
| | 4510 | |
| | 4511 | for (i = 0; i < NL80211_HE_NSS_MAX; i++) { |
| | 4512 | if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i]) |
| | 4513 | mcs[i] = txrate->mcs[i]; |
| | 4514 | else |
| | 4515 | return false; |
| | 4516 | } |
| | 4517 | |
| | 4518 | return true; |
| | 4519 | } |
| | 4520 | |
| 4433 | static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, | 4521 | static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, |
| 4434 | struct nlattr *attrs[], | 4522 | struct nlattr *attrs[], |
| 4435 | enum nl80211_attrs attr, | 4523 | enum nl80211_attrs attr, |
| 4436 | struct cfg80211_bitrate_mask *mask) | 4524 | struct cfg80211_bitrate_mask *mask, |
| | 4525 | struct net_device *dev) |
| 4437 | { | 4526 | { |
| 4438 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | 4527 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; |
| 4439 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4528 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| | 4529 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 4440 | int rem, i; | 4530 | int rem, i; |
| 4441 | struct nlattr *tx_rates; | 4531 | struct nlattr *tx_rates; |
| 4442 | struct ieee80211_supported_band *sband; | 4532 | struct ieee80211_supported_band *sband; |
| 4443 | u16 vht_tx_mcs_map; | 4533 | u16 vht_tx_mcs_map, he_tx_mcs_map; |
| 4444 | | 4534 | |
| 4445 | memset(mask, 0, sizeof(*mask)); | 4535 | memset(mask, 0, sizeof(*mask)); |
| 4446 | /* Default to all rates enabled */ | 4536 | /* Default to all rates enabled */ |
| 4447 | for (i = 0; i < NUM_NL80211_BANDS; i++) { | 4537 | for (i = 0; i < NUM_NL80211_BANDS; i++) { |
| | 4538 | const struct ieee80211_sta_he_cap *he_cap; |
| | 4539 | |
| 4448 | sband = rdev->wiphy.bands[i]; | 4540 | sband = rdev->wiphy.bands[i]; |
| 4449 | | 4541 | |
| 4450 | if (!sband) | 4542 | if (!sband) |
| @@ -4460,6 +4552,16 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, · 9 unmodified lines |
| 4460 | | 4552 | |
| 4461 | vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | 4553 | vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); |
| 4462 | vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs); | 4554 | vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs); |
| | 4555 | |
| | 4556 | he_cap = ieee80211_get_he_iftype_cap(sband, wdev->iftype); |
| | 4557 | if (!he_cap) |
| | 4558 | continue; |
| | 4559 | |
| | 4560 | he_tx_mcs_map = he_get_txmcsmap(info, he_cap); |
| | 4561 | he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs); |
| | 4562 | |
| | 4563 | mask->control[i].he_gi = 0xFF; |
| | 4564 | mask->control[i].he_ltf = 0xFF; |
| 4463 | } | 4565 | } |
| 4464 | | 4566 | |
| 4465 | /* if no rates are given set it back to the defaults */ | 4567 | /* if no rates are given set it back to the defaults */ |
| @@ -4515,13 +4617,25 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, · 49 unmodified lines |
| 4515 | if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI) | 4617 | if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI) |
| 4516 | return -EINVAL; | 4618 | return -EINVAL; |
| 4517 | } | 4619 | } |
| | 4620 | if (tb[NL80211_TXRATE_HE] && |
| | 4621 | !he_set_mcs_mask(info, wdev, sband, |
| | 4622 | nla_data(tb[NL80211_TXRATE_HE]), |
| | 4623 | mask->control[band].he_mcs)) |
| | 4624 | return -EINVAL; |
| | 4625 | if (tb[NL80211_TXRATE_HE_GI]) |
| | 4626 | mask->control[band].he_gi = |
| | 4627 | nla_get_u8(tb[NL80211_TXRATE_HE_GI]); |
| | 4628 | if (tb[NL80211_TXRATE_HE_LTF]) |
| | 4629 | mask->control[band].he_ltf = |
| | 4630 | nla_get_u8(tb[NL80211_TXRATE_HE_LTF]); |
| 4518 | | 4631 | |
| 4519 | if (mask->control[band].legacy == 0) { | 4632 | if (mask->control[band].legacy == 0) { |
| 4520 | /* don't allow empty legacy rates if HT or VHT | 4633 | /* don't allow empty legacy rates if HT, VHT or HE |
| 4521 | * are not even supported. | 4634 | * are not even supported. |
| 4522 | */ | 4635 | */ |
| 4523 | if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || | 4636 | if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || |
| 4524 | rdev->wiphy.bands[band]->vht_cap.vht_supported)) | 4637 | rdev->wiphy.bands[band]->vht_cap.vht_supported || |
| | 4638 | ieee80211_get_he_iftype_cap(sband, wdev->iftype))) |
| 4525 | return -EINVAL; | 4639 | return -EINVAL; |
| 4526 | | 4640 | |
| 4527 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | 4641 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) |
| @@ -4532,6 +4646,10 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, · 4 unmodified lines |
| 4532 | if (mask->control[band].vht_mcs[i]) | 4646 | if (mask->control[band].vht_mcs[i]) |
| 4533 | goto out; | 4647 | goto out; |
| 4534 | | 4648 | |
| | 4649 | for (i = 0; i < NL80211_HE_NSS_MAX; i++) |
| | 4650 | if (mask->control[band].he_mcs[i]) |
| | 4651 | goto out; |
| | 4652 | |
| 4535 | /* legacy and mcs rates may not be both empty */ | 4653 | /* legacy and mcs rates may not be both empty */ |
| 4536 | return -EINVAL; | 4654 | return -EINVAL; |
| 4537 | } | 4655 | } |
| @@ -4976,7 +5094,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) · 438 unmodified lines |
| 4976 | if (info->attrs[NL80211_ATTR_TX_RATES]) { | 5094 | if (info->attrs[NL80211_ATTR_TX_RATES]) { |
| 4977 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, | 5095 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, |
| 4978 | NL80211_ATTR_TX_RATES, | 5096 | NL80211_ATTR_TX_RATES, |
| 4979 | ¶ms.beacon_rate); | 5097 | ¶ms.beacon_rate, |
| | 5098 | dev); |
| 4980 | if (err) | 5099 | if (err) |
| 4981 | return err; | 5100 | return err; |
| 4982 | | 5101 | |
| @@ -10780,7 +10899,8 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, · 5797 unmodified lines |
| 10780 | return -EOPNOTSUPP; | 10899 | return -EOPNOTSUPP; |
| 10781 | | 10900 | |
| 10782 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, | 10901 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, |
| 10783 | NL80211_ATTR_TX_RATES, &mask); | 10902 | NL80211_ATTR_TX_RATES, &mask, |
| | 10903 | dev); |
| 10784 | if (err) | 10904 | if (err) |
| 10785 | return err; | 10905 | return err; |
| 10786 | | 10906 | |
| @@ -11388,7 +11508,8 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) · 601 unmodified lines |
| 11388 | if (info->attrs[NL80211_ATTR_TX_RATES]) { | 11508 | if (info->attrs[NL80211_ATTR_TX_RATES]) { |
| 11389 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, | 11509 | err = nl80211_parse_tx_bitrate_mask(info, info->attrs, |
| 11390 | NL80211_ATTR_TX_RATES, | 11510 | NL80211_ATTR_TX_RATES, |
| 11391 | &setup.beacon_rate); | 11511 | &setup.beacon_rate, |
| | 11512 | dev); |
| 11392 | if (err) | 11513 | if (err) |
| 11393 | return err; | 11514 | return err; |
| 11394 | | 11515 | |
| @@ -14168,7 +14289,7 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev, · 2773 unmodified lines |
| 14168 | if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) { | 14289 | if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) { |
| 14169 | attr = NL80211_TID_CONFIG_ATTR_TX_RATE; | 14290 | attr = NL80211_TID_CONFIG_ATTR_TX_RATE; |
| 14170 | err = nl80211_parse_tx_bitrate_mask(info, attrs, attr, | 14291 | err = nl80211_parse_tx_bitrate_mask(info, attrs, attr, |
| 14171 | &tid_conf->txrate_mask); | 14292 | &tid_conf->txrate_mask, dev); |
| 14172 | if (err) | 14293 | if (err) |
| 14173 | return err; | 14294 | return err; |
| 14174 | | 14295 | |