hw_features.c revision f21452aea786ac056eb01f1cbba4f553bd502747
19085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org/*
29085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * hostapd / Hardware feature query and different modes
39085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * Copyright 2002-2003, Instant802 Networks, Inc.
45ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Copyright 2005-2006, Devicescape Software, Inc.
55ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
65ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
75ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * This software may be distributed under the terms of the BSD license.
89085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org * See README for more details.
99085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org */
109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "utils/includes.h"
129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "utils/common.h"
149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "utils/eloop.h"
159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "common/ieee802_11_defs.h"
169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "common/ieee802_11_common.h"
179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "common/wpa_ctrl.h"
189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "hostapd.h"
199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "ap_config.h"
209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "ap_drv_ops.h"
219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "acs.h"
229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#include "hw_features.h"
239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgvoid hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			      size_t num_hw_features)
279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	size_t i;
299085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (hw_features == NULL)
319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return;
329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
335d6c1f5b20195b800bc6db146920fd6f878d1fd4vegorov@chromium.org	for (i = 0; i < num_hw_features; i++) {
349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		os_free(hw_features[i].channels);
359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		os_free(hw_features[i].rates);
369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	os_free(hw_features);
399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
40c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org
41c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org
4271affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org#ifndef CONFIG_NO_STDOUT_DEBUG
4371affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.orgstatic char * dfs_info(struct hostapd_channel_data *chan)
449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
45e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	static char info[256];
46e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	char *state;
47e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
48e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) {
4940b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org	case HOSTAPD_CHAN_DFS_UNKNOWN:
5040b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org		state = "unknown";
51e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		break;
52e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	case HOSTAPD_CHAN_DFS_USABLE:
53e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		state = "usable";
5440b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org		break;
5540b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org	case HOSTAPD_CHAN_DFS_UNAVAILABLE:
56b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org		state = "unavailable";
57b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org		break;
58b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org	case HOSTAPD_CHAN_DFS_AVAILABLE:
5940b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org		state = "available";
6040b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org		break;
61b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org	default:
62b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org		return "";
63b9d7da12d4486aa0a9d6660de46d977198076e77sgjesse@chromium.org	}
6440b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org	os_snprintf(info, sizeof(info), " (DFS state = %s)", state);
6540b9da37a45dabf86bd82a39e885f2921f47fc08fschneider@chromium.org	info[sizeof(info) - 1] = '\0';
66e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
67e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	return info;
689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org#endif /* CONFIG_NO_STDOUT_DEBUG */
709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgint hostapd_get_hw_features(struct hostapd_iface *iface)
739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	struct hostapd_data *hapd = iface->bss[0];
759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int ret = 0, i, j;
769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	u16 num_modes, flags;
779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	struct hostapd_hw_modes *modes;
789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
799085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (hostapd_drv_none(hapd))
809085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return -1;
819085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
829085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (modes == NULL) {
839085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
849085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			       HOSTAPD_LEVEL_DEBUG,
859085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			       "Fetching hardware channel/rate support not "
869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			       "supported.");
879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return -1;
889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	iface->hw_flags = flags;
91a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
92a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
93a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	iface->hw_features = modes;
94a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	iface->num_hw_features = num_modes;
95a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
96a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	for (i = 0; i < num_modes; i++) {
97a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		struct hostapd_hw_modes *feature = &modes[i];
98a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		int dfs_enabled = hapd->iconf->ieee80211h &&
99a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);
100a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
101c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org		/* set flag for channels we can use in current regulatory
1023a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org		 * domain */
103c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org		for (j = 0; j < feature->num_channels; j++) {
104c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			int dfs = 0;
105c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org
106c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			/*
1073a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org			 * Disable all channels that are marked not to allow
108c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			 * IBSS operation or active scanning.
109c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			 * Use radar channels only if the driver supports DFS.
110c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			 */
111a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			if ((feature->channels[j].flag &
112a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			     HOSTAPD_CHAN_RADAR) && dfs_enabled) {
113a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org				dfs = 1;
114a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			} else if (feature->channels[j].flag &
115a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org				   (HOSTAPD_CHAN_NO_IBSS |
116c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org				    HOSTAPD_CHAN_PASSIVE_SCAN |
117c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org				    HOSTAPD_CHAN_RADAR)) {
118a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org				feature->channels[j].flag |=
119a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org					HOSTAPD_CHAN_DISABLED;
120a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			}
121a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
122c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
123c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org				continue;
124a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
125a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
126a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org				   "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
127a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org				   feature->mode,
128755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				   feature->channels[j].chan,
129eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org				   feature->channels[j].freq,
130755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				   feature->channels[j].max_tx_power,
131755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				   dfs ? dfs_info(&feature->channels[j]) : "");
132a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		}
1334a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org	}
1344a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org
1359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	return ret;
1369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
1379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1384a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org
139eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.orgint hostapd_prepare_rates(struct hostapd_iface *iface,
1409085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			  struct hostapd_hw_modes *mode)
1419085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
1425aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	int i, num_basic_rates = 0;
1435aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	int basic_rates_a[] = { 60, 120, 240, -1 };
1445aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	int basic_rates_b[] = { 10, 20, -1 };
1455aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
1465aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	int *basic_rates;
1475aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
1485aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	if (iface->conf->basic_rates)
1495aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org		basic_rates = iface->conf->basic_rates;
1505aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	else switch (mode->mode) {
1515aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	case HOSTAPD_MODE_IEEE80211A:
1525aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org		basic_rates = basic_rates_a;
1535c838251403b0be9a882540f1922577abba4c872ager@chromium.org		break;
1545c838251403b0be9a882540f1922577abba4c872ager@chromium.org	case HOSTAPD_MODE_IEEE80211B:
1559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		basic_rates = basic_rates_b;
1560ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org		break;
157c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org	case HOSTAPD_MODE_IEEE80211G:
1583a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org		basic_rates = basic_rates_g;
1593a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org		break;
1609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	case HOSTAPD_MODE_IEEE80211AD:
1619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return 0; /* No basic rates for 11ad */
162b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	default:
163b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		return -1;
164b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	}
165b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org
166b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	i = 0;
167b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	while (basic_rates[i] >= 0)
168b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		i++;
169b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	if (i)
170b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		i++; /* -1 termination */
171b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	os_free(iface->basic_rates);
172b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	iface->basic_rates = os_malloc(i * sizeof(int));
173b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	if (iface->basic_rates)
174b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
175b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org
176b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	os_free(iface->current_rates);
177b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	iface->num_rates = 0;
178b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org
1795aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	iface->current_rates =
1805aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org		os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
1819085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (!iface->current_rates) {
182a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
183a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			   "table.");
184a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		return -1;
185a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	}
186a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
187a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	for (i = 0; i < mode->num_rates; i++) {
188a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		struct hostapd_rate_data *rate;
189a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
190c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org		if (iface->conf->supported_rates &&
191c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org		    !hostapd_rate_found(iface->conf->supported_rates,
192c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org					mode->rates[i]))
193c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org			continue;
194c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org
195c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.org		rate = &iface->current_rates[iface->num_rates];
196a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		rate->rate = mode->rates[i];
197a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		if (hostapd_rate_found(basic_rates, rate->rate)) {
198a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			rate->flags |= HOSTAPD_RATE_BASIC;
199a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			num_basic_rates++;
200a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		}
201a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
202a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			   iface->num_rates, rate->rate, rate->flags);
203a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		iface->num_rates++;
204a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	}
205a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
206a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
207a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
208a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
209a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			   "rate sets (%d,%d).",
210a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org			   iface->num_rates, num_basic_rates);
211a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		return -1;
212a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	}
213a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
214a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	return 0;
215a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org}
216a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
217a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
218a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#ifdef CONFIG_IEEE80211N
219c6c5718277d4047fad1e034396228ce15571b5a4sgjesse@chromium.orgstatic int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
2204a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org{
2219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int sec_chan, ok, j, first;
2229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
2239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			  184, 192 };
2249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	size_t k;
22586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org
22686f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	if (!iface->conf->secondary_channel)
22786f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org		return 1; /* HT40 not used */
22886f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org
22986f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
23086f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
23186f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org		   "secondary channel: %d",
23286f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org		   iface->conf->channel, sec_chan);
23386f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org
23486f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	/* Verify that HT40 secondary channel is an allowed 20 MHz
23586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	 * channel */
2369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	ok = 0;
2379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (j = 0; j < iface->current_mode->num_channels; j++) {
2389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		struct hostapd_channel_data *chan =
239b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org			&iface->current_mode->channels[j];
240b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
241b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		    chan->chan == sec_chan) {
242b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org			ok = 1;
243b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org			break;
244b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		}
245b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	}
246b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	if (!ok) {
247b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
248b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org			   sec_chan);
249b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org		return 0;
250b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	}
251b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org
252b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	/*
253b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	 * Verify that HT40 primary,secondary channel pair is allowed per
254b95b98b0c30bcd40b657aa45f6cd75a46a4772adfschneider@chromium.org	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
2559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * 2.4 GHz rules allow all cases where the secondary channel fits into
256a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	 * the list of allowed channels (already checked above).
257a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	 */
258a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
259a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org		return 1;
2609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->conf->secondary_channel > 0)
2629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		first = iface->conf->channel;
2639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	else
2649085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		first = sec_chan;
2659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	ok = 0;
2679085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (k = 0; k < ARRAY_SIZE(allowed); k++) {
2689085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if (first == allowed[k]) {
2699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			ok = 1;
2709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			break;
2719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		}
2729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
2739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (!ok) {
2749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
2759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   iface->conf->channel,
2769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   iface->conf->secondary_channel);
2779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return 0;
2789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
2799085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2809085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	return 1;
2819d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com}
2829d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
2839d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
2849d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.comstatic void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
2859085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
2869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->conf->secondary_channel > 0) {
2879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		iface->conf->channel += 4;
2889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		iface->conf->secondary_channel = -1;
2899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	} else {
2909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		iface->conf->channel -= 4;
2919d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com		iface->conf->secondary_channel = 1;
2929d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	}
2939085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
2949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2959085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2969085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgstatic void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
2979085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org					int *pri_chan, int *sec_chan)
2989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
2999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	struct ieee80211_ht_operation *oper;
3005ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org	struct ieee802_11_elems elems;
3015ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org
3025ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org	*pri_chan = *sec_chan = 0;
3035ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org
3049085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
3059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (elems.ht_operation &&
3069085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	    elems.ht_operation_len >= sizeof(*oper)) {
3079085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
3089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		*pri_chan = oper->control_chan;
3099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
3109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			int sec = oper->ht_param &
3119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
3129085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
3139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				*sec_chan = *pri_chan + 4;
3149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
3159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				*sec_chan = *pri_chan - 4;
3169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		}
3179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
3189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
3199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgstatic int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
3229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				     struct wpa_scan_results *scan_res)
3239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
3249085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
3259085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int bss_pri_chan, bss_sec_chan;
3269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	size_t i;
3279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int match;
3289085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3295ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org	pri_chan = iface->conf->channel;
3309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	sec_chan = iface->conf->secondary_channel * 4;
3319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
3329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->conf->secondary_channel > 0)
3339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		sec_freq = pri_freq + 20;
3349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	else
3359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		sec_freq = pri_freq - 20;
3369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	/*
3389085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
3399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * channel, but not on selected PRI channel.
3409085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 */
3419085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	pri_bss = sec_bss = 0;
3429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (i = 0; i < scan_res->num; i++) {
3439085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		struct wpa_scan_res *bss = scan_res->res[i];
3449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if (bss->freq == pri_freq)
3459085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			pri_bss++;
3469085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		else if (bss->freq == sec_freq)
3479085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			sec_bss++;
3489085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
3499085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (sec_bss && !pri_bss) {
3509085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_INFO, "Switch own primary and secondary "
351755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   "channel to get secondary channel with no Beacons "
3529085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "from other BSSes");
3539085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		ieee80211n_switch_pri_sec(iface);
354755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
3559085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	/*
3579085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * Match PRI/SEC channel with any existing HT40 BSS on the same
3589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * channels that we are about to use (if already mixed order in
3599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * existing BSSes, use own preference).
3609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 */
3619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	match = 0;
3629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (i = 0; i < scan_res->num; i++) {
3639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		struct wpa_scan_res *bss = scan_res->res[i];
3643e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
3653e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		if (pri_chan == bss_pri_chan &&
3663e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		    sec_chan == bss_sec_chan) {
3673e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org			match = 1;
3683e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org			break;
3693e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		}
3709085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
3719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (!match) {
3729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		for (i = 0; i < scan_res->num; i++) {
3739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			struct wpa_scan_res *bss = scan_res->res[i];
3749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
3759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org						    &bss_sec_chan);
376eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org			if (pri_chan == bss_sec_chan &&
3779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			    sec_chan == bss_pri_chan) {
3789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				wpa_printf(MSG_INFO, "Switch own primary and "
379755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org					   "secondary channel due to BSS "
380755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org					   "overlap with " MACSTR,
381755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org					   MAC2STR(bss->bssid));
382755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				ieee80211n_switch_pri_sec(iface);
3839085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				break;
3849085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			}
385755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		}
386755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
387755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
3889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	return 1;
3899155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org}
3909155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org
3919155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org
3929155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.orgstatic int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
3939155e252524a2bf92aecd27493feafed86702312kmillikin@chromium.org				      struct wpa_scan_results *scan_res)
3940ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org{
3950ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org	int pri_freq, sec_freq;
3960ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org	int affected_start, affected_end;
3970ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org	size_t i;
3989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
3999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
40030ce411529579186181838984710b0b0980857aaricow@chromium.org	if (iface->conf->secondary_channel > 0)
4010ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org		sec_freq = pri_freq + 20;
4020ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org	else
4039085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		sec_freq = pri_freq - 20;
404e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	affected_start = (pri_freq + sec_freq) / 2 - 25;
4059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	affected_end = (pri_freq + sec_freq) / 2 + 25;
406755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
4079085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		   affected_start, affected_end);
4089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (i = 0; i < scan_res->num; i++) {
409755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		struct wpa_scan_res *bss = scan_res->res[i];
4109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		int pri = bss->freq;
4119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		int sec = pri;
412755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		int sec_chan, pri_chan;
413755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
414755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
415755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
4169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if (sec_chan) {
417755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			if (sec_chan < pri_chan)
4189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				sec = pri - 20;
4199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			else
4209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				sec = pri + 20;
4219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		}
4229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if ((pri < affected_start || pri > affected_end) &&
4243e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		    (sec < affected_start || sec > affected_end))
4253e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org			continue; /* not within affected channel range */
4263e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
4279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
4283e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org			   " freq=%d pri=%d sec=%d",
4299085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
4309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4319085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		if (sec_chan) {
4329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			if (pri_freq != pri || sec_freq != sec) {
4339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
434a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org					   "mismatch with BSS " MACSTR
4359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
436c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org					   MAC2STR(bss->bssid),
4379d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com					   pri, sec, pri_chan,
4389d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com					   sec > pri ? '+' : '-',
4399d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com					   pri_freq, sec_freq);
4409d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com				return 0;
4419d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com			}
442e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		}
4439085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4449085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		/* TODO: 40 MHz intolerant */
445c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	}
446e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
4479085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	return 1;
4489085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
4499085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4509085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4519085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgstatic void ieee80211n_check_scan(struct hostapd_iface *iface)
452c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org{
453c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	struct wpa_scan_results *scan_res;
4549085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int oper40;
455c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	int res;
4569085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
457c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
4589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
4599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4609085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	iface->scan_cb = NULL;
4619085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4629085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
4639085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (scan_res == NULL) {
464c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org		hostapd_setup_interface_complete(iface, 1);
4659085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return;
4669085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
4679085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4683e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
4693e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
470c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	else
4719085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
4729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	wpa_scan_results_free(scan_res);
473c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org
4749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (!oper40) {
4759085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
4769085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "channel pri=%d sec=%d based on overlapping BSSes",
4779085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   iface->conf->channel,
4789085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   iface->conf->channel +
4793e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org			   iface->conf->secondary_channel * 4);
4803e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		iface->conf->secondary_channel = 0;
4813e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	}
4829085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4833e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	res = ieee80211n_allowed_ht40_channel_pair(iface);
4843e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	hostapd_setup_interface_complete(iface, !res);
4853e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org}
4863e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
4873e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
4889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgstatic void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
4899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org					 struct wpa_driver_scan_params *params)
4909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
4919085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	/* Scan only the affected frequency range */
4929085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int pri_freq, sec_freq;
4939085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int affected_start, affected_end;
4949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int i, pos;
4959085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	struct hostapd_hw_modes *mode;
4969085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
4979085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->current_mode == NULL)
4989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return;
4999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
5009085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
5019085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->conf->secondary_channel > 0)
5029085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		sec_freq = pri_freq + 20;
5039085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	else
5049085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		sec_freq = pri_freq - 20;
5059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	affected_start = (pri_freq + sec_freq) / 2 - 25;
5069085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	affected_end = (pri_freq + sec_freq) / 2 + 25;
5079085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
5089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		   affected_start, affected_end);
5099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
5109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	mode = iface->current_mode;
5119085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
512c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	if (params->freqs == NULL)
513c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		return;
514c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	pos = 0;
515c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org
516c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	for (i = 0; i < mode->num_channels; i++) {
517c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		struct hostapd_channel_data *chan = &mode->channels[i];
518c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		if (chan->flag & HOSTAPD_CHAN_DISABLED)
519e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org			continue;
520e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		if (chan->freq < affected_start ||
521c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org		    chan->freq > affected_end)
5223811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org			continue;
523c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org		params->freqs[pos++] = chan->freq;
5243811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	}
5253811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org}
5263811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org
5273811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org
528c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.orgstatic void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
529c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org					struct wpa_driver_scan_params *params)
530c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org{
531c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	/* Scan only the affected frequency range */
532c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	int pri_freq;
533c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	int affected_start, affected_end;
534c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	int i, pos;
535c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	struct hostapd_hw_modes *mode;
536c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org
5373811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	if (iface->current_mode == NULL)
538c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org		return;
539c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org
5409085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
541c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	if (iface->conf->secondary_channel > 0) {
542c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		affected_start = pri_freq - 10;
543c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		affected_end = pri_freq + 30;
544c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	} else {
545c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		affected_start = pri_freq - 30;
546c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		affected_end = pri_freq + 10;
547c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	}
5482356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
5492356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org		   affected_start, affected_end);
5502356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org
5512356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org	mode = iface->current_mode;
5522356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
553c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	if (params->freqs == NULL)
554c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		return;
555ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org	pos = 0;
55683aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org
55783aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org	for (i = 0; i < mode->num_channels; i++) {
55883aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		struct hostapd_channel_data *chan = &mode->channels[i];
559ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org		if (chan->flag & HOSTAPD_CHAN_DISABLED)
560ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org			continue;
56183aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		if (chan->freq < affected_start ||
562ac6aa175ab59d65cfb7a88dbb621e1d7f1a80b8fsgjesse@chromium.org		    chan->freq > affected_end)
5632356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org			continue;
5642356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org		params->freqs[pos++] = chan->freq;
5652356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org	}
5665d00b60c201d860c74821f553fdc34f4e057b411lrn@chromium.org}
5675d00b60c201d860c74821f553fdc34f4e057b411lrn@chromium.org
568d91075f76b836c2cfa4f4e4cc0fb31170df864ccerik.corry@gmail.com
569d91075f76b836c2cfa4f4e4cc0fb31170df864ccerik.corry@gmail.comstatic int ieee80211n_check_40mhz(struct hostapd_iface *iface)
570496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org{
571496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org	struct wpa_driver_scan_params params;
572496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org
573496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org	if (!iface->conf->secondary_channel)
574496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org		return 0; /* HT40 not used */
575496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org
576496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
577496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
578496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org		   "40 MHz channel");
5792356e6fbe66ac3aa027b61cb43a3c3619b3c3a5evegorov@chromium.org	os_memset(&params, 0, sizeof(params));
5809085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
5819085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		ieee80211n_scan_channels_2g4(iface, &params);
5829085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	else
58371affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org		ieee80211n_scan_channels_5g(iface, &params);
58471affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
58571affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org		wpa_printf(MSG_ERROR, "Failed to request a scan of "
58671affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org			   "neighboring BSSes");
58771affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org		os_free(params.freqs);
588eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		return -1;
589eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	}
59071affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org	os_free(params.freqs);
59171affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org
59271affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org	iface->scan_cb = ieee80211n_check_scan;
59371affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org	return 1;
59471affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org}
59571affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org
59671affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.org
59771affb54842da76b24f0bb3184e9f0960523f89dkasperl@chromium.orgstatic int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
5989085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
5999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	u16 hw = iface->current_mode->ht_capab;
6009085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	u16 conf = iface->conf->ht_capab;
60183aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org
6029085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
6035ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org	    !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
6045ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
6059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "HT capability [LDPC]");
6069085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return 0;
607e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	}
608e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
6099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
610e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
6110ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
6120ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org			   "HT capability [HT40*]");
6130ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org		return 0;
6149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
6159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
6169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
6179085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
6189085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
6199085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "HT capability [SMPS-*]");
620e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return 0;
6219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
6229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
6239085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
624755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
625e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
626755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   "HT capability [GF]");
627755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
6283811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	}
6293811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org
6303811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
6313811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	    !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
632e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
633e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org			   "HT capability [SHORT-GI-20]");
634e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return 0;
635eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	}
636e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
637e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
638e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	    !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
639911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
640911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org			   "HT capability [SHORT-GI-40]");
641911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org		return 0;
642755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
643911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org
644e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
645e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
646911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org			   "HT capability [TX-STBC]");
647911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org		return 0;
648911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	}
649e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
650eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
651eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	    (hw & HT_CAP_INFO_RX_STBC_MASK)) {
652755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
653755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   "HT capability [RX-STBC*]");
654755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
655755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
656755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
657e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	if ((conf & HT_CAP_INFO_DELAYED_BA) &&
658e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	    !(hw & HT_CAP_INFO_DELAYED_BA)) {
659755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
660755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   "HT capability [DELAYED-BA]");
6613811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org		return 0;
6623811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org	}
6635aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
6643e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
6655aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	    !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
6665a6af92a1549c81fb61855518f43b712e4c0e469christian.plesner.hansen@gmail.com		wpa_printf(MSG_ERROR, "Driver does not support configured "
6673811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org			   "HT capability [MAX-AMSDU-7935]");
6685a6af92a1549c81fb61855518f43b712e4c0e469christian.plesner.hansen@gmail.com		return 0;
6695aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	}
670b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org
671b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org	if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
672b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org	    !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
673b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
674b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org			   "HT capability [DSSS_CCK-40]");
675b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org		return 0;
676b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org	}
677755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
678755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
679e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
6809085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "HT capability [PSMP]");
6813e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		return 0;
6823e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	}
6833e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
6843e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
6853e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	    !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
6869085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured "
6879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org			   "HT capability [LSIG-TXOP-PROT]");
6889085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return 0;
6899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
6909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
6915aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	return 1;
6929dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com}
6935aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
6945aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
6953e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org#ifdef CONFIG_IEEE80211AC
6963e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
6973e87580939cb78c5802369f723680d4a16cc2902ager@chromium.orgstatic int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
6983e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org{
699e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	u32 req_cap = conf & cap;
700e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
701e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	/*
702e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	 * Make sure we support all requested capabilities.
70386f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	 * NOTE: We assume that 'cap' represents a capability mask,
70486f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	 * not a discrete value.
70586f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	 */
70686f77b7fe492ed2bdfbf4e1147dab2f09c7d7003kasperl@chromium.org	if ((hw & req_cap) != req_cap) {
707e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org		wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
708755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   name);
709755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
710755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
711e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	return 1;
712e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org}
713e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
714755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
715eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.orgstatic int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
716755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				     const char *name)
717755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org{
718755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	u32 hw_max = hw & cap;
719eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	u32 conf_val = conf & cap;
720755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
721755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if (conf_val > hw_max) {
7229085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		int offset = find_first_bit(cap);
723eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
724755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   name, conf_val >> offset, hw_max >> offset);
725755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
726755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
727dff694e8cc18aa9640e92962de2699b9d07a7690vegorov@chromium.org	return 1;
7289dfbea4c7d423c7bc1db94425cb78e7f7cf41f78erik.corry@gmail.com}
729dff694e8cc18aa9640e92962de2699b9d07a7690vegorov@chromium.org
730dff694e8cc18aa9640e92962de2699b9d07a7690vegorov@chromium.org
7310a4e901cdfb5505a896d30aa8c2e04fce0fbe069vegorov@chromium.orgstatic int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
7320a4e901cdfb5505a896d30aa8c2e04fce0fbe069vegorov@chromium.org{
7330a4e901cdfb5505a896d30aa8c2e04fce0fbe069vegorov@chromium.org	u32 hw = iface->current_mode->vht_capab;
7340a4e901cdfb5505a896d30aa8c2e04fce0fbe069vegorov@chromium.org	u32 conf = iface->conf->vht_capab;
7353e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
7363e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org	wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
7373e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org		   hw, conf);
7383e87580939cb78c5802369f723680d4a16cc2902ager@chromium.org
739911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org#define VHT_CAP_CHECK(cap) \
740911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	do { \
741911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org		if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
742911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org			return 0; \
743911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	} while (0)
744911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org
745911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org#define VHT_CAP_CHECK_MAX(cap) \
746911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	do { \
747911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
748911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org			return 0; \
749911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	} while (0)
750911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org
751911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
752911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
753eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
754eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	VHT_CAP_CHECK(VHT_CAP_RXLDPC);
755eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
756eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
757911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_TXSTBC);
758911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
759911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
760911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
761911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
762911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
763911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
764911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
765911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
766911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
767911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
768911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
769911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
770911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
771911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
772911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org
773911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org#undef VHT_CAP_CHECK
774911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org#undef VHT_CAP_CHECK_MAX
775911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org
776911335cff40a2630bbe1dfb77b1897be991241bfsgjesse@chromium.org	return 1;
77768ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org}
77868ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org#endif /* CONFIG_IEEE80211AC */
77968ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org
78068ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org#endif /* CONFIG_IEEE80211N */
78168ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org
782e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
78368ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.orgint hostapd_check_ht_capab(struct hostapd_iface *iface)
78468ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org{
78568ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org#ifdef CONFIG_IEEE80211N
786e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	int ret;
78768ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org	if (!iface->conf->ieee80211n)
78868ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org		return 0;
78968ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org	if (!ieee80211n_supported_ht_capab(iface))
79068ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org		return -1;
79168ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org#ifdef CONFIG_IEEE80211AC
79268ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org	if (!ieee80211ac_supported_vht_capab(iface))
79368ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org		return -1;
79468ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org#endif /* CONFIG_IEEE80211AC */
79568ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org	ret = ieee80211n_check_40mhz(iface);
79668ac009f55a85e6891742d58914eaf717f667b26kasperl@chromium.org	if (ret)
797eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		return ret;
798755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if (!ieee80211n_allowed_ht40_channel_pair(iface))
799755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return -1;
800755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org#endif /* CONFIG_IEEE80211N */
801eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org
802755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	return 0;
803755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org}
804755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
805eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org
806755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.orgstatic int hostapd_is_usable_chan(struct hostapd_iface *iface,
807755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org				  int channel, int primary)
8089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
809eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	int i;
810755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	struct hostapd_channel_data *chan;
811755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
812755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	for (i = 0; i < iface->current_mode->num_channels; i++) {
813eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		chan = &iface->current_mode->channels[i];
814755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		if (chan->chan != channel)
815755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			continue;
816755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
817755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
818755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			return 1;
819755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
820755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		wpa_printf(MSG_DEBUG,
821755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s",
822755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   primary ? "" : "Configured HT40 secondary ",
823755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   i, chan->chan, chan->flag,
824755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "",
825755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ?
826755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   " PASSIVE-SCAN" : "",
827755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
828755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
829755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
830755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	return 0;
831755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org}
832755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
833755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
834755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.orgstatic int hostapd_is_usable_chans(struct hostapd_iface *iface)
835755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org{
8369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
837c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		return 0;
838c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org
839c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org	if (!iface->conf->secondary_channel)
840c514574143c1bf74d4fb6e7dccb175fe9ff2f5d3sgjesse@chromium.org		return 1;
8419d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
8429d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	return hostapd_is_usable_chan(iface, iface->conf->channel +
8439d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com				      iface->conf->secondary_channel * 4, 0);
8449d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com}
8450ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org
8460ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.org
8470ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.orgstatic enum hostapd_chan_status
8480ee099beef2c2b38743d657b84a30b626d9178ecager@chromium.orghostapd_check_chans(struct hostapd_iface *iface)
849b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org{
850b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org	if (iface->conf->channel) {
851b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org		if (hostapd_is_usable_chans(iface))
8529d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com			return HOSTAPD_CHAN_VALID;
853eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		else
854eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org			return HOSTAPD_CHAN_INVALID;
855e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	}
856eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org
8579d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	/*
8589d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	 * The user set channel=0 or channel=acs_survey
8599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	 * which is used to trigger ACS.
860e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	 */
861e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
8620b6db5975a9d1ebcf3de7b18603380d99f789e66sgjesse@chromium.org	switch (acs_init(iface)) {
8630b6db5975a9d1ebcf3de7b18603380d99f789e66sgjesse@chromium.org	case HOSTAPD_CHAN_ACS:
8649085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return HOSTAPD_CHAN_ACS;
865e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	case HOSTAPD_CHAN_VALID:
8660b6db5975a9d1ebcf3de7b18603380d99f789e66sgjesse@chromium.org	case HOSTAPD_CHAN_INVALID:
8670b6db5975a9d1ebcf3de7b18603380d99f789e66sgjesse@chromium.org	default:
8680b6db5975a9d1ebcf3de7b18603380d99f789e66sgjesse@chromium.org		return HOSTAPD_CHAN_INVALID;
8699085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
8702abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.org}
8712abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.org
8722abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.org
8732abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.orgstatic void hostapd_notify_bad_chans(struct hostapd_iface *iface)
8742abc450936e88b5c98a5e9d43ee6230ccc748272kasperl@chromium.org{
875cec079d8ed1f0920a0ea3dc9a3e81966013287c1whesse@chromium.org	hostapd_logger(iface->bss[0], NULL,
876cec079d8ed1f0920a0ea3dc9a3e81966013287c1whesse@chromium.org		       HOSTAPD_MODULE_IEEE80211,
877d91075f76b836c2cfa4f4e4cc0fb31170df864ccerik.corry@gmail.com		       HOSTAPD_LEVEL_WARNING,
878cec079d8ed1f0920a0ea3dc9a3e81966013287c1whesse@chromium.org		       "Configured channel (%d) not found from the "
8799085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		       "channel list of current mode (%d) %s",
880eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		       iface->conf->channel,
881eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		       iface->current_mode->mode,
8825ad5acef6bd4ebc785f946d8bcc2a88b1e031827ricow@chromium.org		       hostapd_hw_mode_txt(iface->current_mode->mode));
883eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
8849085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		       HOSTAPD_LEVEL_WARNING,
8859085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		       "Hardware does not support configured channel");
886cec079d8ed1f0920a0ea3dc9a3e81966013287c1whesse@chromium.org}
8879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
888e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
8899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgint hostapd_acs_completed(struct hostapd_iface *iface, int err)
8909085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
8919085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	int ret = -1;
892755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
8934af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org	if (err)
8949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		goto out;
8959085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
896755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	switch (hostapd_check_chans(iface)) {
897cec079d8ed1f0920a0ea3dc9a3e81966013287c1whesse@chromium.org	case HOSTAPD_CHAN_VALID:
898755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
899755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			ACS_EVENT_COMPLETED "freq=%d channel=%d",
900755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			hostapd_hw_get_freq(iface->bss[0],
901755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org					    iface->conf->channel),
902755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			iface->conf->channel);
9034af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org		break;
9044af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org	case HOSTAPD_CHAN_ACS:
9054af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org		wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
9064af710e493dc8583f3b7b7ce65127ad4e7c3f8a1ager@chromium.org		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
907755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		hostapd_notify_bad_chans(iface);
908755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		goto out;
909755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	case HOSTAPD_CHAN_INVALID:
910755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	default:
91183aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		wpa_printf(MSG_ERROR, "ACS picked unusable channels");
91283aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED);
91383aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		hostapd_notify_bad_chans(iface);
91483aa54905e559090bea7771b83f188762cfcf082ricow@chromium.org		goto out;
915755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	}
916755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
917755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	ret = hostapd_check_ht_capab(iface);
918755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if (ret < 0)
919755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		goto out;
920755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if (ret == 1) {
921755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
922755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
9239d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	}
9249d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
9259d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	ret = 0;
9269d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.comout:
927755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	return hostapd_setup_interface_complete(iface, ret);
928755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org}
929755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
9309085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
9319d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com/**
9329d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com * hostapd_select_hw_mode - Select the hardware mode
9339d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com * @iface: Pointer to interface data.
9349d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com * Returns: 0 on success, < 0 on failure
9359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org *
9369d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com * Sets up the hardware mode, channel, rates, and passive scanning
9379d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com * based on the configuration.
9389d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com */
9399d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.comint hostapd_select_hw_mode(struct hostapd_iface *iface)
9409d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com{
9419d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	int i;
9429d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
9439d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	if (iface->num_hw_features < 1)
9449d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com		return -1;
9459d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com
9469d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
9479d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	     iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
9489d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com	    iface->conf->channel == 14) {
9499d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com		wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
9509d58c2b1c27d8b2890b9bd46e57d3842b09e0292christian.plesner.hansen@gmail.com		iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
9519085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		iface->conf->ieee80211n = 0;
952e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		iface->conf->ieee80211ac = 0;
953e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	}
954e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
955e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	iface->current_mode = NULL;
956e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	for (i = 0; i < iface->num_hw_features; i++) {
957e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		struct hostapd_hw_modes *mode = &iface->hw_features[i];
958e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		if (mode->mode == iface->conf->hw_mode) {
959e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org			iface->current_mode = mode;
960e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org			break;
961e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		}
962e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	}
963e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
964defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org	if (iface->current_mode == NULL) {
965defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org		wpa_printf(MSG_ERROR, "Hardware does not support configured "
966defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org			   "mode");
967defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
968defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org			       HOSTAPD_LEVEL_WARNING,
969defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org			       "Hardware does not support configured mode "
970e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org			       "(%d) (hw_mode in hostapd.conf)",
971c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org			       (int) iface->conf->hw_mode);
972e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return -2;
973e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	}
9749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
975defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org	switch (hostapd_check_chans(iface)) {
976c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	case HOSTAPD_CHAN_VALID:
977defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org		return 0;
978defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org	case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */
979defbd109bb9bd556bb8ece103c3b340d3552155ekasperl@chromium.org		return 1;
980e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	case HOSTAPD_CHAN_INVALID:
981e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	default:
982e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		hostapd_notify_bad_chans(iface);
9839085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org		return -3;
984c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org	}
985e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
986e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	return 0;
9879085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
988c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org
9895aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
9905aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.orgconst char * hostapd_hw_mode_txt(int mode)
9915aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org{
992e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	switch (mode) {
993e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	case HOSTAPD_MODE_IEEE80211A:
994e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org		return "IEEE 802.11a";
995e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	case HOSTAPD_MODE_IEEE80211B:
996e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return "IEEE 802.11b";
997e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	case HOSTAPD_MODE_IEEE80211G:
998e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return "IEEE 802.11g";
9999085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	case HOSTAPD_MODE_IEEE80211AD:
1000c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org		return "IEEE 802.11ad";
1001e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org	default:
1002e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return "UNKNOWN";
10039085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	}
1004c4c927273ae2b690c4a015b4640a2a469c9a1a69ager@chromium.org}
10055aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
10065aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
10075aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.orgint hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
1008e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org{
1009e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	int i;
1010e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org
1011e959c18cf7193e2f021245584a3c8f1f32f82c92kasperl@chromium.org	if (!hapd->iface->current_mode)
1012e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org		return 0;
1013e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
10149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
1015eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org		struct hostapd_channel_data *ch =
1016755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			&hapd->iface->current_mode->channels[i];
1017755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		if (ch->chan == chan)
1018755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			return ch->freq;
1019eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	}
1020755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
1021755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	return 0;
1022755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org}
1023eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org
1024755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
1025755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.orgint hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
10269085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org{
1027eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org	int i;
1028755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org
1029755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	if (!hapd->iface->current_mode)
1030755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		return 0;
1031eadaf2282ee421d7a63a21d71369b029105341ccager@chromium.org
1032755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
1033755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org		struct hostapd_channel_data *ch =
1034755c5b1cc880bc54405d2652f934a941e8fcda4asgjesse@chromium.org			&hapd->iface->current_mode->channels[i];
10355aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org		if (ch->freq == freq)
10365aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org			return ch->chan;
10375aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org	}
10385aa501ca9fb4dfb30f4191aac135202fe8d80e4aager@chromium.org
1039b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org	return 0;
1040b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org}
1041b302e56e5b70c4504faa2adf4ec3efb64a9d3e38sgjesse@chromium.org