dfs.c revision 7d5c8f257a74ac0d12828962a492e8b84ef83923
1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection
3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2013, Qualcomm Atheros, Inc.
5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *
6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details.
8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h"
11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h"
13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h"
14cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h"
15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h"
16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h"
17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h"
18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h"
19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
21cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface)
22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1;
24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
25cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
26051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
27051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
29cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
31051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 4;
34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 8;
37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
41051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return n_chans;
44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
4704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan,
4804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				 int skip_radar)
49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
5004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/*
5104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * When radar detection happens, CSA is performed. However, there's no
5204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * time for CAC, so radar channels must be skipped when finding a new
5304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * channel for CSA.
5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 */
5504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
5604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (chan->flag & HOSTAPD_CHAN_DISABLED)
59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 1;
65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
6868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * The tables contain first valid channel number based on channel width.
7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * We will also choose this first channel as the control one.
7368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
7468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
7568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			     184, 192 };
7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * VHT80, valid channels based on center frequency:
7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * 42, 58, 106, 122, 138, 155
7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
81f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
82f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * VHT160 valid channels based on center frequency:
83f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * 50, 114
84f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
85f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int allowed_160[] = { 36, 100 };
8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int *allowed = allowed_40;
8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	unsigned int i, allowed_no = 0;
8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (n_chans) {
9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 2:
9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_40;
9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_40);
9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 4:
9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_80;
9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_80);
9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
98f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case 8:
99f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed = allowed_160;
100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_160);
101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
10768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	for (i = 0; i < allowed_no; i++) {
108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == allowed[i])
109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
116cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode,
11704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int first_chan_idx, int num_chans,
11804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int skip_radar)
119cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
120cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *first_chan, *chan;
121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i;
122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (first_chan_idx + num_chans >= mode->num_channels)
124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return 0;
125cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	first_chan = &mode->channels[first_chan_idx];
127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < num_chans; i++) {
129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &mode->channels[first_chan_idx + i];
130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (first_chan->freq + i * 20 != chan->freq)
132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
13404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_channel_available(chan, skip_radar))
135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	return 1;
139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/*
143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation.
144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this:
145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->secondary_channel
146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg0_idx
147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *  - hapd->vht_oper_centr_freq_seg1_idx
148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */
149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface,
150051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    struct hostapd_channel_data **ret_chan,
15104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			    int idx, int skip_radar)
152051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
153051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
154cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *chan;
155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i, channel_idx = 0, n_chans;
156051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
157cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
159051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
160051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
161051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
162051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
163051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip HT40/VHT incompatible channels */
165cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (iface->conf->ieee80211n &&
166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    iface->conf->secondary_channel &&
167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		    !dfs_is_chan_allowed(chan, n_chans))
168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			continue;
169051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
170cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		/* Skip incompatible chandefs */
17104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			continue;
173051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (ret_chan && idx == channel_idx) {
175051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			*ret_chan = chan;
177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return idx;
178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_idx++;
181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
182051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return channel_idx;
183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
186cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
187cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       struct hostapd_channel_data *chan,
188344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				       int secondary_channel,
189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg0_idx,
190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				       u8 *vht_oper_centr_freq_seg1_idx)
191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
192cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211ac)
193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!chan)
196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return;
197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
199cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	switch (iface->conf->vht_oper_chwidth) {
201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_USE_HT:
202344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		if (secondary_channel == 1)
203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
204344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else if (secondary_channel == -1)
205cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
20668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		else
207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			*vht_oper_centr_freq_seg0_idx = chan->chan;
208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_80MHZ:
210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case VHT_CHANWIDTH_160MHZ:
213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
21468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
2177d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		*vht_oper_centr_freq_seg0_idx = 0;
218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg0_idx,
223cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   *vht_oper_centr_freq_seg1_idx);
224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
226051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */
228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface)
229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
232cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int channel_no = iface->conf->channel;
233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = -1, i;
234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* HT40- */
236cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel_no -= 4;
238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* VHT */
240cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
241cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
246cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 6;
247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
249051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no =
250cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				iface->conf->vht_oper_centr_freq_seg0_idx - 14;
251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_INFO,
254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   "DFS only VHT20/40/80/160 is supported now");
255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			channel_no = -1;
256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Get idx */
261cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < mode->num_channels; i++) {
263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[i];
264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == channel_no) {
265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res = i;
266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (res == -1)
271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1");
272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */
278cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface,
279cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				 int start_chan_idx, int n_chans)
280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
285cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_RADAR)
290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */
298cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface,
299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				     int start_chan_idx, int n_chans)
300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
305cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
307f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
309f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
310f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
311f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			break;
312f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
314f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			continue;
315f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
317051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_AVAILABLE)
318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return i == n_chans;
322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */
326cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface,
327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int start_chan_idx,
328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int n_chans)
329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i, res = 0;
333051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
334cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
335051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
336f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		channel = &mode->channels[start_chan_idx + i];
338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (channel->flag & HOSTAPD_CHAN_DISABLED)
339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
341051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
342051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			res++;
343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
349cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data *
350cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface,
351cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      int *secondary_channel,
352cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg0_idx,
35304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      u8 *vht_oper_centr_freq_seg1_idx,
35404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		      int skip_radar)
355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int num_available_chandefs;
359cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int chan_idx;
360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u32 _rand;
361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
3637d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*secondary_channel = 0;
3647d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg0_idx = 0;
3657d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	*vht_oper_centr_freq_seg1_idx = 0;
366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
367cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->current_mode == NULL)
368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
370cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return NULL;
373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
374cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* Get the count first */
37504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
376cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (num_available_chandefs == 0)
377cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return NULL;
378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
379cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	os_get_random((u8 *) &_rand, sizeof(_rand));
380cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	chan_idx = _rand % num_available_chandefs;
38104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
383cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	/* dfs_find_channel() calculations assume HT40+ */
384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->secondary_channel)
385cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 1;
386cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	else
387cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		*secondary_channel = 0;
388cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
389cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	dfs_adjust_vht_center_freq(iface, chan,
390344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt				   *secondary_channel,
391cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg0_idx,
392cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   vht_oper_centr_freq_seg1_idx);
393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return chan;
395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
398cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan = NULL;
402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int i;
403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
404cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
409cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < iface->current_mode->num_channels; i++) {
410cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &iface->current_mode->channels[i];
411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->freq == freq) {
412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->flag & HOSTAPD_CHAN_RADAR) {
413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				chan->flag |= state;
415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return 1; /* Channel found */
416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int chan_offset, int chan_width, int cf1,
426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			 int cf2, u32 state)
427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1, i;
429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int frequency = freq;
431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int ret = 0;
432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
433cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode == NULL)
435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Seems cf1 and chan_width is enough here */
443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 1;
447cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
448cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 4;
456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 8;
460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		   n_chans);
470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
471cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		ret += set_dfs_state_freq(iface, frequency, state);
472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = frequency + 20;
473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return ret;
476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
479cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				       int chan_width, int cf1, int cf2)
481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int start_chan_idx;
483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_hw_modes *mode;
484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *chan;
485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans, i, j, frequency = freq, radar_n_chans = 1;
486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	u8 radar_chan;
487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res = 0;
488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Our configuration */
490cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	mode = iface->current_mode;
491cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface);
492cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
49468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* Check we are on DFS channel(s) */
495cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
49668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return 0;
49768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Reported via radar event */
499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	switch (chan_width) {
500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20_NOHT:
501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_20:
502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 1;
503cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (frequency == 0)
504cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			frequency = cf1;
505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_40:
507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 2;
508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 10;
509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_80:
511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 4;
512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 30;
513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	case CHAN_WIDTH_160:
515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		radar_n_chans = 8;
516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		frequency = cf1 - 70;
517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	default:
519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   chan_width);
521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		break;
522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	ieee80211_freq_to_chan(frequency, &radar_chan);
525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	for (i = 0; i < n_chans; i++) {
527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		chan = &mode->channels[start_chan_idx + i];
52868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
52968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			continue;
530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		for (j = 0; j < radar_n_chans; j++) {
531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				   chan->chan, radar_chan + j * 4);
533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (chan->chan == radar_chan + j * 4)
534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				res++;
535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler
546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup
547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC
548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error
549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
550cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface)
551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res, n_chans, start_chan_idx;
55404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
556cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	iface->cac_started = 0;
557cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	do {
559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get start (first) channel for current configuration */
560cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		start_chan_idx = dfs_get_start_chan_idx(iface);
561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (start_chan_idx == -1)
562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return -1;
563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Get number of used channels, depend on width */
565cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		n_chans = dfs_get_used_n_chans(iface);
566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels require DFS */
568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS %d channels required radar detection",
571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res);
572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (!res)
573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if all channels are DFS available */
576cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG,
578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   "DFS all channels available, (SKIP CAC): %s",
579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res ? "yes" : "no");
580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res)
581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Check if any of configured channels is unavailable */
584cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		res = dfs_check_chans_unavailable(iface, start_chan_idx,
585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt						  n_chans);
586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			   res, res ? "yes": "no");
588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (res) {
58996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			int sec = 0;
59096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			u8 cf1 = 0, cf2 = 0;
591cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
59204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
59304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt							skip_radar);
594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			if (!channel) {
595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				wpa_printf(MSG_ERROR, "could not get valid channel");
596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt				return -1;
597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			}
598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->freq = channel->freq;
600cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->channel = channel->chan;
601cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->secondary_channel = sec;
602cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
603cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	} while (res);
606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Finally start CAC */
608cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	hostapd_set_state(iface, HAPD_IFACE_DFS);
609cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
610cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d",
612cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq,
613cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->channel, iface->conf->secondary_channel);
614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
615cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->freq,
616cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->channel,
617cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->ieee80211n,
618cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->ieee80211ac,
619cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->secondary_channel,
620cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->vht_oper_chwidth,
621cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->vht_oper_centr_freq_seg0_idx,
622cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				  iface->conf->vht_oper_centr_freq_seg1_idx)) {
623051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
624051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return -1;
625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
631cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
634051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
635cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
636cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
637cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
638cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (success) {
640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		/* Complete iface/ap configuration */
641cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		set_dfs_state(iface, freq, ht_enabled, chan_offset,
642051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      chan_width, cf1, cf2,
643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			      HOSTAPD_CHAN_DFS_AVAILABLE);
644cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->cac_started = 0;
645cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_setup_interface_complete(iface, 0);
646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
647051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
648051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
649051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
650051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
651051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
65204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
653051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
654051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	struct hostapd_channel_data *channel;
65504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int secondary_channel;
65696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx = 0;
65796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx = 0;
65804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 0;
659051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int err = 1;
66004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
66104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Radar detected during active CAC */
66204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->cac_started = 0;
66304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
66404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
66504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
66604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
66704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
66804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
66904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "No valid channel available");
67004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_setup_interface_complete(iface, err);
67104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
67204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
67304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
67404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
67504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
67604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
67704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
67804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
67904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
68004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->freq = channel->freq;
68104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->channel = channel->chan;
68204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->secondary_channel = secondary_channel;
68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg0_idx =
68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg0_idx;
68504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	iface->conf->vht_oper_centr_freq_seg1_idx =
68604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		vht_oper_centr_freq_seg1_idx;
68704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = 0;
68804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
68904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	hostapd_setup_interface_complete(iface, err);
69004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return err;
69104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
69204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
69304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
69404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
69504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
69604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct hostapd_channel_data *channel;
697cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int secondary_channel;
698cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg0_idx;
699cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	u8 vht_oper_centr_freq_seg1_idx;
70004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int skip_radar = 1;
70104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct csa_settings csa_settings;
70204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct hostapd_data *hapd = iface->bss[0];
70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	int err = 1;
70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
705344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
706344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		   __func__, iface->cac_started ? "yes" : "no",
707344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		   iface->csa_in_progress ? "yes" : "no");
708344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
709344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	/* Check if CSA in progress */
710344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	if (iface->csa_in_progress)
711344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		return 0;
712051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
71304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Check if active CAC */
71404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (iface->cac_started)
71504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return hostapd_dfs_start_channel_switch_cac(iface);
71604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Perform channel switch/CSA */
718cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	channel = dfs_get_valid_channel(iface, &secondary_channel,
719cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					&vht_oper_centr_freq_seg0_idx,
72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					&vht_oper_centr_freq_seg1_idx,
72104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					skip_radar);
72204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!channel) {
72404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		/* FIXME: Wait for channel(s) to become available */
72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		   channel->chan);
73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		"freq=%d chan=%d sec_chan=%d", channel->freq,
73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		channel->chan, secondary_channel);
73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Setup CSA request */
73604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_memset(&csa_settings, 0, sizeof(csa_settings));
73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.cs_count = 5;
73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	csa_settings.block_tx = 1;
73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = hostapd_set_freq_params(&csa_settings.freq_params,
74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->hw_mode,
74104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->freq,
74204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      channel->chan,
74304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211n,
74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->ieee80211ac,
74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      secondary_channel,
74604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->conf->vht_oper_chwidth,
74704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg0_idx,
74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      vht_oper_centr_freq_seg1_idx,
74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				      iface->current_mode->vht_capab);
75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
75204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_disable_iface(iface);
75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return err;
75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
756cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
75704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	err = hostapd_switch_channel(hapd, &csa_settings);
75804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (err) {
75904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
76004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			   err);
761cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->freq = channel->freq;
762cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->channel = channel->chan;
763cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->secondary_channel = secondary_channel;
764cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg0_idx =
765cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg0_idx;
766cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		iface->conf->vht_oper_centr_freq_seg1_idx =
767cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			vht_oper_centr_freq_seg1_idx;
768051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
769cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		hostapd_disable_iface(iface);
77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		hostapd_enable_iface(iface);
77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
77268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
773051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
77404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/* Channel configuration will be updated once CSA completes and
77504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * ch_switch_notify event is received */
77604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
77704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
778051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
780051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
781051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
782cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
783051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int ht_enabled, int chan_offset, int chan_width,
784051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			       int cf1, int cf2)
785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
786051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int res;
787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
788cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (!iface->conf->ieee80211h)
789051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
790051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
791cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
792cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
793cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
794cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
795051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* mark radar frequency as invalid */
796cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
797051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    chan_width, cf1, cf2,
798051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			    HOSTAPD_CHAN_DFS_UNAVAILABLE);
799051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
800051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* Skip if reported radar event not overlapped our channels */
801cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
802051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (!res)
803051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
804051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
805051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* radar detected while operating, switch the channel. */
806cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	res = hostapd_dfs_start_channel_switch(iface);
807051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
808051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return res;
809051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
810051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
811051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
812cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
813051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int ht_enabled, int chan_offset, int chan_width,
814051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			     int cf1, int cf2)
815051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
816cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
817cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
818cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
819051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	/* TODO add correct implementation here */
820cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
821cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
822051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
823051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
824f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
825f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
826f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface)
827f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{
828f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int n_chans, start_chan_idx;
829f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
830f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (!iface->current_mode)
831f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
832f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
833f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get start (first) channel for current configuration */
834f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	start_chan_idx = dfs_get_start_chan_idx(iface);
835f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (start_chan_idx == -1)
836f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		return -1;
837f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
838f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Get number of used channels, depend on width */
839f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	n_chans = dfs_get_used_n_chans(iface);
840f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt
841f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/* Check if any of configured channels require DFS */
842f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
843f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt}
844