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
21a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1;
24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
25a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	*seg1 = 0;
26a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
27cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
28051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
29051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
30cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
31cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 4;
36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 8;
39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
40a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		case VHT_CHANWIDTH_80P80MHZ:
41a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			n_chans = 4;
42a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			*seg1 = 4;
43a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			break;
44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return n_chans;
50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
5304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan,
5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				 int skip_radar)
55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
5604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/*
5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * When radar detection happens, CSA is performed. However, there's no
5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * time for CAC, so radar channels must be skipped when finding a new
599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	 * channel for CSA, unless they are available for immediate use.
6004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 */
619866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	     HOSTAPD_CHAN_DFS_AVAILABLE))
6404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
6504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (chan->flag & HOSTAPD_CHAN_DISABLED)
67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 1;
73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
77051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * The tables contain first valid channel number based on channel width.
8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * We will also choose this first channel as the control one.
8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
8368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			     184, 192 };
8468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
8568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * VHT80, valid channels based on center frequency:
8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * 42, 58, 106, 122, 138, 155
8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
89f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
90f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * VHT160 valid channels based on center frequency:
91f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * 50, 114
92f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
93f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int allowed_160[] = { 36, 100 };
9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int *allowed = allowed_40;
9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	unsigned int i, allowed_no = 0;
9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (n_chans) {
9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 2:
9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_40;
10068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_40);
10168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 4:
10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_80;
10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_80);
10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
106f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case 8:
107f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed = allowed_160;
108f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_160);
109f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
11068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
11168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
11268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
11368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
11568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	for (i = 0; i < allowed_no; i++) {
116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == allowed[i])
117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode,
12504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int first_chan_idx, int num_chans,
12604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int skip_radar)
127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *first_chan, *chan;
129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i;
130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (first_chan_idx + num_chans >= mode->num_channels)
132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return 0;
133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
134cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	first_chan = &mode->channels[first_chan_idx];
135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < num_chans; i++) {
137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &mode->channels[first_chan_idx + i];
138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (first_chan->freq + i * 20 != chan->freq)
140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
14204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_channel_available(chan, skip_radar))
143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	return 1;
147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
1509866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface,
1519866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			  struct hostapd_channel_data *chan)
1529866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{
1539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	int *entry;
1549866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (!iface->conf->chanlist)
1569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 1;
1579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1589866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	for (entry = iface->conf->chanlist; *entry != -1; entry++) {
1599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (*entry == chan->chan)
1609866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return 1;
1619866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
1629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	return 0;
1639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt}
1649866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1659866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/*
167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation.
168cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this:
169cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->secondary_channel
170cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg0_idx
171cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg1_idx
172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */
173cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface,
174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    struct hostapd_channel_data **ret_chan,
17504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			    int idx, int skip_radar)
176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
178cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *chan;
179a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int i, channel_idx = 0, n_chans, n_chans1;
180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
181cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
182a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
188cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip HT40/VHT incompatible channels */
189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (iface->conf->ieee80211n &&
190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    iface->conf->secondary_channel &&
191cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    !dfs_is_chan_allowed(chan, n_chans))
192051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			continue;
193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
194cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip incompatible chandefs */
19504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
196cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			continue;
197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1989866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!is_in_chanlist(iface, chan))
1999866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			continue;
2009866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (ret_chan && idx == channel_idx) {
202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
203051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			*ret_chan = chan;
204051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return idx;
205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
207051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_idx++;
208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return channel_idx;
210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
214cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       struct hostapd_channel_data *chan,
215344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				       int secondary_channel,
216cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg0_idx,
217cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg1_idx)
218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
219cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211ac)
220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!chan)
223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
225cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
227cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	switch (iface->conf->vht_oper_chwidth) {
228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_USE_HT:
229344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		if (secondary_channel == 1)
230cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
231344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else if (secondary_channel == -1)
232cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
23368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		else
234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan;
235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_80MHZ:
237cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_160MHZ:
240cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
24168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
2447d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = 0;
245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
248cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg0_idx,
250cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg1_idx);
251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */
255a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
259cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int channel_no = iface->conf->channel;
260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = -1, i;
261a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int chan_seg1 = -1;
262a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
263a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	*seg1_start = -1;
264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* HT40- */
266cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_no -= 4;
268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* VHT */
270cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
271cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
276cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
280cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
282a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		case VHT_CHANWIDTH_80P80MHZ:
283a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			channel_no =
284a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
285a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			chan_seg1 =
286a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				iface->conf->vht_oper_centr_freq_seg1_idx - 6;
287a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			break;
288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_INFO,
290a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				   "DFS only VHT20/40/80/160/80+80 is supported now");
291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no = -1;
292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Get idx */
297cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == channel_no) {
301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res = i;
302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
306a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (res != -1 && chan_seg1 > -1) {
307a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		int found = 0;
308a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
309a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		/* Get idx for seg1 */
310a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		mode = iface->current_mode;
311a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		for (i = 0; i < mode->num_channels; i++) {
312a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			chan = &mode->channels[i];
313a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			if (chan->chan == chan_seg1) {
314a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				*seg1_start = i;
315a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				found = 1;
316a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				break;
317a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			}
318a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		}
319a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		if (!found)
320a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			res = -1;
321a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	}
322a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
3239866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (res == -1) {
3249866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		wpa_printf(MSG_DEBUG,
3259866086a955d00e237cc8df3722e7dff75c02532Dmitry 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",
3269866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   mode->num_channels, channel_no, iface->conf->channel,
3279866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->ieee80211n,
3289866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->secondary_channel,
3299866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->vht_oper_chwidth);
3309866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
3319866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		for (i = 0; i < mode->num_channels; i++) {
3329866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Available channel: %d",
3339866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt				   mode->channels[i].chan);
3349866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
3359866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
336051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
341051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */
342cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface,
343cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				 int start_chan_idx, int n_chans)
344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
349cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_RADAR)
354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
358051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */
362cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface,
363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				     int start_chan_idx, int n_chans)
364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
369cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
371f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
373f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
374f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
375f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			break;
376f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
377f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
378f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
379f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_AVAILABLE)
382051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
383051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
384051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
385051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return i == n_chans;
386051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
387051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
388051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */
390cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface,
391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int start_chan_idx,
392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int n_chans)
393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
398cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
400f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
409051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
413cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data *
414cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface,
415cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      int *secondary_channel,
416cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg0_idx,
41704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg1_idx,
41804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      int skip_radar)
419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
422cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int num_available_chandefs;
423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int chan_idx;
424051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u32 _rand;
425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
4277d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*secondary_channel = 0;
4287d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg0_idx = 0;
4297d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
431cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->current_mode == NULL)
432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
434cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
438cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* Get the count first */
43904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
440cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (num_available_chandefs == 0)
441cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return NULL;
442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
443cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	os_get_random((u8 *) &_rand, sizeof(_rand));
444cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	chan_idx = _rand % num_available_chandefs;
44504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
446cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
447cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* dfs_find_channel() calculations assume HT40+ */
448cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->secondary_channel)
449cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 1;
450cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	else
451cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 0;
452cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
453cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	dfs_adjust_vht_center_freq(iface, chan,
454344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				   *secondary_channel,
455cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg0_idx,
456cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg1_idx);
457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return chan;
459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
462cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
468cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
473cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < iface->current_mode->num_channels; i++) {
474cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &iface->current_mode->channels[i];
475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->freq == freq) {
476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->flag & HOSTAPD_CHAN_RADAR) {
477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag |= state;
479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return 1; /* Channel found */
480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
488cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int chan_offset, int chan_width, int cf1,
490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int cf2, u32 state)
491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1, i;
493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int frequency = freq;
495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int ret = 0;
496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
497cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Seems cf1 and chan_width is enough here */
507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 1;
511cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
512cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 4;
520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 8;
524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		   n_chans);
534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
535cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		ret += set_dfs_state_freq(iface, frequency, state);
536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = frequency + 20;
537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return ret;
540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
543cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int chan_width, int cf1, int cf2)
545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
546a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int start_chan_idx, start_chan_idx1;
547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
549a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u8 radar_chan;
551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = 0;
552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Our configuration */
554cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
555a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
556a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
55868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* Check we are on DFS channel(s) */
559cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
56068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return 0;
56168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Reported via radar event */
563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 1;
567cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 2;
572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 4;
576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 8;
580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	ieee80211_freq_to_chan(frequency, &radar_chan);
589051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
590051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
591051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[start_chan_idx + i];
59268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
59368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			continue;
594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		for (j = 0; j < radar_n_chans; j++) {
595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   chan->chan, radar_chan + j * 4);
597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->chan == radar_chan + j * 4)
598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				res++;
599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
602051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
608df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
609df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				     int start_chan_idx, int n_chans)
610df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
611df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_channel_data *channel;
612df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_hw_modes *mode;
613df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int i;
614df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	unsigned int cac_time_ms = 0;
615df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
616df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	mode = iface->current_mode;
617df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
618df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
619df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
620df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
621df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			continue;
622df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (channel->dfs_cac_ms > cac_time_ms)
623df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			cac_time_ms = channel->dfs_cac_ms;
624df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
625df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
626df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return cac_time_ms;
627df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
628df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
629df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler
632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup
633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC
634051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error
635051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
636cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface)
637051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
638051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
639a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
64004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
641051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
642cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	iface->cac_started = 0;
643cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	do {
645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get start (first) channel for current configuration */
646a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		start_chan_idx = dfs_get_start_chan_idx(iface,
647a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt							&start_chan_idx1);
648051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (start_chan_idx == -1)
649051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return -1;
650051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
651051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get number of used channels, depend on width */
652a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		n_chans = dfs_get_used_n_chans(iface, &n_chans1);
653051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
654df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		/* Setup CAC time */
655df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
656df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						     n_chans);
657df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
658051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels require DFS */
659cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
660051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
661051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS %d channels required radar detection",
662051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res);
663051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (!res)
664051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
665051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
666051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if all channels are DFS available */
667cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
668051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
669051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS all channels available, (SKIP CAC): %s",
670051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res ? "yes" : "no");
671051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res)
672051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
673051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
674051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels is unavailable */
675cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_unavailable(iface, start_chan_idx,
676051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt						  n_chans);
677051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
678051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res, res ? "yes": "no");
679051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res) {
68096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			int sec = 0;
68196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			u8 cf1 = 0, cf2 = 0;
682cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt							skip_radar);
685051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (!channel) {
686051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				wpa_printf(MSG_ERROR, "could not get valid channel");
687051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return -1;
688051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
689cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
690cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->freq = channel->freq;
691cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->channel = channel->chan;
692cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->secondary_channel = sec;
693cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
694cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
695051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
696051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	} while (res);
697051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
698051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Finally start CAC */
699cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	hostapd_set_state(iface, HAPD_IFACE_DFS);
700cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
701cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
702df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
703cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq,
704a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->channel, iface->conf->secondary_channel,
705a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_chwidth,
706a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx,
707df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx,
708df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms / 1000);
709a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
710a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
711a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->freq,
712a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->channel,
713a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211n,
714a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211ac,
715a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->secondary_channel,
716a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_chwidth,
717a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg0_idx,
718a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg1_idx);
719a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
720a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	if (res) {
721a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
722051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return -1;
723051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
724051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
725051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
726051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
727051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
728051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
729cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
730051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
731051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
732051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
733cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
734cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
735cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
736cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
737051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (success) {
738051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Complete iface/ap configuration */
739cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		set_dfs_state(iface, freq, ht_enabled, chan_offset,
740051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      chan_width, cf1, cf2,
741051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      HOSTAPD_CHAN_DFS_AVAILABLE);
742cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->cac_started = 0;
743cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_setup_interface_complete(iface, 0);
744051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
745051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
746051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
747051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
748051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
749051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
751051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
752051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int secondary_channel;
75496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx = 0;
75596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx = 0;
75604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
757051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int err = 1;
75804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
75904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Radar detected during active CAC */
76004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->cac_started = 0;
76104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
76204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
76304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
76404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
76504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
76604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
76704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "No valid channel available");
76804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_setup_interface_complete(iface, err);
76904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
77204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
77304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
77404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
77504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
77604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
77704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
77804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->freq = channel->freq;
77904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->channel = channel->chan;
78004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->secondary_channel = secondary_channel;
78104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg0_idx =
78204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg0_idx;
78304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg1_idx =
78404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg1_idx;
78504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = 0;
78604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
78704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	hostapd_setup_interface_complete(iface, err);
78804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return err;
78904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
79004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
79104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
792d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtstatic int hostapd_csa_in_progress(struct hostapd_iface *iface)
793d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{
794d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	unsigned int i;
795d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	for (i = 0; i < iface->num_bss; i++)
796d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (iface->bss[i]->csa_in_progress)
797d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			return 1;
798d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	return 0;
799d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt}
800d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
801d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
80204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
80304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
80404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct hostapd_channel_data *channel;
805cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int secondary_channel;
806cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx;
807cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx;
80804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 1;
80904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct csa_settings csa_settings;
810d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	unsigned int i;
81104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int err = 1;
81204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
813344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
814344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		   __func__, iface->cac_started ? "yes" : "no",
815d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		   hostapd_csa_in_progress(iface) ? "yes" : "no");
816344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
817344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	/* Check if CSA in progress */
818d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (hostapd_csa_in_progress(iface))
819344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		return 0;
820051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
82104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Check if active CAC */
82204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (iface->cac_started)
82304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return hostapd_dfs_start_channel_switch_cac(iface);
82404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
82504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Perform channel switch/CSA */
826cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
827cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
82804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
82904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
83004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
83104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
8329866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		/*
8339866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * If there is no channel to switch immediately to, check if
8349866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * there is another channel where we can switch even if it
8359866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * requires to perform a CAC first.
8369866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 */
8379866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		skip_radar = 0;
8389866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		channel = dfs_get_valid_channel(iface, &secondary_channel,
8399866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg0_idx,
8409866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg1_idx,
8419866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						skip_radar);
8429866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!channel) {
8439866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			/* FIXME: Wait for channel(s) to become available */
8449866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			hostapd_disable_iface(iface);
8459866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return err;
8469866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
8479866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
8489866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->freq = channel->freq;
8499866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->channel = channel->chan;
8509866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
8519866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
8529866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
8539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
8549866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
8559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
85604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
8579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		hostapd_enable_iface(iface);
8589866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 0;
85904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
86004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
86104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
86204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
86304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
86404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
86504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
86604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
86704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Setup CSA request */
86804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_memset(&csa_settings, 0, sizeof(csa_settings));
86904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.cs_count = 5;
87004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.block_tx = 1;
87104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = hostapd_set_freq_params(&csa_settings.freq_params,
87204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->hw_mode,
87304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->freq,
87404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->chan,
87504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211n,
87604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211ac,
87704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      secondary_channel,
87804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->vht_oper_chwidth,
87904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg0_idx,
88004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg1_idx,
88104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->current_mode->vht_capab);
88204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
88304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
88404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
88504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
88604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
88704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
888cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
889d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	for (i = 0; i < iface->num_bss; i++) {
890d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
891d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (err)
892d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			break;
893d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	}
894d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
89504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
89604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
89704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			   err);
898cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq = channel->freq;
899cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->channel = channel->chan;
900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
901cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
902cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
903cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
904cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
905051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
906cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_disable_iface(iface);
90704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_enable_iface(iface);
90804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
90968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
910051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
91104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Channel configuration will be updated once CSA completes and
91204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * ch_switch_notify event is received */
91304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
91404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
915051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
916051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
917051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
918051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
919cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
920051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int ht_enabled, int chan_offset, int chan_width,
921051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int cf1, int cf2)
922051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
923051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res;
924051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
925cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211h)
926051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
927051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
928cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
929cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
930cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
931cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
932051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* mark radar frequency as invalid */
9336aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
9346aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
935051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
936051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Skip if reported radar event not overlapped our channels */
937cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
938051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!res)
939051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
940051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
941051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* radar detected while operating, switch the channel. */
942cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = hostapd_dfs_start_channel_switch(iface);
943051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
944051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
945051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
946051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
947051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
948cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
949051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
950051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
951051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
952cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
953cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
954cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
955051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* TODO add correct implementation here */
956cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
957cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
958051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
959051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
960f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
961f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
962f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface)
963f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
964a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
965f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
96661593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	if (!iface->conf->ieee80211h || !iface->current_mode ||
96761593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
96861593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt		return 0;
969f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
970f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get start (first) channel for current configuration */
971a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
972f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (start_chan_idx == -1)
973f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
974f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
975f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get number of used channels, depend on width */
976a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
977f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
978f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Check if any of configured channels require DFS */
979a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
980a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (res)
981a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		return res;
982a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (start_chan_idx1 >= 0 && n_chans1 > 0)
983a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
984a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	return res;
985f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
986