hw_features.c revision 4530cfd4d14a77c58e35393b91e40f8dd9d62697
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" 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hw_features.h" 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_hw_features) 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hw_features == NULL) 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_hw_features; i++) { 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].channels); 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features[i].rates); 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(hw_features); 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_get_hw_features(struct hostapd_iface *iface) 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0, i, j; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 num_modes, flags; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *modes; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_drv_none(hapd)) 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (modes == NULL) { 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_DEBUG, 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Fetching hardware channel/rate support not " 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "supported."); 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_flags = flags; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->hw_features = modes; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_hw_features = num_modes; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < num_modes; i++) { 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *feature = &modes[i]; 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* set flag for channels we can use in current regulatory 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * domain */ 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < feature->num_channels; j++) { 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Disable all channels that are marked not to allow 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IBSS operation or active scanning. In addition, 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * disable all channels that require radar detection, 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * since that (in addition to full DFS) is not yet 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * supported. 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (HOSTAPD_CHAN_NO_IBSS | 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN | 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_RADAR)) 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].flag |= 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_CHAN_DISABLED; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "chan=%d freq=%d MHz max_tx_power=%d dBm", 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->mode, 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].chan, 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].freq, 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt feature->channels[j].max_tx_power); 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint hostapd_prepare_rates(struct hostapd_iface *iface, 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode) 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, num_basic_rates = 0; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_a[] = { 60, 120, 240, -1 }; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_b[] = { 10, 20, -1 }; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int basic_rates_g[] = { 10, 20, 55, 110, -1 }; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *basic_rates; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->basic_rates) 1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt basic_rates = iface->conf->basic_rates; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else switch (mode->mode) { 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_a; 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_b; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt basic_rates = basic_rates_g; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i = 0; 1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (basic_rates[i] >= 0) 1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt i++; 1324530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt if (i) 1334530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt i++; /* -1 termination */ 1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->basic_rates); 1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->basic_rates = os_malloc(i * sizeof(int)); 1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->basic_rates) 1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt os_free(iface->current_rates); 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates = 0; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->current_rates = 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (!iface->current_rates) { 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "table."); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < mode->num_rates; i++) { 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_rate_data *rate; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (iface->conf->supported_rates && 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt !hostapd_rate_found(iface->conf->supported_rates, 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mode->rates[i])) 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rate = &iface->current_rates[iface->num_rates]; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->rate = mode->rates[i]; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_rate_found(basic_rates, rate->rate)) { 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rate->flags |= HOSTAPD_RATE_BASIC; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_basic_rates++; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", 1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, rate->rate, rate->flags); 1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates++; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if ((iface->num_rates == 0 || num_basic_rates == 0) && 1701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (!iface->conf->ieee80211n || !iface->conf->require_ht)) { 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "rate sets (%d,%d).", 1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt iface->num_rates, num_basic_rates); 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, ok, j, first; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 184, 192 }; 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t k; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* HT40 not used */ 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "HT40: control channel: %d " 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel: %d", 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, sec_chan); 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Verify that HT40 secondary channel is an allowed 20 MHz 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel */ 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chan->chan == sec_chan) { 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan); 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Verify that HT40 primary,secondary channel pair is allowed per 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IEEE 802.11n Annex J. This is only needed for 5 GHz band since 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 2.4 GHz rules allow all cases where the secondary channel fits into 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the list of allowed channels (already checked above). 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = iface->conf->channel; 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt first = sec_chan; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) { 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (first == allowed[k]) { 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 1; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ok) { 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel); 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) { 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel += 4; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = -1; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel -= 4; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 1; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int *pri_chan, int *sec_chan) 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee80211_ht_operation *oper; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems elems; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = *sec_chan = 0; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems.ht_operation && 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elems.ht_operation_len >= sizeof(*oper)) { 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper = (struct ieee80211_ht_operation *) elems.ht_operation; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pri_chan = oper->control_chan; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = oper->ht_param & 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan + 4; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *sec_chan = *pri_chan - 4; 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int bss_pri_chan, bss_sec_chan; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int match; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_chan = iface->conf->channel; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan = iface->conf->secondary_channel * 4; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Switch PRI/SEC channels if Beacons were detected on selected SEC 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channel, but not on selected PRI channel. 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss = sec_bss = 0; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bss->freq == pri_freq) 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_bss++; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (bss->freq == sec_freq) 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_bss++; 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_bss && !pri_bss) { 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and secondary " 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel to get secondary channel with no Beacons " 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from other BSSes"); 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Match PRI/SEC channel with any existing HT40 BSS on the same 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * channels that we are about to use (if already mixed order in 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * existing BSSes, use own preference). 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 0; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_pri_chan && 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_sec_chan) { 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match = 1; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!match) { 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &bss_sec_chan); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_chan == bss_sec_chan && 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan == bss_pri_chan) { 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "Switch own primary and " 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "secondary channel due to BSS " 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "overlap with " MACSTR, 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid)); 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_switch_pri_sec(iface); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res) 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri_freq, sec_freq; 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int affected_start, affected_end; 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->secondary_channel > 0) 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq + 20; 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_freq = pri_freq - 20; 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt affected_start, affected_end); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_res *bss = scan_res->res[i]; 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pri = bss->freq; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec = pri; 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan, pri_chan; 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan < pri_chan) 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri - 20; 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec = pri + 20; 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((pri < affected_start || pri > affected_end) && 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (sec < affected_start || sec > affected_end)) 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; /* not within affected channel range */ 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " freq=%d pri=%d sec=%d", 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sec_chan) { 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pri_freq != pri || sec_freq != sec) { 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz pri/sec " 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mismatch with BSS " MACSTR 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " <%d,%d> (chan=%d%c) vs. <%d,%d>", 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(bss->bssid), 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri, sec, pri_chan, 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec > pri ? '+' : '-', 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pri_freq, sec_freq); 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: 40 MHz intolerant */ 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ieee80211n_check_scan(struct hostapd_iface *iface) 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_scan_results *scan_res; 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oper40; 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is 42104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = NULL; 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt scan_res = hostapd_driver_get_scan_results(iface->bss[0]); 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (scan_res == NULL) { 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, 1); 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_scan_results_free(scan_res); 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!oper40) { 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel pri=%d sec=%d based on overlapping BSSes", 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel + 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4); 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel = 0; 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ieee80211n_allowed_ht40_channel_pair(iface); 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_setup_interface_complete(iface, !res); 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 45204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, 45304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpa_driver_scan_params *params) 45404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 45504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Scan only the affected frequency range */ 45604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int pri_freq, sec_freq; 45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int affected_start, affected_end; 45804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int i, pos; 45904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_hw_modes *mode; 46004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode == NULL) 46204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 46304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 46404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); 46504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->conf->secondary_channel > 0) 46604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq + 20; 46704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt else 46804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sec_freq = pri_freq - 20; 46904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start = (pri_freq + sec_freq) / 2 - 25; 47004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_end = (pri_freq + sec_freq) / 2 + 25; 47104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", 47204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt affected_start, affected_end); 47304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 47404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt mode = iface->current_mode; 47561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); 47604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (params->freqs == NULL) 47704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 47804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt pos = 0; 47904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 48004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 48104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[i]; 48204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 48304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 48404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (chan->freq < affected_start || 48504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt chan->freq > affected_end) 48604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt continue; 48704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt params->freqs[pos++] = chan->freq; 48804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 48904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 49004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 49104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface) 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpa_driver_scan_params params; 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->secondary_channel) 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; /* HT40 not used */ 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "40 MHz channel"); 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(¶ms, 0, sizeof(params)); 50204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 50304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ieee80211n_scan_channels_2g4(iface, ¶ms); 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Failed to request a scan of " 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "neighboring BSSes"); 50704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 51004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(params.freqs); 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->scan_cb = ieee80211n_check_scan; 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 hw = iface->current_mode->ht_capab; 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 conf = iface->conf->ht_capab; 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LDPC]"); 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [HT40*]"); 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SMPS-*]"); 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_GREEN_FIELD) && 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_GREEN_FIELD)) { 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [GF]"); 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-20]"); 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [SHORT-GI-40]"); 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [TX-STBC]"); 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_RX_STBC_MASK) > 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hw & HT_CAP_INFO_RX_STBC_MASK)) { 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [RX-STBC*]"); 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DELAYED_BA) && 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DELAYED_BA)) { 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DELAYED-BA]"); 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [MAX-AMSDU-7935]"); 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [DSSS_CCK-40]"); 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [PSMP]"); 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Driver does not support configured " 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "HT capability [LSIG-TXOP-PROT]"); 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_check_ht_capab(struct hostapd_iface *iface) 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->conf->ieee80211n) 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_supported_ht_capab(iface)) 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ieee80211n_check_40mhz(iface); 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ieee80211n_allowed_ht40_channel_pair(iface)) 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_select_hw_mode - Select the hardware mode 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @iface: Pointer to interface data. 63987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen * Returns: 0 on success, < 0 on failure 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sets up the hardware mode, channel, rates, and passive scanning 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * based on the configuration. 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_select_hw_mode(struct hostapd_iface *iface) 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i, j, ok; 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_hw_features < 1) 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < iface->num_hw_features; i++) { 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_hw_modes *mode = &iface->hw_features[i]; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mode->mode == iface->conf->hw_mode) { 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = mode; 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Hardware does not support configured " 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "mode"); 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured mode " 6661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "(%d) (hw_mode in hostapd.conf)", 6671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt (int) iface->conf->hw_mode); 66887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -2; 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 67587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen if (chan->chan == iface->conf->channel) { 67687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen if (chan->flag & HOSTAPD_CHAN_DISABLED) { 67787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen wpa_printf(MSG_ERROR, 67887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen "channel [%i] (%i) is disabled for " 6791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt "use in AP mode, flags: 0x%x%s%s%s", 6801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt j, chan->chan, chan->flag, 6811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt chan->flag & HOSTAPD_CHAN_NO_IBSS ? 6821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " NO-IBSS" : "", 6831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt chan->flag & 6841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt HOSTAPD_CHAN_PASSIVE_SCAN ? 6851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " PASSIVE-SCAN" : "", 6861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt chan->flag & HOSTAPD_CHAN_RADAR ? 6871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt " RADAR" : ""); 68887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen } else { 68987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen ok = 1; 69087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen break; 69187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen } 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ok && iface->conf->secondary_channel) { 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_ok = 0; 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sec_chan = iface->conf->channel + 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->secondary_channel * 4; 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (j = 0; j < iface->current_mode->num_channels; j++) { 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *chan = 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &iface->current_mode->channels[j]; 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (chan->chan == sec_chan)) { 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_ok = 1; 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!sec_ok) { 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Configured HT40 secondary channel " 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%d) not found from the channel list " 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "of current mode (%d) %s", 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sec_chan, iface->current_mode->mode, 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_hw_mode_txt( 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode->mode)); 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ok = 0; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->channel == 0) { 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: could request a scan of neighboring BSSes and select 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the channel automatically */ 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "Channel not configured " 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(hw_mode/channel in hostapd.conf)"); 72587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -3; 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ok == 0 && iface->conf->channel != 0) { 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_MODULE_IEEE80211, 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Configured channel (%d) not found from the " 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "channel list of current mode (%d) %s", 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel, 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode->mode, 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_hw_mode_txt(iface->current_mode->mode)); 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->current_mode = NULL; 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode == NULL) { 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HOSTAPD_LEVEL_WARNING, 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Hardware does not support configured channel"); 74387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen return -4; 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * hostapd_hw_mode_txt(int mode) 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (mode) { 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211A: 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11a"; 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211B: 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11b"; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case HOSTAPD_MODE_IEEE80211G: 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "IEEE 802.11g"; 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "UNKNOWN"; 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->chan == chan) 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->freq; 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!hapd->iface->current_mode) 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_channel_data *ch = 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hapd->iface->current_mode->channels[i]; 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ch->freq == freq) 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ch->chan; 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 799