hw_features.c revision 7832adbbd72a1b784b7fb74a71a5d4085b0cb0d3
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" 227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "ieee802_11.h" 237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "beacon.h" 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hw_features.h" 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_hw_features) 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hw_features == NULL) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_hw_features; i++) { 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].channels); 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].rates); 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features); 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic char * dfs_info(struct hostapd_channel_data *chan) 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt static char info[256]; 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt char *state; 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNKNOWN: 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unknown"; 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 54051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_USABLE: 55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "usable"; 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 57051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNAVAILABLE: 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unavailable"; 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_AVAILABLE: 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "available"; 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ""; 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt os_snprintf(info, sizeof(info), " (DFS state = %s)", state); 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt info[sizeof(info) - 1] = '\0'; 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return info; 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */ 72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0, i, j; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs_enabled = hapd->iconf->ieee80211h && 101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); 102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs = 0; 107051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * IBSS operation or active scanning. 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Use radar channels only if the driver supports DFS. 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((feature->channels[j].flag & 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR) && dfs_enabled) { 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs = 1; 116d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } else if (((feature->channels[j].flag & 117d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt HOSTAPD_CHAN_RADAR) && 118d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt !(iface->drv_flags & 119d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || 120d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt (feature->channels[j].flag & 121d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt (HOSTAPD_CHAN_NO_IBSS | 122d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN))) { 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].flag |= 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_DISABLED; 125051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 126051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 129051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 131051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "chan=%d freq=%d MHz max_tx_power=%d dBm%s", 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->mode, 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].chan, 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].freq, 135051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt feature->channels[j].max_tx_power, 136051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs ? dfs_info(&feature->channels[j]) : ""); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint hostapd_prepare_rates(struct hostapd_iface *iface, 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode) 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, num_basic_rates = 0; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_a[] = { 60, 120, 240, -1 }; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_b[] = { 10, 20, -1 }; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *basic_rates; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->basic_rates) 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt basic_rates = iface->conf->basic_rates; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else switch (mode->mode) { 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_a; 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_b; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_g; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; /* No basic rates for 11ad */ 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i = 0; 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (basic_rates[i] >= 0) 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i++; 1744530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt if (i) 1754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt i++; /* -1 termination */ 1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->basic_rates); 1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->basic_rates = os_malloc(i * sizeof(int)); 1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->basic_rates) 1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->current_rates); 1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates = 0; 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->current_rates = 18561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!iface->current_rates) { 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "table."); 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < mode->num_rates; i++) { 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_rate_data *rate; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->supported_rates && 1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt !hostapd_rate_found(iface->conf->supported_rates, 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mode->rates[i])) 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rate = &iface->current_rates[iface->num_rates]; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->rate = mode->rates[i]; 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_rate_found(basic_rates, rate->rate)) { 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->flags |= HOSTAPD_RATE_BASIC; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_basic_rates++; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, rate->rate, rate->flags); 2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates++; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((iface->num_rates == 0 || num_basic_rates == 0) && 2121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "rate sets (%d,%d).", 2151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, num_basic_rates); 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, ok, j, first; 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 184, 192 }; 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t k; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel: %d", 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, sec_chan); 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel */ 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chan->chan == sec_chan) { 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan); 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the list of allowed channels (already checked above). 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = iface->conf->channel; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = sec_chan; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 27268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (k = 0; k < ARRAY_SIZE(allowed); k++) { 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first == allowed[k]) { 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel); 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *pri_chan, int *sec_chan) 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems elems; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = *sec_chan = 0; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems.ht_operation && 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elems.ht_operation_len >= sizeof(*oper)) { 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 313f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt *pri_chan = oper->primary_chan; 314f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = oper->ht_param & 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan + 4; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan - 4; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int bss_pri_chan, bss_sec_chan; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int match; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 335b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt sec_chan = pri_chan + iface->conf->secondary_channel * 4; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel, but not on selected PRI channel. 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss = sec_bss = 0; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss->freq == pri_freq) 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss++; 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (bss->freq == sec_freq) 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_bss++; 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_bss && !pri_bss) { 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and secondary " 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel to get secondary channel with no Beacons " 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from other BSSes"); 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 359b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt return 1; 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Match PRI/SEC channel with any existing HT40 BSS on the same 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channels that we are about to use (if already mixed order in 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * existing BSSes, use own preference). 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 0; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_pri_chan && 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_sec_chan) { 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 1; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!match) { 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &bss_sec_chan); 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_sec_chan && 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_pri_chan) { 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and " 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel due to BSS " 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "overlap with " MACSTR, 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid)); 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_freq, sec_freq; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int affected_start, affected_end; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start, affected_end); 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri = bss->freq; 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = pri; 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, pri_chan; 4197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct ieee802_11_elems elems; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan < pri_chan) 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri - 20; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri + 20; 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((pri < affected_start || pri > affected_end) && 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (sec < affected_start || sec > affected_end)) 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; /* not within affected channel range */ 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d pri=%d sec=%d", 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mismatch with BSS " MACSTR 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri, sec, pri_chan, 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec > pri ? '+' : '-', 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq, sec_freq); 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4517832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 4527832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 0); 4537832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (elems.ht_capabilities && 4547832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt elems.ht_capabilities_len >= 4557832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt sizeof(struct ieee80211_ht_capabilities)) { 4567832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct ieee80211_ht_capabilities *ht_cap = 4577832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt (struct ieee80211_ht_capabilities *) 4587832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt elems.ht_capabilities; 4597832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4607832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (le_to_host16(ht_cap->ht_capabilities_info) & 4617832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt HT_CAP_INFO_40MHZ_INTOLERANT) { 4627832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_DEBUG, 4637832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "40 MHz Intolerant is set on channel %d in BSS " 4647832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt MACSTR, pri, MAC2STR(bss->bssid)); 4657832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 0; 4667832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 4677832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 48104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4977832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->secondary_ch = iface->conf->secondary_channel; 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 5057832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) { 5067832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt /* 5077832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * TODO: Could consider scheduling another scan to check 5087832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * if channel width can be changed if no coex reports 5097832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * are received from associating stations. 5107832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt */ 5117832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 5157832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (!res) { 5167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 5177832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_INFO, "Fallback to 20 MHz"); 5187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 5197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 53404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 53504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 53704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 53804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 53904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 54004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 54104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 54204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 54304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 54404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 54504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 54604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 54761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 54804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 54904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 55004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 55104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 55304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 55404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 55504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 55604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 55704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 55804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 55904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 56004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 56104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 56204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 56304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, 565cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct wpa_driver_scan_params *params) 566cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 567cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Scan only the affected frequency range */ 568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int pri_freq; 569cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int affected_start, affected_end; 570cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, pos; 571cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_hw_modes *mode; 572cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 573cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 574cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 575cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 576cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 577cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 10; 579cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 30; 580cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } else { 581cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 30; 582cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 10; 583cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 584cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 585cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start, affected_end); 586cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 587cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 588cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 589cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (params->freqs == NULL) 590cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 591cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pos = 0; 592cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 593cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 594cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 595cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 596cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 597cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->freq < affected_start || 598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan->freq > affected_end) 599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 600cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs[pos++] = chan->freq; 601cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 602cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 603cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 604cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 6057832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtstatic void ap_ht40_scan_retry(void *eloop_data, void *user_data) 6067832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 6077832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#define HT2040_COEX_SCAN_RETRY 15 6087832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct hostapd_iface *iface = eloop_data; 6097832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct wpa_driver_scan_params params; 6107832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int ret; 6117832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6127832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 6137832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 6147832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 6157832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt else 6167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee80211n_scan_channels_5g(iface, ¶ms); 6177832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret = hostapd_driver_scan(iface->bss[0], ¶ms); 6197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries++; 6207832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_free(params.freqs); 6217832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == -EBUSY && 6237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) { 6247832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 6257832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)", 6267832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret), iface->num_ht40_scan_tries); 6277832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); 6287832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 6297832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 6307832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6317832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == 0) { 6327832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 6337832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 6347832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 6357832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6367832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_DEBUG, 6377832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan in device, bringing up in HT20 mode"); 6387832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 6397832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 6407832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 6417832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 6427832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6437832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6447832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid hostapd_stop_setup_timers(struct hostapd_iface *iface) 6457832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 6467832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); 6477832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 6487832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6497832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 6537832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int ret; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* HT40 not used */ 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 66204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 66304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 664cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 665cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ieee80211n_scan_channels_5g(iface, ¶ms); 6667832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6677832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret = hostapd_driver_scan(iface->bss[0], ¶ms); 6687832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_free(params.freqs); 6697832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6707832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == -EBUSY) { 6717832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 6727832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again", 6737832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret)); 6747832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries = 1; 6757832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); 6767832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); 6777832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 1; 6787832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 6797832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 6807832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret < 0) { 6817832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 6827832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s)", 6837832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret)); 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SMPS-*]"); 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 78368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 78468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 78568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 78668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) 78768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 78868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 req_cap = conf & cap; 78968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 79068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 79168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * Make sure we support all requested capabilities. 79268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * NOTE: We assume that 'cap' represents a capability mask, 79368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * not a discrete value. 79468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 79568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if ((hw & req_cap) != req_cap) { 79668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", 79768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt name); 79868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 79968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 80068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 80168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 80268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 80368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 80468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap, 80568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt const char *name) 80668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 80768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 hw_max = hw & cap; 80868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 conf_val = conf & cap; 80968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 81068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (conf_val > hw_max) { 81168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int offset = find_first_bit(cap); 81268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", 81368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt name, conf_val >> offset, hw_max >> offset); 81468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 81568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 81668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 81768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 81868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 81968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 82068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) 82168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 82268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 hw = iface->current_mode->vht_capab; 82368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 conf = iface->conf->vht_capab; 82468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 82568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", 82668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt hw, conf); 82768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 82868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK(cap) \ 82968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 83068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ 83168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 83268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 83368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 83468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK_MAX(cap) \ 83568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 83668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \ 83768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 83868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 83968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 84068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); 84168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); 84268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); 84368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RXLDPC); 84468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); 84568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); 84668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TXSTBC); 84768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); 84868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); 84968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); 85068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); 85168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); 85268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); 85368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); 85468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); 85568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_HTC_VHT); 856a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); 85768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); 85868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); 85968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); 86068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); 86168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 86268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK 86368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK_MAX 86468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 86568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 86668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 86768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 86868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 88068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 88168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_supported_vht_capab(iface)) 88268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return -1; 88368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 895b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chan(struct hostapd_iface *iface, 896b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int channel, int primary) 897b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 898b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 899b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt struct hostapd_channel_data *chan; 900b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 901b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 902b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan = &iface->current_mode->channels[i]; 903b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (chan->chan != channel) 904b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt continue; 905b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 906b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) 907b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 908b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 909b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt wpa_printf(MSG_DEBUG, 910b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s", 911b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt primary ? "" : "Configured HT40 secondary ", 912b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt i, chan->chan, chan->flag, 913b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "", 914b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ? 915b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt " PASSIVE-SCAN" : "", 916b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); 917b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 918b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 919b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 920b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 921b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 922b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 923b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chans(struct hostapd_iface *iface) 924b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 925b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) 926b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 927b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 928b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!iface->conf->secondary_channel) 929b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 930b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 931b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return hostapd_is_usable_chan(iface, iface->conf->channel + 932b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->secondary_channel * 4, 0); 933b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 934b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 935b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 936b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic enum hostapd_chan_status 937b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidthostapd_check_chans(struct hostapd_iface *iface) 938b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 939b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (iface->conf->channel) { 940b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (hostapd_is_usable_chans(iface)) 941b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_VALID; 942b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt else 943b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 944b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 945b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 946b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt /* 947391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * The user set channel=0 or channel=acs_survey 948391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * which is used to trigger ACS. 949b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt */ 950391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 951391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (acs_init(iface)) { 952391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 953391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_ACS; 954391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 955391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 956391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 957391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 958391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 959b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 960b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 961b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 962b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface) 963b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 964b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 965b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 966b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 967b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Configured channel (%d) not found from the " 968b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "channel list of current mode (%d) %s", 969b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->channel, 970b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->current_mode->mode, 971b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 972b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 973b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 974b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Hardware does not support configured channel"); 975b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 976b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 977b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 9784ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtint hostapd_acs_completed(struct hostapd_iface *iface, int err) 979391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt{ 9804ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt int ret = -1; 9814ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt 9824ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt if (err) 9834ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 984391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 985391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (hostapd_check_chans(iface)) { 986391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 987cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, 988cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ACS_EVENT_COMPLETED "freq=%d channel=%d", 989cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_hw_get_freq(iface->bss[0], 990cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel), 991cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel); 992391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 993391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 994391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); 995cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 996391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 9974ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 998391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 999391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 1000391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS picked unusable channels"); 1001cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 1002391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 10034ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 1004391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 1005391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 1006391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt ret = hostapd_check_ht_capab(iface); 1007391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret < 0) 10084ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 1009391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret == 1) { 1010391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); 1011391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 0; 1012391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 1013391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 10144ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt ret = 0; 10154ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtout: 10164ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt return hostapd_setup_interface_complete(iface, ret); 1017391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt} 1018391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 1019391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 102387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1030b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1035f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || 1036f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n || iface->conf->ieee80211ac) && 1037f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->channel == 14) { 1038f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14"); 1039f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; 1040f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n = 0; 1041f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211ac = 0; 1042f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1043f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Hardware does not support configured " 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mode"); 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured mode " 10591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "(%d) (hw_mode in hostapd.conf)", 10601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (int) iface->conf->hw_mode); 106187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -2; 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1064b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt switch (hostapd_check_chans(iface)) { 1065b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_VALID: 1066b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 1067391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ 1068391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 1; 1069b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 1070b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt default: 1071b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_notify_bad_chans(iface); 107287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 1086a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 1087a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return "IEEE 802.11ad"; 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->chan == chan) 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->freq; 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->freq == freq) 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->chan; 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1128