dfs.c revision d30ac604c9f6da71a0dd7f46d25be05a2a62cfbb
1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection
3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2013, Qualcomm Atheros, Inc.
5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *
6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details.
8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h"
11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h"
13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h"
14cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h"
15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h"
16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h"
17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h"
18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h"
19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
21cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface)
22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1;
24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
25cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
26051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
27051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
29cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
31051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 4;
34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 8;
37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
41051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return n_chans;
44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
4704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan,
4804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				 int skip_radar)
49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
5004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/*
5104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * When radar detection happens, CSA is performed. However, there's no
5204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * time for CAC, so radar channels must be skipped when finding a new
539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	 * channel for CSA, unless they are available for immediate use.
5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 */
559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	     HOSTAPD_CHAN_DFS_AVAILABLE))
5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
5904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (chan->flag & HOSTAPD_CHAN_DISABLED)
61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 1;
67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * The tables contain first valid channel number based on channel width.
7468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * We will also choose this first channel as the control one.
7568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			     184, 192 };
7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * VHT80, valid channels based on center frequency:
8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * 42, 58, 106, 122, 138, 155
8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
83f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
84f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * VHT160 valid channels based on center frequency:
85f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * 50, 114
86f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
87f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int allowed_160[] = { 36, 100 };
8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int *allowed = allowed_40;
8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	unsigned int i, allowed_no = 0;
9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (n_chans) {
9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 2:
9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_40;
9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_40);
9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 4:
9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_80;
9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_80);
9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case 8:
101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed = allowed_160;
102f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_160);
103f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
10668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
10768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
10968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	for (i = 0; i < allowed_no; i++) {
110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == allowed[i])
111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
118cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode,
11904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int first_chan_idx, int num_chans,
12004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int skip_radar)
121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *first_chan, *chan;
123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i;
124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
125cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (first_chan_idx + num_chans >= mode->num_channels)
126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return 0;
127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	first_chan = &mode->channels[first_chan_idx];
129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < num_chans; i++) {
131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &mode->channels[first_chan_idx + i];
132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (first_chan->freq + i * 20 != chan->freq)
134cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
13604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_channel_available(chan, skip_radar))
137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	return 1;
141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
1449866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface,
1459866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			  struct hostapd_channel_data *chan)
1469866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{
1479866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	int *entry;
1489866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1499866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (!iface->conf->chanlist)
1509866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 1;
1519866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1529866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	for (entry = iface->conf->chanlist; *entry != -1; entry++) {
1539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (*entry == chan->chan)
1549866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return 1;
1559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
1569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	return 0;
1579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt}
1589866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
160cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/*
161cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation.
162cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this:
163cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->secondary_channel
164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg0_idx
165cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg1_idx
166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */
167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface,
168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    struct hostapd_channel_data **ret_chan,
16904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			    int idx, int skip_radar)
170051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
171051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *chan;
173cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i, channel_idx = 0, n_chans;
174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
175cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
176cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
182cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip HT40/VHT incompatible channels */
183cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (iface->conf->ieee80211n &&
184cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    iface->conf->secondary_channel &&
185cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    !dfs_is_chan_allowed(chan, n_chans))
186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			continue;
187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
188cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip incompatible chandefs */
18904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			continue;
191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1929866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!is_in_chanlist(iface, chan))
1939866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			continue;
1949866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (ret_chan && idx == channel_idx) {
196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			*ret_chan = chan;
198051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return idx;
199051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
200051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_idx++;
202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
203051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return channel_idx;
204051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
208cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       struct hostapd_channel_data *chan,
209344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				       int secondary_channel,
210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg0_idx,
211cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg1_idx)
212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211ac)
214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!chan)
217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
219cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
220cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	switch (iface->conf->vht_oper_chwidth) {
222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_USE_HT:
223344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		if (secondary_channel == 1)
224cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
225344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else if (secondary_channel == -1)
226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
22768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		else
228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan;
229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_80MHZ:
231cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_160MHZ:
234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
23568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
2387d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = 0;
239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
240051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
242cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
243cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg0_idx,
244cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg1_idx);
245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */
249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface)
250051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
253cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int channel_no = iface->conf->channel;
254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = -1, i;
255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* HT40- */
257cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_no -= 4;
259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* VHT */
261cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
262cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
267cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
271cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_INFO,
275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   "DFS only VHT20/40/80/160 is supported now");
276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no = -1;
277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Get idx */
282cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == channel_no) {
286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res = i;
287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
2919866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (res == -1) {
2929866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		wpa_printf(MSG_DEBUG,
2939866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
2949866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   mode->num_channels, channel_no, iface->conf->channel,
2959866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->ieee80211n,
2969866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->secondary_channel,
2979866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->vht_oper_chwidth);
2989866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
2999866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		for (i = 0; i < mode->num_channels; i++) {
3009866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Available channel: %d",
3019866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt				   mode->channels[i].chan);
3029866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
3039866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */
310cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface,
311cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				 int start_chan_idx, int n_chans)
312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
315051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
317cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_RADAR)
322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */
330cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface,
331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				     int start_chan_idx, int n_chans)
332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
333051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
334051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
335051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
336051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
337cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
339f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
341f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
342f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
343f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			break;
344f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
345f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
346f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
347f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_AVAILABLE)
350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return i == n_chans;
354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */
358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface,
359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int start_chan_idx,
360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int n_chans)
361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
366cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
368f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
381cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data *
382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface,
383cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      int *secondary_channel,
384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg0_idx,
38504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg1_idx,
38604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      int skip_radar)
387051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
388051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
390cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int num_available_chandefs;
391cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int chan_idx;
392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u32 _rand;
393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
3957d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*secondary_channel = 0;
3967d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg0_idx = 0;
3977d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
399cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->current_mode == NULL)
400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
402cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
406cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* Get the count first */
40704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
408cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (num_available_chandefs == 0)
409cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return NULL;
410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
411cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	os_get_random((u8 *) &_rand, sizeof(_rand));
412cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	chan_idx = _rand % num_available_chandefs;
41304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
414cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
415cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* dfs_find_channel() calculations assume HT40+ */
416cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->secondary_channel)
417cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 1;
418cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	else
419cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 0;
420cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
421cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	dfs_adjust_vht_center_freq(iface, chan,
422344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				   *secondary_channel,
423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg0_idx,
424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg1_idx);
425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return chan;
427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
430cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
436cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
441cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < iface->current_mode->num_channels; i++) {
442cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &iface->current_mode->channels[i];
443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->freq == freq) {
444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->flag & HOSTAPD_CHAN_RADAR) {
445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag |= state;
447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return 1; /* Channel found */
448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
456cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int chan_offset, int chan_width, int cf1,
458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int cf2, u32 state)
459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1, i;
461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int frequency = freq;
463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int ret = 0;
464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
465cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Seems cf1 and chan_width is enough here */
475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 1;
479cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
480cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 4;
488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 8;
492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		   n_chans);
502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
503cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		ret += set_dfs_state_freq(iface, frequency, state);
504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = frequency + 20;
505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return ret;
508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
511cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int chan_width, int cf1, int cf2)
513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int start_chan_idx;
515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans, i, j, frequency = freq, radar_n_chans = 1;
518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u8 radar_chan;
519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = 0;
520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Our configuration */
522cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
523cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface);
524cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
52668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* Check we are on DFS channel(s) */
527cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
52868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return 0;
52968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Reported via radar event */
531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 1;
535cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
536cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 2;
540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 4;
544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 8;
548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
556051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	ieee80211_freq_to_chan(frequency, &radar_chan);
557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[start_chan_idx + i];
56068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
56168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			continue;
562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		for (j = 0; j < radar_n_chans; j++) {
563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   chan->chan, radar_chan + j * 4);
565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->chan == radar_chan + j * 4)
566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				res++;
567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
568051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
576df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
577df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				     int start_chan_idx, int n_chans)
578df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
579df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_channel_data *channel;
580df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_hw_modes *mode;
581df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int i;
582df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	unsigned int cac_time_ms = 0;
583df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
584df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	mode = iface->current_mode;
585df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
586df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
587df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
588df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
589df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			continue;
590df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (channel->dfs_cac_ms > cac_time_ms)
591df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			cac_time_ms = channel->dfs_cac_ms;
592df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
593df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
594df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return cac_time_ms;
595df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
596df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
597df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler
600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup
601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC
602051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error
603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
604cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface)
605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res, n_chans, start_chan_idx;
60804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
609051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
610cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	iface->cac_started = 0;
611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	do {
613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get start (first) channel for current configuration */
614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		start_chan_idx = dfs_get_start_chan_idx(iface);
615051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (start_chan_idx == -1)
616051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return -1;
617051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
618051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get number of used channels, depend on width */
619cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		n_chans = dfs_get_used_n_chans(iface);
620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
621df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		/* Setup CAC time */
622df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
623df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						     n_chans);
624df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels require DFS */
626cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS %d channels required radar detection",
629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res);
630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (!res)
631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if all channels are DFS available */
634cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
635051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
636051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS all channels available, (SKIP CAC): %s",
637051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res ? "yes" : "no");
638051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res)
639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
641051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels is unavailable */
642cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_unavailable(iface, start_chan_idx,
643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt						  n_chans);
644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res, res ? "yes": "no");
646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res) {
64796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			int sec = 0;
64896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			u8 cf1 = 0, cf2 = 0;
649cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
65104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt							skip_radar);
652051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (!channel) {
653051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				wpa_printf(MSG_ERROR, "could not get valid channel");
654051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return -1;
655051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
656cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
657cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->freq = channel->freq;
658cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->channel = channel->chan;
659cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->secondary_channel = sec;
660cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
661cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
662051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
663051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	} while (res);
664051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
665051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Finally start CAC */
666cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	hostapd_set_state(iface, HAPD_IFACE_DFS);
667cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
668cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
669df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
670cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq,
671a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->channel, iface->conf->secondary_channel,
672a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_chwidth,
673a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx,
674df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx,
675df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms / 1000);
676a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
677a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
678a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->freq,
679a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->channel,
680a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211n,
681a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211ac,
682a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->secondary_channel,
683a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_chwidth,
684a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg0_idx,
685a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg1_idx);
686a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
687a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	if (res) {
688a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
689051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return -1;
690051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
691051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
692051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
693051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
694051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
695051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
696cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
697051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
698051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
699051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
700cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
701cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
702cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
703cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
704051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (success) {
705051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Complete iface/ap configuration */
706cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		set_dfs_state(iface, freq, ht_enabled, chan_offset,
707051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      chan_width, cf1, cf2,
708051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      HOSTAPD_CHAN_DFS_AVAILABLE);
709cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->cac_started = 0;
710cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_setup_interface_complete(iface, 0);
711051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
712051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
713051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
714051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
715051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
716051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
718051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
719051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int secondary_channel;
72196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx = 0;
72296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx = 0;
72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
724051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int err = 1;
72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Radar detected during active CAC */
72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->cac_started = 0;
72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "No valid channel available");
73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_setup_interface_complete(iface, err);
73604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
74104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
74204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
74304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->freq = channel->freq;
74604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->channel = channel->chan;
74704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->secondary_channel = secondary_channel;
74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg0_idx =
74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg0_idx;
75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg1_idx =
75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg1_idx;
75204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = 0;
75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	hostapd_setup_interface_complete(iface, err);
75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return err;
75604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
75704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
75804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
759d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtstatic int hostapd_csa_in_progress(struct hostapd_iface *iface)
760d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{
761d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	unsigned int i;
762d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	for (i = 0; i < iface->num_bss; i++)
763d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (iface->bss[i]->csa_in_progress)
764d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			return 1;
765d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	return 0;
766d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt}
767d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
768d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
76904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct hostapd_channel_data *channel;
772cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int secondary_channel;
773cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx;
774cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx;
77504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 1;
77604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct csa_settings csa_settings;
777d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	unsigned int i;
77804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int err = 1;
77904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
780344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
781344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		   __func__, iface->cac_started ? "yes" : "no",
782d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		   hostapd_csa_in_progress(iface) ? "yes" : "no");
783344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
784344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	/* Check if CSA in progress */
785d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (hostapd_csa_in_progress(iface))
786344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		return 0;
787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
78804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Check if active CAC */
78904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (iface->cac_started)
79004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return hostapd_dfs_start_channel_switch_cac(iface);
79104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
79204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Perform channel switch/CSA */
793cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
794cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
79504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
79604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
79704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
79804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
7999866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		/*
8009866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * If there is no channel to switch immediately to, check if
8019866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * there is another channel where we can switch even if it
8029866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * requires to perform a CAC first.
8039866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 */
8049866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		skip_radar = 0;
8059866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		channel = dfs_get_valid_channel(iface, &secondary_channel,
8069866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg0_idx,
8079866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg1_idx,
8089866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						skip_radar);
8099866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!channel) {
8109866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			/* FIXME: Wait for channel(s) to become available */
8119866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			hostapd_disable_iface(iface);
8129866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return err;
8139866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
8149866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
8159866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->freq = channel->freq;
8169866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->channel = channel->chan;
8179866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
8189866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
8199866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
8209866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
8219866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
8229866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
82304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
8249866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		hostapd_enable_iface(iface);
8259866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 0;
82604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
82704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
82804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
82904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
83004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
83104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
83204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
83304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
83404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Setup CSA request */
83504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_memset(&csa_settings, 0, sizeof(csa_settings));
83604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.cs_count = 5;
83704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.block_tx = 1;
83804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = hostapd_set_freq_params(&csa_settings.freq_params,
83904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->hw_mode,
84004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->freq,
84104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->chan,
84204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211n,
84304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211ac,
84404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      secondary_channel,
84504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->vht_oper_chwidth,
84604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg0_idx,
84704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg1_idx,
84804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->current_mode->vht_capab);
84904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
85004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
85104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
85204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
85304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
85404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
855cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
856d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	for (i = 0; i < iface->num_bss; i++) {
857d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
858d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (err)
859d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			break;
860d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	}
861d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
86204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
86304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
86404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			   err);
865cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq = channel->freq;
866cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->channel = channel->chan;
867cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
868cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
869cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
870cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
871cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
872051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
873cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_disable_iface(iface);
87404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_enable_iface(iface);
87504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
87668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
877051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
87804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Channel configuration will be updated once CSA completes and
87904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * ch_switch_notify event is received */
88004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
88104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
882051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
883051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
884051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
885051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
886cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
887051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int ht_enabled, int chan_offset, int chan_width,
888051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int cf1, int cf2)
889051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
890051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res;
891051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
892cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211h)
893051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
894051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
895cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
896cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
897cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
898cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
899051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* mark radar frequency as invalid */
900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
901051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    chan_width, cf1, cf2,
902051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    HOSTAPD_CHAN_DFS_UNAVAILABLE);
903051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
904051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Skip if reported radar event not overlapped our channels */
905cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
906051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!res)
907051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
908051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
909051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* radar detected while operating, switch the channel. */
910cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = hostapd_dfs_start_channel_switch(iface);
911051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
912051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
913051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
914051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
915051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
916cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
917051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
918051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
919051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
920cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
921cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
922cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
923051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* TODO add correct implementation here */
924cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
925cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
926051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
927051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
928f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
929f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
930f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface)
931f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
932f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int n_chans, start_chan_idx;
933f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
93461593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	if (!iface->conf->ieee80211h || !iface->current_mode ||
93561593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
93661593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt		return 0;
937f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
938f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get start (first) channel for current configuration */
939f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface);
940f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (start_chan_idx == -1)
941f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
942f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
943f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get number of used channels, depend on width */
944f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
945f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Check if any of configured channels require DFS */
947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
948f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
949