18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / IEEE 802.11n HT 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007-2008, Intel Corporation 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * See README for more details. 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 137832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "utils/eloop.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h" 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "beacon.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11.h" 207832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "hw_features.h" 217832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "ap_drv_ops.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_capabilities *cap; 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos = eid; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode || 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->conf->disable_11n) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eid; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = WLAN_EID_HT_CAP; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = sizeof(*cap); 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap = (struct ieee80211_ht_capabilities *) pos; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(cap, 0, sizeof(*cap)); 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set, 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16); 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: ht_extended_capabilities (now fully disabled) */ 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: tx_bf_capability_info (now fully disabled) */ 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: asel_capabilities (now fully disabled) */ 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(*cap); 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 495460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt if (hapd->iconf->obss_interval) { 505460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt struct ieee80211_obss_scan_parameters *scan_params; 515460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt 525460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt *pos++ = WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS; 535460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt *pos++ = sizeof(*scan_params); 545460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt 555460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt scan_params = (struct ieee80211_obss_scan_parameters *) pos; 565460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt os_memset(scan_params, 0, sizeof(*scan_params)); 575460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt scan_params->width_trigger_scan_interval = 585460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt host_to_le16(hapd->iconf->obss_interval); 595460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt 60b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt /* Fill in default values for remaining parameters 61b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt * (IEEE Std 802.11-2012, 8.4.2.61 and MIB defval) */ 62b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->scan_passive_dwell = 63b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(20); 64b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->scan_active_dwell = 65b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(10); 66b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->scan_passive_total_per_channel = 67b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(200); 68b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->scan_active_total_per_channel = 69b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(20); 70b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->channel_transition_delay_factor = 71b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(5); 72b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt scan_params->scan_activity_threshold = 73b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt host_to_le16(25); 745460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt 755460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt pos += sizeof(*scan_params); 765460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt } 775460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos = eid; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eid; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = WLAN_EID_HT_OPERATION; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos++ = sizeof(*oper); 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) pos; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(oper, 0, sizeof(*oper)); 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 96f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt oper->primary_chan = hapd->iconf->channel; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hapd->iconf->secondary_channel == 1) 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | 100f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt HT_INFO_HT_PARAM_STA_CHNL_WIDTH; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hapd->iconf->secondary_channel == -1) 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | 103f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt HT_INFO_HT_PARAM_STA_CHNL_WIDTH; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += sizeof(*oper); 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return pos; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtop_mode 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSet to 0 (HT pure) under the followign conditions 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt - all STAs in the BSS are 20 MHz HT in 20 MHz BSS 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSet to 1 (HT non-member protection) if there may be non-HT STAs 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt in both the primary and the secondary channel 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSet to 2 if only HT STAs are associated in BSS, 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt however and at least one 20 MHz HT STA is associated 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSet to 3 (HT mixed mode) when one or more non-HT STAs are associated 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/ 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_ht_operation_update(struct hostapd_iface *iface) 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 cur_op_mode, new_op_mode; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int op_mode_changes = 0; 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X", 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, iface->ht_op_mode); 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 133f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (!(iface->ht_op_mode & HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT) 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt && iface->num_sta_ht_no_gf) { 135f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt iface->ht_op_mode |= HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT; 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt op_mode_changes++; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if ((iface->ht_op_mode & 138f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT) && 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_sta_ht_no_gf == 0) { 140f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt iface->ht_op_mode &= ~HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt op_mode_changes++; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 144f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (!(iface->ht_op_mode & HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) && 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (iface->num_sta_no_ht || iface->olbc_ht)) { 146f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt iface->ht_op_mode |= HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt op_mode_changes++; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if ((iface->ht_op_mode & 149f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT) && 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) { 151f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt iface->ht_op_mode &= ~HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt op_mode_changes++; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_sta_no_ht) 156f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt new_op_mode = HT_PROT_NON_HT_MIXED; 157f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz) 158f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt new_op_mode = HT_PROT_20MHZ_PROTECTION; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (iface->olbc_ht) 160f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt new_op_mode = HT_PROT_NONMEMBER_PROTECTION; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 162f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt new_op_mode = HT_PROT_NO_PROTECTION; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 164f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt cur_op_mode = iface->ht_op_mode & HT_OPER_OP_MODE_HT_PROT_MASK; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cur_op_mode != new_op_mode) { 166f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt iface->ht_op_mode &= ~HT_OPER_OP_MODE_HT_PROT_MASK; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ht_op_mode |= new_op_mode; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt op_mode_changes++; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d", 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, iface->ht_op_mode, op_mode_changes); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return op_mode_changes; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1787832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtstatic int is_40_allowed(struct hostapd_iface *iface, int channel) 1797832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 1807832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int pri_freq, sec_freq; 1817832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int affected_start, affected_end; 1827832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int pri = 2407 + 5 * channel; 1837832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 1847832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 1857832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 1; 1867832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 1877832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 1887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 1897832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->conf->secondary_channel > 0) 1907832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt sec_freq = pri_freq + 20; 1917832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt else 1927832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt sec_freq = pri_freq - 20; 1937832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 1947832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 1957832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 1967832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if ((pri < affected_start || pri > affected_end)) 1977832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 1; /* not within affected channel range */ 1987832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 1997832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz", 2007832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt affected_start, affected_end); 2017832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri); 2027832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 0; 2037832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 2047832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2057832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2067832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid hostapd_2040_coex_action(struct hostapd_data *hapd, 2077832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 2087832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 2097832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct hostapd_iface *iface = hapd->iface; 2107832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct ieee80211_2040_bss_coex_ie *bc_ie; 2117832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct ieee80211_2040_intol_chan_report *ic_report; 212af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt int is_ht40_allowed = 1; 2137832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int i; 2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *start = (const u8 *) mgmt; 2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt const u8 *data = start + IEEE80211_HDRLEN + 2; 2167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2177832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 2187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d", 2197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt mgmt->u.action.u.public_action.action); 2207832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2217832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) 2227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 2237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) 2257832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 2267832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt bc_ie = (struct ieee80211_2040_bss_coex_ie *) data; 2286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE || 2296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt bc_ie->length < 1) { 2306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report", 2316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt bc_ie->element_id, bc_ie->length); 2326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) 2356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt data += 2 + bc_ie->length; 2377832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x", 2396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt bc_ie->coex_param); 2407832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) { 2417832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_logger(hapd, mgmt->sa, 2427832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 2437832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 2447832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "20 MHz BSS width request bit is set in BSS coexistence information field"); 245af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt is_ht40_allowed = 0; 2467832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 2477832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2487832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) { 2497832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_logger(hapd, mgmt->sa, 2507832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 2517832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 2527832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "40 MHz intolerant bit is set in BSS coexistence information field"); 253af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt is_ht40_allowed = 0; 2547832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 2557832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (start + len - data >= 3 && 2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) { 2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 ielen = data[1]; 2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ielen > start + len - data - 2) 2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ic_report = (struct ieee80211_2040_intol_chan_report *) data; 2636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 2646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "20/40 BSS Intolerant Channel Report: Operating Class %u", 2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ic_report->op_class); 2666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2677832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt /* Go through the channel report to find any BSS there in the 2687832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * affected channel range */ 2696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (i = 0; i < ielen - 1; i++) { 2706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 chan = ic_report->variable[i]; 2716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (is_40_allowed(iface, chan)) 2737832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt continue; 2747832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_logger(hapd, mgmt->sa, 2757832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 2767832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 2777832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "20_40_INTOLERANT channel %d reported", 2786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan); 279af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt is_ht40_allowed = 0; 2807832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 2817832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 282af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d", 283af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt is_ht40_allowed, iface->num_sta_ht40_intolerant); 2847832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 285af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt if (!is_ht40_allowed && 2867832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { 2877832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->conf->secondary_channel) { 2887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_logger(hapd, mgmt->sa, 2897832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 2907832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HOSTAPD_LEVEL_INFO, 2917832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Switching to 20 MHz operation"); 2927832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 2937832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee802_11_set_beacons(iface); 2947832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 295216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt if (!iface->num_sta_ht40_intolerant && 296216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt iface->conf->obss_interval) { 2977832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt unsigned int delay_time; 2987832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR * 2997832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->obss_interval; 3007832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface, 3017832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt NULL); 3027832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(delay_time, 0, ap_ht2040_timeout, 3037832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hapd->iface, NULL); 3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Reschedule HT 20/40 timeout to occur in %u seconds", 3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt delay_time); 3077832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3087832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3097832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 3107832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3117832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, 3139d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt const u8 *ht_capab) 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 315912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt /* 316912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt * Disable HT caps for STAs associated to no-HT BSSes, or for stations 317912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt * that did not specify a valid WMM IE in the (Re)Association Request 318912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt * frame. 319912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt */ 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ht_capab || 321912c6ecf72fb2c84fbf17dbd0666492778dbd9fcDmitry Shmidt !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) { 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->flags &= ~WLAN_STA_HT; 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(sta->ht_capabilities); 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->ht_capabilities = NULL; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return WLAN_STATUS_SUCCESS; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sta->ht_capabilities == NULL) { 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->ht_capabilities = 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_zalloc(sizeof(struct ieee80211_ht_capabilities)); 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sta->ht_capabilities == NULL) 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return WLAN_STATUS_UNSPECIFIED_FAILURE; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->flags |= WLAN_STA_HT; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(sta->ht_capabilities, ht_capab, 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(struct ieee80211_ht_capabilities)); 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return WLAN_STATUS_SUCCESS; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3437832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta) 3447832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 3457832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 3467832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 3477832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3487832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR 3497832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt " in Association Request", MAC2STR(sta->addr)); 3507832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3517832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (sta->ht40_intolerant_set) 3527832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 3537832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3547832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt sta->ht40_intolerant_set = 1; 3557832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_sta_ht40_intolerant++; 3567832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); 3577832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3587832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->conf->secondary_channel && 3597832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { 3607832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 3617832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee802_11_set_beacons(iface); 3627832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3637832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 3647832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3657832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3667832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta) 3677832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 3687832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (!sta->ht40_intolerant_set) 3697832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 3707832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3717832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt sta->ht40_intolerant_set = 0; 3727832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_sta_ht40_intolerant--; 3737832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3747832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->num_sta_ht40_intolerant == 0 && 3757832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt (iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 3767832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { 3777832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR * 3787832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->obss_interval; 3797832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_DEBUG, 3807832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "HT: Start 20->40 MHz transition timer (%d seconds)", 3817832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt delay_time); 3827832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); 3837832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(delay_time, 0, ap_ht2040_timeout, 3847832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface, NULL); 3857832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3867832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 3877832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta) 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 ht_capab; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info); 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: " 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "0x%04x", MAC2STR(sta->addr), ht_capab); 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) { 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!sta->no_ht_gf_set) { 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->no_ht_gf_set = 1; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_ht_no_gf++; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num " 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "of non-gf stations %d", 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, MAC2STR(sta->addr), 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_ht_no_gf); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) { 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!sta->ht_20mhz_set) { 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->ht_20mhz_set = 1; 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_ht_20mhz++; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of " 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "20MHz HT STAs %d", 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, MAC2STR(sta->addr), 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_ht_20mhz); 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4177832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT) 4187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ht40_intolerant_add(hapd->iface, sta); 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta) 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!sta->no_ht_set) { 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sta->no_ht_set = 1; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_no_ht++; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hapd->iconf->ieee80211n) { 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of " 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "non-HT stations %d", 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, MAC2STR(sta->addr), 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hapd->iface->num_sta_no_ht); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt update_sta_ht(hapd, sta); 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt update_sta_no_ht(hapd, sta); 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_ht_operation_update(hapd->iface) > 0) 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_set_beacons(hapd->iface); 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_get_ht_capab(struct hostapd_data *hapd, 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_capabilities *ht_cap, 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_capabilities *neg_ht_cap) 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 cap; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ht_cap == NULL) 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap)); 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap = le_to_host16(neg_ht_cap->ht_capabilities_info); 45975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen 46075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen /* 46175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen * Mask out HT features we don't support, but don't overwrite 46275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen * non-symmetric features like STBC and SMPS. Just because 46375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen * we're not in dynamic SMPS mode the STA might still be. 46475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen */ 46575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK | 46675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK); 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * STBC needs to be handled specially 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if we don't support RX STBC, mask out TX STBC in the STA's HT caps 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * if we don't support TX STBC, mask out RX STBC in the STA's HT caps 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK)) 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap &= ~HT_CAP_INFO_TX_STBC; 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC)) 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cap &= ~HT_CAP_INFO_RX_STBC_MASK; 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt neg_ht_cap->ht_capabilities_info = host_to_le16(cap); 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4807832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4817832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4827832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid ap_ht2040_timeout(void *eloop_data, void *user_data) 4837832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 4847832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct hostapd_iface *iface = eloop_data; 4857832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4867832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_INFO, "Switching to 40 MHz operation"); 4877832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = iface->secondary_ch; 4897832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee802_11_set_beacons(iface); 4907832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 491