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