hw_features.c revision f21452aea786ac056eb01f1cbba4f553bd502747
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / Hardware feature query and different modes 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2002-2003, Instant802 Networks, Inc. 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2005-2006, Devicescape Software, Inc. 504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 8fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * See README for more details. 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h" 17cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_drv_ops.h" 21391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt#include "acs.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hw_features.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_hw_features) 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hw_features == NULL) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_hw_features; i++) { 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].channels); 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].rates); 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG 43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic char * dfs_info(struct hostapd_channel_data *chan) 44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt static char info[256]; 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt char *state; 47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNKNOWN: 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unknown"; 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_USABLE: 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "usable"; 54051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNAVAILABLE: 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unavailable"; 57051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_AVAILABLE: 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "available"; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ""; 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt os_snprintf(info, sizeof(info), " (DFS state = %s)", state); 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt info[sizeof(info) - 1] = '\0'; 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return info; 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */ 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0, i, j; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 98051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs_enabled = hapd->iconf->ieee80211h && 99051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); 100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs = 0; 105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * IBSS operation or active scanning. 109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Use radar channels only if the driver supports DFS. 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((feature->channels[j].flag & 112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR) && dfs_enabled) { 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs = 1; 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } else if (feature->channels[j].flag & 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (HOSTAPD_CHAN_NO_IBSS | 116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN | 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR)) { 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].flag |= 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_DISABLED; 120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 124051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 126051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "chan=%d freq=%d MHz max_tx_power=%d dBm%s", 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->mode, 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].chan, 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].freq, 130051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt feature->channels[j].max_tx_power, 131051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs ? dfs_info(&feature->channels[j]) : ""); 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint hostapd_prepare_rates(struct hostapd_iface *iface, 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode) 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, num_basic_rates = 0; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_a[] = { 60, 120, 240, -1 }; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_b[] = { 10, 20, -1 }; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *basic_rates; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->basic_rates) 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt basic_rates = iface->conf->basic_rates; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else switch (mode->mode) { 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_a; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_b; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_g; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; /* No basic rates for 11ad */ 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i = 0; 1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (basic_rates[i] >= 0) 1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i++; 1694530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt if (i) 1704530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt i++; /* -1 termination */ 1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->basic_rates); 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->basic_rates = os_malloc(i * sizeof(int)); 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->basic_rates) 1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->current_rates); 1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates = 0; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->current_rates = 18061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!iface->current_rates) { 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "table."); 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < mode->num_rates; i++) { 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_rate_data *rate; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->supported_rates && 1911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt !hostapd_rate_found(iface->conf->supported_rates, 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mode->rates[i])) 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rate = &iface->current_rates[iface->num_rates]; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->rate = mode->rates[i]; 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_rate_found(basic_rates, rate->rate)) { 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->flags |= HOSTAPD_RATE_BASIC; 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_basic_rates++; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, rate->rate, rate->flags); 2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates++; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((iface->num_rates == 0 || num_basic_rates == 0) && 2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "rate sets (%d,%d).", 2101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, num_basic_rates); 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, ok, j, first; 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 184, 192 }; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t k; 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel: %d", 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, sec_chan); 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel */ 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chan->chan == sec_chan) { 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan); 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the list of allowed channels (already checked above). 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = iface->conf->channel; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = sec_chan; 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 26768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (k = 0; k < ARRAY_SIZE(allowed); k++) { 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first == allowed[k]) { 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel); 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *pri_chan, int *sec_chan) 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems elems; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = *sec_chan = 0; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems.ht_operation && 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elems.ht_operation_len >= sizeof(*oper)) { 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = oper->control_chan; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = oper->ht_param & 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan + 4; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan - 4; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int bss_pri_chan, bss_sec_chan; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int match; 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->secondary_channel * 4; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel, but not on selected PRI channel. 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss = sec_bss = 0; 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss->freq == pri_freq) 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss++; 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (bss->freq == sec_freq) 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_bss++; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_bss && !pri_bss) { 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and secondary " 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel to get secondary channel with no Beacons " 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from other BSSes"); 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Match PRI/SEC channel with any existing HT40 BSS on the same 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channels that we are about to use (if already mixed order in 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * existing BSSes, use own preference). 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 0; 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_pri_chan && 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_sec_chan) { 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 1; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!match) { 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &bss_sec_chan); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_sec_chan && 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_pri_chan) { 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and " 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel due to BSS " 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "overlap with " MACSTR, 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid)); 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_freq, sec_freq; 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int affected_start, affected_end; 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start, affected_end); 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri = bss->freq; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = pri; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, pri_chan; 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan < pri_chan) 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri - 20; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri + 20; 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((pri < affected_start || pri > affected_end) && 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (sec < affected_start || sec > affected_end)) 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; /* not within affected channel range */ 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d pri=%d sec=%d", 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mismatch with BSS " MACSTR 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri, sec, pri_chan, 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec > pri ? '+' : '-', 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq, sec_freq); 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: 40 MHz intolerant */ 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 48804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 48904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 49004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 49104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 49204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 49304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 49404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 49504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 49604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 49704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 49804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 49904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 50004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 50104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 50204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 50304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 50404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 50504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 50604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 50704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 50804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 50904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 51161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 51304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 51404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 51504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 51704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 528cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, 529cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct wpa_driver_scan_params *params) 530cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 531cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Scan only the affected frequency range */ 532cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int pri_freq; 533cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int affected_start, affected_end; 534cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, pos; 535cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_hw_modes *mode; 536cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 537cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 538cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 539cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 540cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 541cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 542cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 10; 543cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 30; 544cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } else { 545cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 30; 546cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 10; 547cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 548cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 549cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start, affected_end); 550cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 551cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 552cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 553cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (params->freqs == NULL) 554cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 555cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pos = 0; 556cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 557cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 558cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 559cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 560cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 561cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->freq < affected_start || 562cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan->freq > affected_end) 563cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs[pos++] = chan->freq; 565cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 566cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 567cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* HT40 not used */ 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 576cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 58004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 58104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 582cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 583cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ieee80211n_scan_channels_5g(iface, ¶ms); 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to request a scan of " 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "neighboring BSSes"); 58704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 59004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SMPS-*]"); 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [PSMP]"); 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 69468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 69568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 69668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 69768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) 69868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 69968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 req_cap = conf & cap; 70068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 70168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 70268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * Make sure we support all requested capabilities. 70368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * NOTE: We assume that 'cap' represents a capability mask, 70468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * not a discrete value. 70568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 70668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if ((hw & req_cap) != req_cap) { 70768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", 70868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt name); 70968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 71068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 71168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 71268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 71368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 71468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 71568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap, 71668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt const char *name) 71768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 71868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 hw_max = hw & cap; 71968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 conf_val = conf & cap; 72068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 72168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (conf_val > hw_max) { 72268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int offset = find_first_bit(cap); 72368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", 72468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt name, conf_val >> offset, hw_max >> offset); 72568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 72668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 72768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 72868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 72968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 73068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 73168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) 73268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 73368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 hw = iface->current_mode->vht_capab; 73468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 conf = iface->conf->vht_capab; 73568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 73668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", 73768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt hw, conf); 73868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 73968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK(cap) \ 74068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 74168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ 74268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 74368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 74468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 74568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK_MAX(cap) \ 74668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 74768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \ 74868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 74968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 75068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 75168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); 75268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); 75368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); 75468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RXLDPC); 75568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); 75668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); 75768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TXSTBC); 75868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); 75968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); 76068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); 76168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); 76268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); 76368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); 76468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); 76568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); 76668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_HTC_VHT); 76768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT); 76868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); 76968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); 77068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); 77168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); 77268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 77368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK 77468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK_MAX 77568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 77668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 77768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 77868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 77968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 79168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 79268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_supported_vht_capab(iface)) 79368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return -1; 79468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 806b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chan(struct hostapd_iface *iface, 807b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int channel, int primary) 808b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 809b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 810b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt struct hostapd_channel_data *chan; 811b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 812b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 813b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan = &iface->current_mode->channels[i]; 814b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (chan->chan != channel) 815b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt continue; 816b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 817b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) 818b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 819b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 820b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt wpa_printf(MSG_DEBUG, 821b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s", 822b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt primary ? "" : "Configured HT40 secondary ", 823b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt i, chan->chan, chan->flag, 824b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "", 825b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ? 826b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt " PASSIVE-SCAN" : "", 827b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); 828b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 829b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 830b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 831b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 832b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 833b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 834b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chans(struct hostapd_iface *iface) 835b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 836b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) 837b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 838b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 839b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!iface->conf->secondary_channel) 840b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 841b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 842b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return hostapd_is_usable_chan(iface, iface->conf->channel + 843b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->secondary_channel * 4, 0); 844b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 845b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 846b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 847b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic enum hostapd_chan_status 848b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidthostapd_check_chans(struct hostapd_iface *iface) 849b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 850b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (iface->conf->channel) { 851b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (hostapd_is_usable_chans(iface)) 852b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_VALID; 853b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt else 854b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 855b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 856b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 857b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt /* 858391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * The user set channel=0 or channel=acs_survey 859391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * which is used to trigger ACS. 860b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt */ 861391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 862391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (acs_init(iface)) { 863391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 864391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_ACS; 865391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 866391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 867391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 868391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 869391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 870b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 871b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 872b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 873b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface) 874b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 875b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 876b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 877b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 878b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Configured channel (%d) not found from the " 879b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "channel list of current mode (%d) %s", 880b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->channel, 881b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->current_mode->mode, 882b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 883b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 884b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 885b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Hardware does not support configured channel"); 886b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 887b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 888b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 8894ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtint hostapd_acs_completed(struct hostapd_iface *iface, int err) 890391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt{ 8914ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt int ret = -1; 8924ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt 8934ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt if (err) 8944ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 895391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 896391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (hostapd_check_chans(iface)) { 897391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 898cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, 899cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ACS_EVENT_COMPLETED "freq=%d channel=%d", 900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_hw_get_freq(iface->bss[0], 901cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel), 902cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel); 903391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 904391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 905391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); 906cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 907391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 9084ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 909391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 910391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 911391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS picked unusable channels"); 912cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 913391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 9144ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 915391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 916391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 917391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt ret = hostapd_check_ht_capab(iface); 918391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret < 0) 9194ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 920391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret == 1) { 921391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); 922391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 0; 923391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 924391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 9254ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt ret = 0; 9264ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtout: 9274ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt return hostapd_setup_interface_complete(iface, ret); 928391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt} 929391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 930391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 93487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 941b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || 947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n || iface->conf->ieee80211ac) && 948f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->channel == 14) { 949f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14"); 950f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; 951f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n = 0; 952f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211ac = 0; 953f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 954f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Hardware does not support configured " 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mode"); 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured mode " 9701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "(%d) (hw_mode in hostapd.conf)", 9711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (int) iface->conf->hw_mode); 97287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -2; 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 975b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt switch (hostapd_check_chans(iface)) { 976b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_VALID: 977b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 978391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ 979391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 1; 980b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 981b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt default: 982b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_notify_bad_chans(iface); 98387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 999a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 1000a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return "IEEE 802.11ad"; 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->chan == chan) 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->freq; 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->freq == freq) 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->chan; 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1041