1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection
3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * Copyright (c) 2013-2017, 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"
147f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#include "common/hw_features_common.h"
15cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h"
16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h"
17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h"
18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h"
19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h"
20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
21051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
22a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1;
25051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
26a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	*seg1 = 0;
27a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
29051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
31cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
32cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 4;
37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 8;
40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
41a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		case VHT_CHANWIDTH_80P80MHZ:
42a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			n_chans = 4;
43a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			*seg1 = 4;
44a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			break;
45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return n_chans;
51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan,
5504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				 int skip_radar)
56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/*
5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * When radar detection happens, CSA is performed. However, there's no
5904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * time for CAC, so radar channels must be skipped when finding a new
609866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	 * channel for CSA, unless they are available for immediate use.
6104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 */
629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
649866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	     HOSTAPD_CHAN_DFS_AVAILABLE))
6504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
6604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (chan->flag & HOSTAPD_CHAN_DISABLED)
68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 1;
74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
76051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
78051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * The tables contain first valid channel number based on channel width.
8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * We will also choose this first channel as the control one.
8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
8468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			     184, 192 };
8568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * VHT80, valid channels based on center frequency:
8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * 42, 58, 106, 122, 138, 155
8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
90f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
91f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * VHT160 valid channels based on center frequency:
92f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * 50, 114
93f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
94f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int allowed_160[] = { 36, 100 };
9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int *allowed = allowed_40;
9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	unsigned int i, allowed_no = 0;
9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (n_chans) {
9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 2:
10068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_40;
10168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_40);
10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 4:
10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_80;
10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_80);
10668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
107f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case 8:
108f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed = allowed_160;
109f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_160);
110f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
11168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
11268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
11368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
11468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
11668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	for (i = 0; i < allowed_no; i++) {
117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == allowed[i])
118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
124051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
125dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidtstatic struct hostapd_channel_data *
126dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidtdfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
127dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt{
128dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	int i;
129dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt
130dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	for (i = first_chan_idx; i < mode->num_channels; i++) {
131dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		if (mode->channels[i].freq == freq)
132dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt			return &mode->channels[i];
133dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	}
134dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt
135dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	return NULL;
136dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt}
137dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt
138dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt
139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode,
14004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int first_chan_idx, int num_chans,
14104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int skip_radar)
142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *first_chan, *chan;
144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i;
145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
146dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	if (first_chan_idx + num_chans > mode->num_channels)
147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return 0;
148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	first_chan = &mode->channels[first_chan_idx];
150cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
151cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < num_chans; i++) {
152dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
153dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt					 first_chan_idx);
154dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		if (!chan)
155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
156cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
15704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_channel_available(chan, skip_radar))
158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
159cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
160cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
161cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	return 1;
162cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
163cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
1659866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface,
1669866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			  struct hostapd_channel_data *chan)
1679866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{
168dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	if (!iface->conf->acs_ch_list.num)
1699866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 1;
1709866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
171dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
1729866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt}
1739866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1749866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
175cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/*
176cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation.
177cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this:
178cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->secondary_channel
179cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg0_idx
180cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg1_idx
181cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */
182cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface,
183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    struct hostapd_channel_data **ret_chan,
18404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			    int idx, int skip_radar)
185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
187cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *chan;
188a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int i, channel_idx = 0, n_chans, n_chans1;
189051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
191a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
192051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
197cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip HT40/VHT incompatible channels */
198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (iface->conf->ieee80211n &&
199cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    iface->conf->secondary_channel &&
200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    !dfs_is_chan_allowed(chan, n_chans))
201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			continue;
202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip incompatible chandefs */
20404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
205cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			continue;
206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
2079866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!is_in_chanlist(iface, chan))
2089866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			continue;
2099866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (ret_chan && idx == channel_idx) {
211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			*ret_chan = chan;
213051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return idx;
214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_idx++;
217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return channel_idx;
219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
223cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       struct hostapd_channel_data *chan,
224344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				       int secondary_channel,
225cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg0_idx,
226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg1_idx)
227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211ac)
229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!chan)
232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
235cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
236cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	switch (iface->conf->vht_oper_chwidth) {
237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_USE_HT:
238344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		if (secondary_channel == 1)
239cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
240344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else if (secondary_channel == -1)
241cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
24268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		else
243cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan;
244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_80MHZ:
246cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_160MHZ:
249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
25068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
2537d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = 0;
254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
257cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
258cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg0_idx,
259cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg1_idx);
260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */
264a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
268cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int channel_no = iface->conf->channel;
269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = -1, i;
270a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int chan_seg1 = -1;
271a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
272a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	*seg1_start = -1;
273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* HT40- */
275cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_no -= 4;
277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* VHT */
279cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
280cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
285cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
289cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
291a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		case VHT_CHANWIDTH_80P80MHZ:
292a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			channel_no =
293a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
294a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			chan_seg1 =
295a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				iface->conf->vht_oper_centr_freq_seg1_idx - 6;
296a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			break;
297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_INFO,
299a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				   "DFS only VHT20/40/80/160/80+80 is supported now");
300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no = -1;
301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Get idx */
306cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == channel_no) {
310051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res = i;
311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
315a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (res != -1 && chan_seg1 > -1) {
316a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		int found = 0;
317a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
318a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		/* Get idx for seg1 */
319a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		mode = iface->current_mode;
320a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		for (i = 0; i < mode->num_channels; i++) {
321a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			chan = &mode->channels[i];
322a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			if (chan->chan == chan_seg1) {
323a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				*seg1_start = i;
324a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				found = 1;
325a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt				break;
326a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			}
327a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		}
328a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		if (!found)
329a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			res = -1;
330a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	}
331a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
3329866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (res == -1) {
3339866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		wpa_printf(MSG_DEBUG,
3349866086a955d00e237cc8df3722e7dff75c02532Dmitry 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",
3359866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   mode->num_channels, channel_no, iface->conf->channel,
3369866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->ieee80211n,
3379866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->secondary_channel,
3389866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			   iface->conf->vht_oper_chwidth);
3399866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
3409866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		for (i = 0; i < mode->num_channels; i++) {
3419866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Available channel: %d",
3429866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt				   mode->channels[i].chan);
3439866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
3449866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */
351cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface,
352cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				 int start_chan_idx, int n_chans)
353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_RADAR)
363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */
371cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface,
372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				     int start_chan_idx, int n_chans)
373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
378cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
380f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
382f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
383f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
384f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			break;
385f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
386f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
387f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
388f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
390051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_AVAILABLE)
391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return i == n_chans;
395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */
399cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface,
400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int start_chan_idx,
401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int n_chans)
402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
407cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
409f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
422cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data *
423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface,
424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      int *secondary_channel,
425cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg0_idx,
42604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg1_idx,
42704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      int skip_radar)
428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
431cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int num_available_chandefs;
432cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int chan_idx;
433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u32 _rand;
434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
4367d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*secondary_channel = 0;
4377d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg0_idx = 0;
4387d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
440cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->current_mode == NULL)
441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
443cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
447cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* Get the count first */
44804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
449cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (num_available_chandefs == 0)
450cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return NULL;
451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
45357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		return NULL;
454cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	chan_idx = _rand % num_available_chandefs;
45504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
456cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
457cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* dfs_find_channel() calculations assume HT40+ */
458cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->secondary_channel)
459cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 1;
460cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	else
461cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 0;
462cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
463cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	dfs_adjust_vht_center_freq(iface, chan,
464344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				   *secondary_channel,
465cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg0_idx,
466cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg1_idx);
467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return chan;
469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
472cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
478cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
483cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < iface->current_mode->num_channels; i++) {
484cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &iface->current_mode->channels[i];
485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->freq == freq) {
486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->flag & HOSTAPD_CHAN_RADAR) {
487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag |= state;
489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return 1; /* Channel found */
490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
498cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int chan_offset, int chan_width, int cf1,
500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int cf2, u32 state)
501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1, i;
503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int frequency = freq;
505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int ret = 0;
506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
507cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Seems cf1 and chan_width is enough here */
517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 1;
521cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
522cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 4;
530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 8;
534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		   n_chans);
544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
545cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		ret += set_dfs_state_freq(iface, frequency, state);
546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = frequency + 20;
547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return ret;
550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
553cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int chan_width, int cf1, int cf2)
555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
556a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int start_chan_idx, start_chan_idx1;
557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
559a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u8 radar_chan;
561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = 0;
562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Our configuration */
564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
565a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
566a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
56868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* Check we are on DFS channel(s) */
569cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
57068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return 0;
57168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Reported via radar event */
573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 1;
577cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 2;
582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 4;
586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
589051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 8;
590051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
591051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
592051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
593051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	ieee80211_freq_to_chan(frequency, &radar_chan);
599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[start_chan_idx + i];
60268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
60368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			continue;
604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		for (j = 0; j < radar_n_chans; j++) {
605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   chan->chan, radar_chan + j * 4);
607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->chan == radar_chan + j * 4)
608051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				res++;
609051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
610051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
611051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
614051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
615051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
616051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
617051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
618df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
619df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				     int start_chan_idx, int n_chans)
620df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
621df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_channel_data *channel;
622df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hostapd_hw_modes *mode;
623df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int i;
624df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	unsigned int cac_time_ms = 0;
625df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
626df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	mode = iface->current_mode;
627df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
628df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
629df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
630df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
631df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			continue;
632df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (channel->dfs_cac_ms > cac_time_ms)
633df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			cac_time_ms = channel->dfs_cac_ms;
634df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
635df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
636df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return cac_time_ms;
637df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
638df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
639df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
641051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler
642051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup
643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC
644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error
645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
646cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface)
647051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
648051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
649a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
651051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!iface->current_mode) {
6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * This can happen with drivers that do not provide mode
6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * information and as such, cannot really use hostapd for DFS.
6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 1;
6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
662cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	iface->cac_started = 0;
663cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
664051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	do {
665051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get start (first) channel for current configuration */
666a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		start_chan_idx = dfs_get_start_chan_idx(iface,
667a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt							&start_chan_idx1);
668051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (start_chan_idx == -1)
669051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return -1;
670051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
671051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get number of used channels, depend on width */
672a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		n_chans = dfs_get_used_n_chans(iface, &n_chans1);
673051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
674df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		/* Setup CAC time */
675df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
676df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						     n_chans);
677df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
678051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels require DFS */
679cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
680051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
681051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS %d channels required radar detection",
682051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res);
683051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (!res)
684051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
685051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
686051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if all channels are DFS available */
687cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
688051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
689051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS all channels available, (SKIP CAC): %s",
690051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res ? "yes" : "no");
691051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res)
692051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
693051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
694051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels is unavailable */
695cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_unavailable(iface, start_chan_idx,
696051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt						  n_chans);
697051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
698051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res, res ? "yes": "no");
699051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res) {
70096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			int sec = 0;
70196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			u8 cf1 = 0, cf2 = 0;
702cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt							skip_radar);
705051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (!channel) {
706051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				wpa_printf(MSG_ERROR, "could not get valid channel");
70731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				hostapd_set_state(iface, HAPD_IFACE_DFS);
70831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				return 0;
709051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
710cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
711cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->freq = channel->freq;
712cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->channel = channel->chan;
713cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->secondary_channel = sec;
714cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
715cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
716051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
717051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	} while (res);
718051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
719051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Finally start CAC */
720cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	hostapd_set_state(iface, HAPD_IFACE_DFS);
721cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
722cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
723df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
724cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq,
725a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->channel, iface->conf->secondary_channel,
726a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_chwidth,
727a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx,
728df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx,
729df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		iface->dfs_cac_ms / 1000);
730a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
731a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
732a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->freq,
733a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->channel,
734a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211n,
735a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->ieee80211ac,
736a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->secondary_channel,
737a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_chwidth,
738a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg0_idx,
739a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				    iface->conf->vht_oper_centr_freq_seg1_idx);
740a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
741a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	if (res) {
742a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
743051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return -1;
744051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
745051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
746051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
747051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
748051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
749051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
750d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtstatic int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
751d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{
752d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
753d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
754d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	/* Get the start (first) channel for current configuration */
755d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
756d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	if (start_chan_idx < 0)
757d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		return 0;
758d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
759d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	/* Get the number of used channels, depending on width */
760d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
761d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
762d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	/* Check if all channels are DFS available */
763d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return dfs_check_chans_available(iface, start_chan_idx, n_chans);
764d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}
765d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
766d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
767cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
768051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
769051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
770051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
771cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
772cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
773cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
774cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
775051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (success) {
776051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Complete iface/ap configuration */
777203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
778203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			/* Complete AP configuration for the first bring up. */
779203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			if (iface->state != HAPD_IFACE_ENABLED)
780203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt				hostapd_setup_interface_complete(iface, 0);
781203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			else
782203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt				iface->cac_started = 0;
783203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		} else {
784203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			set_dfs_state(iface, freq, ht_enabled, chan_offset,
785203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt				      chan_width, cf1, cf2,
786203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt				      HOSTAPD_CHAN_DFS_AVAILABLE);
787d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			/*
788d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * Just mark the channel available when CAC completion
789d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * event is received in enabled state. CAC result could
790d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * have been propagated from another radio having the
791d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * same regulatory configuration. When CAC completion is
792d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * received during non-HAPD_IFACE_ENABLED state, make
793d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * sure the configured channel is available because this
794d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * CAC completion event could have been propagated from
795d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 * another radio.
796d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			 */
797d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			if (iface->state != HAPD_IFACE_ENABLED &&
798d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			    hostapd_config_dfs_chan_available(iface)) {
799d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				hostapd_setup_interface_complete(iface, 0);
800d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				iface->cac_started = 0;
801d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			}
802203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		}
803051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
804051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
805051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
806051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
807051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
808051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
809d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtint hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
810d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				int ht_enabled, int chan_offset, int chan_width,
811d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				int cf1, int cf2)
812d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{
813d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
814d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
815d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
816d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
817d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	/* Proceed only if DFS is not offloaded to the driver */
818d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
819d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		return 0;
820d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
821d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
822d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
823d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
824d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return 0;
825d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}
826d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
827d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
82804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
829051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
830051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
83104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int secondary_channel;
83296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx = 0;
83396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx = 0;
83404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
835051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int err = 1;
83604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
83704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Radar detected during active CAC */
83804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->cac_started = 0;
83904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
84004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
84104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
84204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
84304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
84404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
84504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "No valid channel available");
84604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
84704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
84804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
84904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
85004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
85104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
85204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
85304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
85404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
85504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->freq = channel->freq;
85604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->channel = channel->chan;
85704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->secondary_channel = secondary_channel;
85804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg0_idx =
85904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg0_idx;
86004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg1_idx =
86104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg1_idx;
86204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = 0;
86304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
86404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	hostapd_setup_interface_complete(iface, err);
86504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return err;
86604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
86704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
86804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
86904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
87004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
87104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct hostapd_channel_data *channel;
872cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int secondary_channel;
873cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx;
874cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx;
87504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 1;
87604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct csa_settings csa_settings;
877d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	unsigned int i;
87804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int err = 1;
87904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
880344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
881344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		   __func__, iface->cac_started ? "yes" : "no",
882d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		   hostapd_csa_in_progress(iface) ? "yes" : "no");
883344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
884344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	/* Check if CSA in progress */
885d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (hostapd_csa_in_progress(iface))
886344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		return 0;
887051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
88804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Check if active CAC */
88904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (iface->cac_started)
89004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return hostapd_dfs_start_channel_switch_cac(iface);
89104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
892d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	/*
893d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	 * Allow selection of DFS channel in ETSI to comply with
894d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	 * uniform spreading.
895d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	 */
896d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
897d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		skip_radar = 0;
898d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
89904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Perform channel switch/CSA */
900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
901cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
90204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
90304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
90404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
90504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
9069866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		/*
9079866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * If there is no channel to switch immediately to, check if
9089866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * there is another channel where we can switch even if it
9099866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 * requires to perform a CAC first.
9109866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		 */
9119866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		skip_radar = 0;
9129866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		channel = dfs_get_valid_channel(iface, &secondary_channel,
9139866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg0_idx,
9149866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						&vht_oper_centr_freq_seg1_idx,
9159866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt						skip_radar);
9169866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (!channel) {
91731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			wpa_printf(MSG_INFO,
91831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				   "%s: no DFS channels left, waiting for NOP to finish",
91931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				   __func__);
9209866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return err;
9219866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		}
9229866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
9239866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->freq = channel->freq;
9249866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->channel = channel->chan;
9259866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
9269866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
9279866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
9289866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
9299866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
9309866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
93104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
9329866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		hostapd_enable_iface(iface);
9339866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 0;
93404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
93504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
93604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
93704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
93804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
93904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
94004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
94104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
94204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Setup CSA request */
94304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_memset(&csa_settings, 0, sizeof(csa_settings));
94404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.cs_count = 5;
94504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.block_tx = 1;
94604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = hostapd_set_freq_params(&csa_settings.freq_params,
94704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->hw_mode,
94804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->freq,
94904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->chan,
95004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211n,
95104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211ac,
95204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      secondary_channel,
95304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->vht_oper_chwidth,
95404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg0_idx,
95504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg1_idx,
95604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->current_mode->vht_capab);
95704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
95804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
95904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
96004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
96104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
96204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
963cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
964d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	for (i = 0; i < iface->num_bss; i++) {
965d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
966d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (err)
967d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			break;
968d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	}
969d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
97004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
97104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
97204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			   err);
973cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq = channel->freq;
974cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->channel = channel->chan;
975cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
976cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
977cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
978cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
979cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
980051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
981cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_disable_iface(iface);
98204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_enable_iface(iface);
98304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
98468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
985051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
98604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Channel configuration will be updated once CSA completes and
98704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * ch_switch_notify event is received */
98804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
98904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
990051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
991051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
992051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
993051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
994cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
995051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int ht_enabled, int chan_offset, int chan_width,
996051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int cf1, int cf2)
997051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
998051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res;
999051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1000cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
1001cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1002cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1003cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
1004203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	/* Proceed only if DFS is not offloaded to the driver */
1005203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1006203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 0;
1007203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1008203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (!iface->conf->ieee80211h)
1009203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 0;
1010203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1011051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* mark radar frequency as invalid */
10126aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
10136aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
1014051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1015051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Skip if reported radar event not overlapped our channels */
1016cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
1017051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!res)
1018051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
1019051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1020051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* radar detected while operating, switch the channel. */
1021cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = hostapd_dfs_start_channel_switch(iface);
1022051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1023051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
1024051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
1025051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1026051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
1027cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
1028051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
1029051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
1030051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
1031cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
1032cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1033cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1034203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1035203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	/* Proceed only if DFS is not offloaded to the driver */
1036203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1037203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 0;
1038203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1039051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* TODO add correct implementation here */
1040cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1041cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
104231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
104331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	/* Handle cases where all channels were initially unavailable */
104431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
104531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		hostapd_handle_dfs(iface);
104631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
1047051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
1048051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
1049f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1050f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1051f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface)
1052f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
1053a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
1054f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
105561593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	if (!iface->conf->ieee80211h || !iface->current_mode ||
105661593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
105761593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt		return 0;
1058f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1059f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get start (first) channel for current configuration */
1060a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
1061f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (start_chan_idx == -1)
1062f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
1063f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1064f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get number of used channels, depend on width */
1065a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
1066f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
1067f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Check if any of configured channels require DFS */
1068a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1069a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (res)
1070a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		return res;
1071a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	if (start_chan_idx1 >= 0 && n_chans1 > 0)
1072a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1073a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	return res;
1074f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
1075203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1076203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1077203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtint hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
1078203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			  int ht_enabled, int chan_offset, int chan_width,
1079203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			  int cf1, int cf2)
1080203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{
1081203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1082203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1083203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		"seg1=%d cac_time=%ds",
1084203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
1085203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	iface->cac_started = 1;
1086203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	return 0;
1087203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt}
1088203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1089203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1090203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt/*
1091203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * Main DFS handler for offloaded case.
1092203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 2 - continue channel/AP setup for non-DFS channel
1093203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 1 - continue channel/AP setup for DFS channel
1094203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 0 - channel/AP setup will be continued after CAC
1095203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * -1 - hit critical error
1096203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt */
1097203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtint hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1098203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{
1099203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1100203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		   __func__, iface->cac_started);
1101203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1102203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	/*
1103203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * If DFS has already been started, then we are being called from a
1104203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * callback to continue AP/channel setup. Reset the CAC start flag and
1105203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * return.
1106203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 */
1107203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (iface->cac_started) {
1108203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1109203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			   __func__, iface->cac_started);
1110203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		iface->cac_started = 0;
1111203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 1;
1112203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	}
1113203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1114203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (ieee80211_is_dfs(iface->freq)) {
1115203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
1116203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			   __func__, iface->freq);
1117203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 0;
1118203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	}
1119203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
1120203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	wpa_printf(MSG_DEBUG,
1121203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		   "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1122203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		   __func__, iface->freq);
1123203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	return 2;
1124203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt}
1125