hw_features.c revision 4ce9c87407c036fc83eb5a6044ddf976c86f53fc
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 * 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details. 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "drivers/driver.h" 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h" 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h" 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_drv_ops.h" 27391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt#include "acs.h" 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hw_features.h" 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_hw_features) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hw_features == NULL) 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_hw_features; i++) { 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].channels); 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].rates); 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features); 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic char * dfs_info(struct hostapd_channel_data *chan) 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt static char info[256]; 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt char *state; 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 54051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { 55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNKNOWN: 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unknown"; 57051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_USABLE: 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "usable"; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_UNAVAILABLE: 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "unavailable"; 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case HOSTAPD_CHAN_DFS_AVAILABLE: 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt state = "available"; 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ""; 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt os_snprintf(info, sizeof(info), " (DFS state = %s)", state); 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt info[sizeof(info) - 1] = '\0'; 72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return info; 74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */ 76051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 77051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0, i, j; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs_enabled = hapd->iconf->ieee80211h && 105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int dfs = 0; 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * IBSS operation or active scanning. 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Use radar channels only if the driver supports DFS. 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((feature->channels[j].flag & 118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR) && dfs_enabled) { 119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs = 1; 120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } else if (feature->channels[j].flag & 121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt (HOSTAPD_CHAN_NO_IBSS | 122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN | 123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_RADAR)) { 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 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 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{ 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, ok, j, first; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 184, 192 }; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t k; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel: %d", 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, sec_chan); 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel */ 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chan->chan == sec_chan) { 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan); 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the list of allowed channels (already checked above). 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = iface->conf->channel; 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = sec_chan; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) { 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first == allowed[k]) { 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *pri_chan, int *sec_chan) 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems elems; 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = *sec_chan = 0; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems.ht_operation && 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elems.ht_operation_len >= sizeof(*oper)) { 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = oper->control_chan; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = oper->ht_param & 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan + 4; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan - 4; 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int bss_pri_chan, bss_sec_chan; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int match; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->secondary_channel * 4; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel, but not on selected PRI channel. 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss = sec_bss = 0; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss->freq == pri_freq) 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss++; 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (bss->freq == sec_freq) 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_bss++; 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_bss && !pri_bss) { 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and secondary " 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel to get secondary channel with no Beacons " 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from other BSSes"); 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 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; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan < pri_chan) 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri - 20; 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri + 20; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((pri < affected_start || pri > affected_end) && 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (sec < affected_start || sec > affected_end)) 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; /* not within affected channel range */ 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d pri=%d sec=%d", 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mismatch with BSS " MACSTR 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri, sec, pri_chan, 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec > pri ? '+' : '-', 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq, sec_freq); 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: 40 MHz intolerant */ 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 46404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 49404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 49504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 49604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 49704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 49804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 49904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 50004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 50104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 50204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 50304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 50404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 50504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 50604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 50704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 50804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 50904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 51004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 51104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 51304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 51404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 51504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 51604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 51761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 51804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 51904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 52004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 52104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 52204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 52304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 52404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 52504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 52604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 52704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 52804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 52904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 53004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 53104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 53204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 53304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* HT40 not used */ 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 54404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 54504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to request a scan of " 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "neighboring BSSes"); 54904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 55204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SMPS-*]"); 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [PSMP]"); 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chan(struct hostapd_iface *iface, 679b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int channel, int primary) 680b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 681b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 682b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt struct hostapd_channel_data *chan; 683b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 684b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 685b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan = &iface->current_mode->channels[i]; 686b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (chan->chan != channel) 687b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt continue; 688b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 689b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) 690b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 691b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 692b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt wpa_printf(MSG_DEBUG, 693b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s", 694b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt primary ? "" : "Configured HT40 secondary ", 695b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt i, chan->chan, chan->flag, 696b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "", 697b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ? 698b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt " PASSIVE-SCAN" : "", 699b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); 700b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 701b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 702b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 703b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 704b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 705b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 706b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chans(struct hostapd_iface *iface) 707b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 708b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) 709b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 710b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 711b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!iface->conf->secondary_channel) 712b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 713b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 714b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return hostapd_is_usable_chan(iface, iface->conf->channel + 715b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->secondary_channel * 4, 0); 716b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 717b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 718b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 719b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic enum hostapd_chan_status 720b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidthostapd_check_chans(struct hostapd_iface *iface) 721b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 722b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (iface->conf->channel) { 723b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (hostapd_is_usable_chans(iface)) 724b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_VALID; 725b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt else 726b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 727b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 728b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 729b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt /* 730391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * The user set channel=0 or channel=acs_survey 731391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * which is used to trigger ACS. 732b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt */ 733391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 734391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (acs_init(iface)) { 735391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 736391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_ACS; 737391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 738391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 739391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 740391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 741391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 742b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 743b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 744b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 745b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface) 746b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 747b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 748b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 749b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 750b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Configured channel (%d) not found from the " 751b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "channel list of current mode (%d) %s", 752b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->channel, 753b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->current_mode->mode, 754b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 755b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 756b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 757b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Hardware does not support configured channel"); 758b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 759b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 760b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 7614ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtint hostapd_acs_completed(struct hostapd_iface *iface, int err) 762391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt{ 7634ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt int ret = -1; 7644ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt 7654ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt if (err) 7664ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 767391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 768391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (hostapd_check_chans(iface)) { 769391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 770391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 771391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 772391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); 773391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 7744ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 775391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 776391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 777391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS picked unusable channels"); 778391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 7794ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 780391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 781391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 782391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt ret = hostapd_check_ht_capab(iface); 783391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret < 0) 7844ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt goto out; 785391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret == 1) { 786391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); 787391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 0; 788391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 789391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 7904ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt ret = 0; 7914ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidtout: 7924ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt return hostapd_setup_interface_complete(iface, ret); 793391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt} 794391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 795391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 79987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 806b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Hardware does not support configured " 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mode"); 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured mode " 8261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "(%d) (hw_mode in hostapd.conf)", 8271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (int) iface->conf->hw_mode); 82887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -2; 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 831b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt switch (hostapd_check_chans(iface)) { 832b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_VALID: 833b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 834391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ 835391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 1; 836b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 837b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt default: 838b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_notify_bad_chans(iface); 83987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 855a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 856a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return "IEEE 802.11ad"; 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->chan == chan) 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->freq; 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->freq == freq) 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->chan; 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 897