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" 18ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "common/hw_features_common.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_drv_ops.h" 22391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt#include "acs.h" 237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "ieee802_11.h" 247832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "beacon.h" 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hw_features.h" 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_hw_features) 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hw_features == NULL) 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_hw_features; i++) { 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].channels); 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].rates); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features); 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic char * dfs_info(struct hostapd_channel_data *chan) 47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt static char info[256]; 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt char *state; 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNKNOWN: 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unknown"; 54051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_USABLE: 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "usable"; 57051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNAVAILABLE: 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unavailable"; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_AVAILABLE: 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "available"; 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ""; 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt os_snprintf(info, sizeof(info), " (DFS state = %s)", state); 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt info[sizeof(info) - 1] = '\0'; 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return info; 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */ 73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 782f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt int i, j; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs_enabled = hapd->iconf->ieee80211h && 102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); 103051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 107051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs = 0; 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * to initiate radiation (a.k.a. passive scan and no 1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * IBSS). 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Use radar channels only if the driver supports DFS. 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((feature->channels[j].flag & 116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR) && dfs_enabled) { 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs = 1; 118d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } else if (((feature->channels[j].flag & 119d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt HOSTAPD_CHAN_RADAR) && 120d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt !(iface->drv_flags & 121d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || 122d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt (feature->channels[j].flag & 1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt HOSTAPD_CHAN_NO_IR)) { 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].flag |= 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_DISABLED; 126051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 127051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 130051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 132051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "chan=%d freq=%d MHz max_tx_power=%d dBm%s", 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->mode, 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].chan, 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].freq, 136051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt feature->channels[j].max_tx_power, 137051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs ? dfs_info(&feature->channels[j]) : ""); 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1412f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt return 0; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint hostapd_prepare_rates(struct hostapd_iface *iface, 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode) 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, num_basic_rates = 0; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_a[] = { 60, 120, 240, -1 }; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_b[] = { 10, 20, -1 }; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *basic_rates; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->basic_rates) 1551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt basic_rates = iface->conf->basic_rates; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else switch (mode->mode) { 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_a; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_b; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_g; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; /* No basic rates for 11ad */ 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i = 0; 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (basic_rates[i] >= 0) 1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i++; 1754530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt if (i) 1764530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt i++; /* -1 termination */ 1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->basic_rates); 1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->basic_rates = os_malloc(i * sizeof(int)); 1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->basic_rates) 1801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->current_rates); 1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates = 0; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->current_rates = 18661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!iface->current_rates) { 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "table."); 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < mode->num_rates; i++) { 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_rate_data *rate; 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->supported_rates && 1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt !hostapd_rate_found(iface->conf->supported_rates, 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mode->rates[i])) 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rate = &iface->current_rates[iface->num_rates]; 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->rate = mode->rates[i]; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_rate_found(basic_rates, rate->rate)) { 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->flags |= HOSTAPD_RATE_BASIC; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_basic_rates++; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, rate->rate, rate->flags); 2091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates++; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((iface->num_rates == 0 || num_basic_rates == 0) && 2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "rate sets (%d,%d).", 2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, num_basic_rates); 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 227ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri_chan, sec_chan; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 232ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_chan = iface->conf->channel; 233ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan = pri_chan + iface->conf->secondary_channel * 4; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 235ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return allowed_ht40_channel_pair(iface->current_mode, pri_chan, 236ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan); 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 255ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri_chan, sec_chan; 256ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int res; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 259b36ed7cd946148d829f311de8fe53ea3ffaaffe3Dmitry Shmidt sec_chan = pri_chan + iface->conf->secondary_channel * 4; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 261ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan); 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 263d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (res == 2) { 264d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (iface->conf->no_pri_sec_switch) { 265d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt wpa_printf(MSG_DEBUG, 266d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt "Cannot switch PRI/SEC channels due to local constraint"); 267d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt } else { 268d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 269d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt } 270d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt } 2716dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt 272ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return !!res; 2736dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt} 2746dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt 2756dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 279ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt int pri_chan, sec_chan; 2806dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt 281ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt pri_chan = iface->conf->channel; 282ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan = pri_chan + iface->conf->secondary_channel * 4; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 284ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan, 285ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt sec_chan); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 29604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3127832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->secondary_ch = iface->conf->secondary_channel; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 3207832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) { 3217832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt /* 3227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * TODO: Could consider scheduling another scan to check 3237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * if channel width can be changed if no coex reports 3247832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt * are received from associating stations. 3257832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt */ 3267832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 3307832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (!res) { 3317832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 332b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt res = 1; 3337832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_INFO, "Fallback to 20 MHz"); 3347832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 3357832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 34004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 34104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 34204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 34304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 34404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 34504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 34604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 34704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 35004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 35104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 35304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 3574171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt /* 3584171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt * Note: Need to find the PRI channel also in cases where the affected 3594171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt * channel is the SEC channel of a 40 MHz BSS, so need to include the 3604171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt * scanning coverage here to be 40 MHz from the center frequency. 3614171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt */ 3624171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 40; 3634171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 40; 36404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 36504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 36604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 36704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 36904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 37004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 37104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 37204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 37304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 37404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 37504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 37604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 37704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 37804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 37904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 38004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 38104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 38204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 38304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 385cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, 386cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct wpa_driver_scan_params *params) 387cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 388cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Scan only the affected frequency range */ 389cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int pri_freq; 390cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int affected_start, affected_end; 391cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, pos; 392cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_hw_modes *mode; 393cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 394cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 395cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 396cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 397cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 398cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 399cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 10; 400cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 30; 401cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } else { 402cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start = pri_freq - 30; 403cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_end = pri_freq + 10; 404cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 405cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 406cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt affected_start, affected_end); 407cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 408cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 409cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 410cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (params->freqs == NULL) 411cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return; 412cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt pos = 0; 413cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 414cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 415cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 416cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 417cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 418cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (chan->freq < affected_start || 419cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan->freq > affected_end) 420cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 421cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt params->freqs[pos++] = chan->freq; 422cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 425cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 4267832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtstatic void ap_ht40_scan_retry(void *eloop_data, void *user_data) 4277832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 4287832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#define HT2040_COEX_SCAN_RETRY 15 4297832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct hostapd_iface *iface = eloop_data; 4307832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt struct wpa_driver_scan_params params; 4317832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int ret; 4327832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4337832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 4347832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 4357832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 4367832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt else 4377832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ieee80211n_scan_channels_5g(iface, ¶ms); 4387832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4397832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret = hostapd_driver_scan(iface->bss[0], ¶ms); 4407832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries++; 4417832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_free(params.freqs); 4427832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4437832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == -EBUSY && 4447832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) { 4457832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 4467832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)", 4477832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret), iface->num_ht40_scan_tries); 4487832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); 4497832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 4507832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 4517832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4527832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == 0) { 4537832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 4547832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return; 4557832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 4567832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4577832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_DEBUG, 4587832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan in device, bringing up in HT20 mode"); 4597832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->secondary_channel = 0; 4607832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 4617832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 4627832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 4637832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4647832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4657832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtvoid hostapd_stop_setup_timers(struct hostapd_iface *iface) 4667832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt{ 4677832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); 4687832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt} 4697832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4707832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 4747832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt int ret; 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 476d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt /* Check that HT40 is used and PRI / SEC switch is allowed */ 477d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch) 478d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt return 0; 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 480cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 48404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 48504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 486cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 487cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ieee80211n_scan_channels_5g(iface, ¶ms); 4887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4897832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret = hostapd_driver_scan(iface->bss[0], ¶ms); 4907832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt os_free(params.freqs); 4917832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 4927832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret == -EBUSY) { 4937832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 4947832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again", 4957832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret)); 4967832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt iface->num_ht40_scan_tries = 1; 4977832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); 4987832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); 4997832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt return 1; 5007832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt } 5017832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt 5027832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt if (ret < 0) { 5037832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt wpa_printf(MSG_ERROR, 5047832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt "Failed to request a scan of neighboring BSSes ret=%d (%s)", 5057832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt ret, strerror(-ret)); 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 526dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt /* 527dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * Driver ACS chosen channel may not be HT40 due to internal driver 528dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt * restrictions. 529dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt */ 530dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (conf & HT_CAP_INFO_SMPS_MASK) { 5386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case HT_CAP_INFO_SMPS_STATIC: 5396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) { 5406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_ERROR, 5416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Driver does not support configured HT capability [SMPS-STATIC]"); 5426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 5436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 5456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case HT_CAP_INFO_SMPS_DYNAMIC: 5466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) { 5476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_ERROR, 5486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "Driver does not support configured HT capability [SMPS-DYNAMIC]"); 5496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 5506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 5516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 5526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case HT_CAP_INFO_SMPS_DISABLED: 5536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 5546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 62268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 62368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 62468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 62568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) 62668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 62768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 req_cap = conf & cap; 62868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 62968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 63068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * Make sure we support all requested capabilities. 63168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * NOTE: We assume that 'cap' represents a capability mask, 63268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * not a discrete value. 63368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 63468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if ((hw & req_cap) != req_cap) { 63568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", 63668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt name); 63768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 63868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 63968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 64068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 64168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 64268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 6436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask, 6446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int shift, 64568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt const char *name) 64668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 hw_max = hw & mask; 6486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 conf_val = conf & mask; 64968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 65068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (conf_val > hw_max) { 65168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", 6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt name, conf_val >> shift, hw_max >> shift); 65368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 65468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 65568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 65668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 65768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 65868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 65968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) 66068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{ 6612f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt struct hostapd_hw_modes *mode = iface->current_mode; 6622f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt u32 hw = mode->vht_capab; 66368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt u32 conf = iface->conf->vht_capab; 66468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 66568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", 66668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt hw, conf); 66768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 6682f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt if (mode->mode == HOSTAPD_MODE_IEEE80211G && 6692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt iface->conf->bss[0]->vendor_vht && 6702f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt mode->vht_capab == 0 && iface->hw_features) { 6712f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt int i; 6722f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt 6732f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 6742f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt if (iface->hw_features[i].mode == 6752f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt HOSTAPD_MODE_IEEE80211A) { 6762f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt mode = &iface->hw_features[i]; 6772f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt hw = mode->vht_capab; 6782f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt wpa_printf(MSG_DEBUG, 6792f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt "update hw vht capab based on 5 GHz band: 0x%x", 6802f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt hw); 6812f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt break; 6822f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt } 6832f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt } 6842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt } 6852f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt 68668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK(cap) \ 68768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 68868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ 68968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 69068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 69168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 69268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define VHT_CAP_CHECK_MAX(cap) \ 69368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt do { \ 6946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \ 6956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt #cap)) \ 69668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; \ 69768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } while (0) 69868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 69968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); 70068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); 70168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); 70268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RXLDPC); 70368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); 70468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); 70568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TXSTBC); 70668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); 70768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); 70868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); 70968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); 71068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); 71168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); 71268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); 71368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); 71468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_HTC_VHT); 715a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); 71668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); 71768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); 71868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); 71968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); 72068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 72168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK 72268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#undef VHT_CAP_CHECK_MAX 72368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 72468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 1; 72568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt} 72668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 72768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 737d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 738d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B && 739d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G && 740d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt (iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) { 741d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt wpa_printf(MSG_DEBUG, 742d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt "Disable HT capability [DSSS_CCK-40] on 5 GHz band"); 743d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ; 744d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt } 745d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 74868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#ifdef CONFIG_IEEE80211AC 74968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!ieee80211ac_supported_vht_capab(iface)) 75068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return -1; 75168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif /* CONFIG_IEEE80211AC */ 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 763b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chan(struct hostapd_iface *iface, 764b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int channel, int primary) 765b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 766b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 767b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt struct hostapd_channel_data *chan; 768b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 7697a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt if (!iface->current_mode) 7707a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt return 0; 7717a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt 772b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 773b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan = &iface->current_mode->channels[i]; 774b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (chan->chan != channel) 775b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt continue; 776b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 777b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) 778b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 779b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 780b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt wpa_printf(MSG_DEBUG, 7816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s", 782b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt primary ? "" : "Configured HT40 secondary ", 783b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt i, chan->chan, chan->flag, 7846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", 785b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); 786b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 787b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 788b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 789b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 790b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 791b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 792b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chans(struct hostapd_iface *iface) 793b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 794b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) 795b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 796b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 797b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!iface->conf->secondary_channel) 798b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 799b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 800b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return hostapd_is_usable_chan(iface, iface->conf->channel + 801b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->secondary_channel * 4, 0); 802b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 803b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 804b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 805b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic enum hostapd_chan_status 806b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidthostapd_check_chans(struct hostapd_iface *iface) 807b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 808b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (iface->conf->channel) { 809b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (hostapd_is_usable_chans(iface)) 810b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_VALID; 811b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt else 812b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 813b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 814b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 815b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt /* 816391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * The user set channel=0 or channel=acs_survey 817391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * which is used to trigger ACS. 818b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt */ 819391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 820391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (acs_init(iface)) { 821391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 822391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_ACS; 823391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 824391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 825391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 826391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 827391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 828b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 829b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 830b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 831b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface) 832b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 8337a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt if (!iface->current_mode) { 8347a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 8357a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 8367a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt "Hardware does not support configured mode"); 8377a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt return; 8387a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt } 839b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 840b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 841b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 842b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Configured channel (%d) not found from the " 843b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "channel list of current mode (%d) %s", 844b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->channel, 845b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->current_mode->mode, 846b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 847b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 848b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 849b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Hardware does not support configured channel"); 850b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 851b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 852b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 8534ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtint hostapd_acs_completed(struct hostapd_iface *iface, int err) 854391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt{ 8554ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt int ret = -1; 8564ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt 8574ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt if (err) 8584ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 859391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 860391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (hostapd_check_chans(iface)) { 861391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 862cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, 863cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ACS_EVENT_COMPLETED "freq=%d channel=%d", 864cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_hw_get_freq(iface->bss[0], 865cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel), 866cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel); 867391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 868391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 869391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); 870cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 871391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 8724ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 873391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 874391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 875391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS picked unusable channels"); 876cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); 877391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 8784ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 879391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 880391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 881391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt ret = hostapd_check_ht_capab(iface); 882391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret < 0) 8834ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 884391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret == 1) { 885391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); 886391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 0; 887391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 888391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 8894ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt ret = 0; 8904ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtout: 8914ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt return hostapd_setup_interface_complete(iface, ret); 892391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt} 893391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 894391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 89887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 905b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 910f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || 911f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n || iface->conf->ieee80211ac) && 912f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->channel == 14) { 913f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14"); 914f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; 915f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211n = 0; 916f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt iface->conf->ieee80211ac = 0; 917f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 918f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 929b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || 930b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) 931b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt { 932b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt wpa_printf(MSG_ERROR, 933b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt "Hardware does not support configured mode"); 934b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt hostapd_logger(iface->bss[0], NULL, 935b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt HOSTAPD_MODULE_IEEE80211, 936b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt HOSTAPD_LEVEL_WARNING, 937b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)", 938b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt (int) iface->conf->hw_mode); 939b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt return -2; 940b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt } 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 943b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt switch (hostapd_check_chans(iface)) { 944b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_VALID: 945b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 946391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ 947391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 1; 948b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 949b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt default: 950b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_notify_bad_chans(iface); 95187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 965a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 966a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return "IEEE 802.11ad"; 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 975ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return hw_get_freq(hapd->iface->current_mode, chan); 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 981ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt return hw_get_chan(hapd->iface->current_mode, freq); 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 983