ieee802_11_vht.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * hostapd / IEEE 802.11ac VHT
  3. * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of BSD license
  7. *
  8. * See README and COPYING for more details.
  9. */
  10. #include "utils/includes.h"
  11. #include "utils/common.h"
  12. #include "common/ieee802_11_defs.h"
  13. #include "hostapd.h"
  14. #include "ap_config.h"
  15. #include "sta_info.h"
  16. #include "beacon.h"
  17. #include "ieee802_11.h"
  18. u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
  19. {
  20. struct ieee80211_vht_capabilities *cap;
  21. u8 *pos = eid;
  22. if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
  23. hapd->conf->disable_11ac)
  24. return eid;
  25. *pos++ = WLAN_EID_VHT_CAP;
  26. *pos++ = sizeof(*cap);
  27. cap = (struct ieee80211_vht_capabilities *) pos;
  28. os_memset(cap, 0, sizeof(*cap));
  29. cap->vht_capabilities_info = host_to_le32(
  30. hapd->iface->conf->vht_capab);
  31. /* Supported MCS set comes from hw */
  32. os_memcpy(&cap->vht_supported_mcs_set,
  33. hapd->iface->current_mode->vht_mcs_set, 8);
  34. pos += sizeof(*cap);
  35. return pos;
  36. }
  37. u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
  38. {
  39. struct ieee80211_vht_operation *oper;
  40. u8 *pos = eid;
  41. if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
  42. return eid;
  43. *pos++ = WLAN_EID_VHT_OPERATION;
  44. *pos++ = sizeof(*oper);
  45. oper = (struct ieee80211_vht_operation *) pos;
  46. os_memset(oper, 0, sizeof(*oper));
  47. /*
  48. * center freq = 5 GHz + (5 * index)
  49. * So index 42 gives center freq 5.210 GHz
  50. * which is channel 42 in 5G band
  51. */
  52. oper->vht_op_info_chan_center_freq_seg0_idx =
  53. hapd->iconf->vht_oper_centr_freq_seg0_idx;
  54. oper->vht_op_info_chan_center_freq_seg1_idx =
  55. hapd->iconf->vht_oper_centr_freq_seg1_idx;
  56. oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
  57. /* VHT Basic MCS set comes from hw */
  58. /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
  59. oper->vht_basic_mcs_set = host_to_le16(0xfffc);
  60. pos += sizeof(*oper);
  61. return pos;
  62. }
  63. u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
  64. const u8 *vht_capab, size_t vht_capab_len)
  65. {
  66. /* Disable VHT caps for STAs associated to no-VHT BSSes. */
  67. if (!vht_capab ||
  68. vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
  69. hapd->conf->disable_11ac) {
  70. sta->flags &= ~WLAN_STA_VHT;
  71. os_free(sta->vht_capabilities);
  72. sta->vht_capabilities = NULL;
  73. return WLAN_STATUS_SUCCESS;
  74. }
  75. if (sta->vht_capabilities == NULL) {
  76. sta->vht_capabilities =
  77. os_zalloc(sizeof(struct ieee80211_vht_capabilities));
  78. if (sta->vht_capabilities == NULL)
  79. return WLAN_STATUS_UNSPECIFIED_FAILURE;
  80. }
  81. sta->flags |= WLAN_STA_VHT;
  82. os_memcpy(sta->vht_capabilities, vht_capab,
  83. sizeof(struct ieee80211_vht_capabilities));
  84. return WLAN_STATUS_SUCCESS;
  85. }
  86. u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
  87. const u8 *vht_oper_notif)
  88. {
  89. u8 channel_width;
  90. if (!vht_oper_notif) {
  91. sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
  92. return WLAN_STATUS_SUCCESS;
  93. }
  94. channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
  95. if (channel_width != VHT_CHANWIDTH_USE_HT &&
  96. channel_width != VHT_CHANWIDTH_80MHZ &&
  97. channel_width != VHT_CHANWIDTH_160MHZ &&
  98. channel_width != VHT_CHANWIDTH_80P80MHZ &&
  99. ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >>
  100. VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) {
  101. sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
  102. return WLAN_STATUS_UNSPECIFIED_FAILURE;
  103. }
  104. sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
  105. sta->vht_opmode = *vht_oper_notif;
  106. return WLAN_STATUS_SUCCESS;
  107. }
  108. void hostapd_get_vht_capab(struct hostapd_data *hapd,
  109. struct ieee80211_vht_capabilities *vht_cap,
  110. struct ieee80211_vht_capabilities *neg_vht_cap)
  111. {
  112. u32 cap, own_cap, sym_caps;
  113. if (vht_cap == NULL)
  114. return;
  115. os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
  116. cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
  117. own_cap = hapd->iconf->vht_capab;
  118. /* mask out symmetric VHT capabilities we don't support */
  119. sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
  120. cap &= ~sym_caps | (own_cap & sym_caps);
  121. /* mask out beamformer/beamformee caps if not supported */
  122. if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
  123. cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
  124. VHT_CAP_BEAMFORMEE_STS_MAX);
  125. if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
  126. cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
  127. VHT_CAP_SOUNDING_DIMENSION_MAX);
  128. if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
  129. cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
  130. if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
  131. cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
  132. /* mask channel widths we don't support */
  133. switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
  134. case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
  135. break;
  136. case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
  137. if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
  138. cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
  139. cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
  140. }
  141. break;
  142. default:
  143. cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
  144. break;
  145. }
  146. if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
  147. cap &= ~VHT_CAP_SHORT_GI_160;
  148. /*
  149. * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
  150. * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
  151. */
  152. if (!(own_cap & VHT_CAP_RXSTBC_MASK))
  153. cap &= ~VHT_CAP_TXSTBC;
  154. if (!(own_cap & VHT_CAP_TXSTBC))
  155. cap &= ~VHT_CAP_RXSTBC_MASK;
  156. neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
  157. }