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 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0, i, j; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IBSS operation or active scanning. In addition, 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * disable all channels that require radar detection, 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * since that (in addition to full DFS) is not yet 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * supported. 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (HOSTAPD_CHAN_NO_IBSS | 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN | 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_RADAR)) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].flag |= 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_DISABLED; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "chan=%d freq=%d MHz max_tx_power=%d dBm", 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->mode, 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].chan, 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].freq, 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].max_tx_power); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint hostapd_prepare_rates(struct hostapd_iface *iface, 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode) 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, num_basic_rates = 0; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_a[] = { 60, 120, 240, -1 }; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_b[] = { 10, 20, -1 }; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *basic_rates; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->basic_rates) 1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt basic_rates = iface->conf->basic_rates; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else switch (mode->mode) { 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_a; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_b; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_g; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 126a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 127a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; /* No basic rates for 11ad */ 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i = 0; 1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (basic_rates[i] >= 0) 1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i++; 1354530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt if (i) 1364530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt i++; /* -1 termination */ 1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->basic_rates); 1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->basic_rates = os_malloc(i * sizeof(int)); 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->basic_rates) 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->current_rates); 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates = 0; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->current_rates = 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!iface->current_rates) { 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "table."); 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < mode->num_rates; i++) { 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_rate_data *rate; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->supported_rates && 1571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt !hostapd_rate_found(iface->conf->supported_rates, 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mode->rates[i])) 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rate = &iface->current_rates[iface->num_rates]; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->rate = mode->rates[i]; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_rate_found(basic_rates, rate->rate)) { 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->flags |= HOSTAPD_RATE_BASIC; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_basic_rates++; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, rate->rate, rate->flags); 1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates++; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((iface->num_rates == 0 || num_basic_rates == 0) && 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "rate sets (%d,%d).", 1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, num_basic_rates); 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, ok, j, first; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 184, 192 }; 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t k; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel: %d", 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, sec_chan); 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel */ 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chan->chan == sec_chan) { 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan); 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the list of allowed channels (already checked above). 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = iface->conf->channel; 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = sec_chan; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) { 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first == allowed[k]) { 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel); 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *pri_chan, int *sec_chan) 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems elems; 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = *sec_chan = 0; 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems.ht_operation && 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elems.ht_operation_len >= sizeof(*oper)) { 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = oper->control_chan; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = oper->ht_param & 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan + 4; 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan - 4; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int bss_pri_chan, bss_sec_chan; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int match; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->secondary_channel * 4; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel, but not on selected PRI channel. 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss = sec_bss = 0; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss->freq == pri_freq) 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss++; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (bss->freq == sec_freq) 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_bss++; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_bss && !pri_bss) { 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and secondary " 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel to get secondary channel with no Beacons " 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from other BSSes"); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Match PRI/SEC channel with any existing HT40 BSS on the same 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channels that we are about to use (if already mixed order in 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * existing BSSes, use own preference). 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 0; 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_pri_chan && 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_sec_chan) { 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 1; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!match) { 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &bss_sec_chan); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_sec_chan && 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_pri_chan) { 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and " 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel due to BSS " 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "overlap with " MACSTR, 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid)); 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_freq, sec_freq; 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int affected_start, affected_end; 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start, affected_end); 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri = bss->freq; 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = pri; 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, pri_chan; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan < pri_chan) 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri - 20; 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri + 20; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((pri < affected_start || pri > affected_end) && 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (sec < affected_start || sec > affected_end)) 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; /* not within affected channel range */ 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d pri=%d sec=%d", 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mismatch with BSS " MACSTR 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri, sec, pri_chan, 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec > pri ? '+' : '-', 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq, sec_freq); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: 40 MHz intolerant */ 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 45404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 45504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 45604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 45904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 46004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 46104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 46204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 46404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 46504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 46704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 46804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 46904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 47004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 47104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 47204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 47304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 47404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 47504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 47604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 47761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 47804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 47904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 48004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 48104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 48204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 48304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 48404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 48504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 48604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 48704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 48804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 48904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 49004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 49104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 49204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 49304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* HT40 not used */ 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 50404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 50504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to request a scan of " 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "neighboring BSSes"); 50904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 51204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SMPS-*]"); 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [PSMP]"); 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chan(struct hostapd_iface *iface, 639b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int channel, int primary) 640b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 641b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 642b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt struct hostapd_channel_data *chan; 643b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 644b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 645b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan = &iface->current_mode->channels[i]; 646b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (chan->chan != channel) 647b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt continue; 648b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 649b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) 650b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 651b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 652b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt wpa_printf(MSG_DEBUG, 653b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s", 654b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt primary ? "" : "Configured HT40 secondary ", 655b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt i, chan->chan, chan->flag, 656b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "", 657b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ? 658b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt " PASSIVE-SCAN" : "", 659b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); 660b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 661b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 662b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 663b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 664b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 665b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 666b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int hostapd_is_usable_chans(struct hostapd_iface *iface) 667b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 668b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) 669b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 670b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 671b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!iface->conf->secondary_channel) 672b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 1; 673b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 674b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return hostapd_is_usable_chan(iface, iface->conf->channel + 675b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->secondary_channel * 4, 0); 676b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 677b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 678b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 679b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic enum hostapd_chan_status 680b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidthostapd_check_chans(struct hostapd_iface *iface) 681b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 682b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (iface->conf->channel) { 683b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (hostapd_is_usable_chans(iface)) 684b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_VALID; 685b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt else 686b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 687b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } 688b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 689b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt /* 690391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * The user set channel=0 or channel=acs_survey 691391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt * which is used to trigger ACS. 692b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt */ 693391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 694391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (acs_init(iface)) { 695391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 696391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_ACS; 697391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 698391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 699391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 700391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return HOSTAPD_CHAN_INVALID; 701391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 702b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 703b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 704b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 705b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface) 706b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{ 707b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 708b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 709b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 710b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Configured channel (%d) not found from the " 711b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "channel list of current mode (%d) %s", 712b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->conf->channel, 713b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt iface->current_mode->mode, 714b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 715b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 716b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 717b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt "Hardware does not support configured channel"); 718b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt} 719b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 720b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 721391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidtint hostapd_acs_completed(struct hostapd_iface *iface) 722391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt{ 723391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt int ret; 724391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 725391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt switch (hostapd_check_chans(iface)) { 726391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_VALID: 727391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 728391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: 729391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); 730391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 731391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return -1; 732391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 733391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 734391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_ERROR, "ACS picked unusable channels"); 735391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt hostapd_notify_bad_chans(iface); 736391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return -1; 737391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 738391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 739391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt ret = hostapd_check_ht_capab(iface); 740391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret < 0) 741391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return -1; 742391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt if (ret == 1) { 743391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); 744391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 0; 745391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 746391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 747391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return hostapd_setup_interface_complete(iface, 0); 748391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt} 749391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 750391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 75487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 761b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt int i; 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Hardware does not support configured " 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mode"); 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured mode " 7811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "(%d) (hw_mode in hostapd.conf)", 7821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (int) iface->conf->hw_mode); 78387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -2; 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 786b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt switch (hostapd_check_chans(iface)) { 787b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_VALID: 788b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return 0; 789391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ 790391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return 1; 791b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt case HOSTAPD_CHAN_INVALID: 792b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt default: 793b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt hostapd_notify_bad_chans(iface); 79487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 810a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case HOSTAPD_MODE_IEEE80211AD: 811a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return "IEEE 802.11ad"; 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->chan == chan) 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->freq; 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->freq == freq) 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->chan; 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 852