1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/*
2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection
3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2013, Qualcomm Atheros, Inc.
5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *
6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details.
8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */
9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h"
11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h"
13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h"
14cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h"
15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h"
16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h"
17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h"
18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h"
19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
21a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	int n_chans = 1;
24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
25a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt	*seg1 = 0;
26a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt
27cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
28051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		n_chans = 2;
29051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
30cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (iface->conf->ieee80211ac) {
31cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		switch (iface->conf->vht_oper_chwidth) {
32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_USE_HT:
33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_80MHZ:
35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 4;
36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		case VHT_CHANWIDTH_160MHZ:
38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			n_chans = 8;
39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
40a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt		case VHT_CHANWIDTH_80P80MHZ:
41a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			n_chans = 4;
42a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			*seg1 = 4;
43a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt			break;
44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		default:
45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			break;
46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		}
47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return n_chans;
50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
5304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan,
5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				 int skip_radar)
55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
5604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	/*
5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * When radar detection happens, CSA is performed. However, there's no
5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 * time for CAC, so radar channels must be skipped when finding a new
599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	 * channel for CSA, unless they are available for immediate use.
6004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	 */
619866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	     HOSTAPD_CHAN_DFS_AVAILABLE))
6404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return 0;
6504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if (chan->flag & HOSTAPD_CHAN_DISABLED)
67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		return 0;
72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 1;
73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
77051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{
7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * The tables contain first valid channel number based on channel width.
8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * We will also choose this first channel as the control one.
8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
8368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			     184, 192 };
8468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
8568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * VHT80, valid channels based on center frequency:
8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * 42, 58, 106, 122, 138, 155
8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
89f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	/*
90f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * VHT160 valid channels based on center frequency:
91f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 * 50, 114
92f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	 */
93f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int allowed_160[] = { 36, 100 };
9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int *allowed = allowed_40;
9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	unsigned int i, allowed_no = 0;
9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (n_chans) {
9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 2:
9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_40;
10068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_40);
10168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case 4:
10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed = allowed_80;
10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_80);
10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
106f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	case 8:
107f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed = allowed_160;
108f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		allowed_no = ARRAY_SIZE(allowed_160);
109f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		break;
11068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
11168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
11268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
11368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
11568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	for (i = 0; i < allowed_no; i++) {
116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		if (chan->chan == allowed[i])
117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt			return 1;
118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	return 0;
121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt}
122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode,
12504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int first_chan_idx, int num_chans,
12604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				    int skip_radar)
127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	struct hostapd_channel_data *first_chan, *chan;
129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int i;
130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (first_chan_idx + num_chans >= mode->num_channels)
132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		return 0;
133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
134cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	first_chan = &mode->channels[first_chan_idx];
135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	for (i = 0; i < num_chans; i++) {
137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		chan = &mode->channels[first_chan_idx + i];
138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (first_chan->freq + i * 20 != chan->freq)
140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
14204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!dfs_channel_available(chan, skip_radar))
143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return 0;
144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	return 1;
147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
1509866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface,
1519866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			  struct hostapd_channel_data *chan)
1529866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{
1539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	int *entry;
1549866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	if (!iface->conf->chanlist)
1569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		return 1;
1579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1589866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	for (entry = iface->conf->chanlist; *entry != -1; entry++) {
1599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt		if (*entry == chan->chan)
1609866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt			return 1;
1619866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	}
1629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	return 0;
1639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt}
1649866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
1659866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt
166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/*
167