1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection 3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * Copyright (c) 2013-2015, Qualcomm Atheros, Inc. 5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details. 8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h" 11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h" 13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h" 147f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#include "common/hw_features_common.h" 15cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h" 16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h" 17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h" 18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h" 19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h" 20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 21051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 22a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) 23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1; 25051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 26a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt *seg1 = 0; 27a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt 28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel) 29051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 31cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 32cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 41a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt case VHT_CHANWIDTH_80P80MHZ: 42a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt n_chans = 4; 43a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt *seg1 = 4; 44a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt break; 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return n_chans; 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan, 5504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* 5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * When radar detection happens, CSA is performed. However, there's no 5904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * time for CAC, so radar channels must be skipped when finding a new 609866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * channel for CSA, unless they are available for immediate use. 6104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt */ 629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) && 639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) != 649866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE)) 6504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 6604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((chan->flag & HOSTAPD_CHAN_RADAR) && 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE)) 72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 76051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) 78051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * The tables contain first valid channel number based on channel width. 8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * We will also choose this first channel as the control one. 8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 8368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 8468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 184, 192 }; 8568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * VHT80, valid channels based on center frequency: 8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * 42, 58, 106, 122, 138, 155 8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_80[] = { 36, 52, 100, 116, 132, 149 }; 90f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* 91f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * VHT160 valid channels based on center frequency: 92f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * 50, 114 93f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt */ 94f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int allowed_160[] = { 36, 100 }; 9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int *allowed = allowed_40; 9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt unsigned int i, allowed_no = 0; 9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt switch (n_chans) { 9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 2: 10068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_40; 10168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_40); 10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 4: 10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_80; 10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_80); 10668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 107f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 8: 108f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed = allowed_160; 109f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_160); 110f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 11168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt default: 11268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 11368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 11468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 11668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (i = 0; i < allowed_no; i++) { 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 124051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 125dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidtstatic struct hostapd_channel_data * 126dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidtdfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx) 127dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt{ 128dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt int i; 129dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt 130dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt for (i = first_chan_idx; i < mode->num_channels; i++) { 131dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (mode->channels[i].freq == freq) 132dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt return &mode->channels[i]; 133dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt } 134dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt 135dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt return NULL; 136dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt} 137dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt 138dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt 139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode, 14004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int first_chan_idx, int num_chans, 14104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *first_chan, *chan; 144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i; 145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 146dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (first_chan_idx + num_chans > mode->num_channels) 147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt first_chan = &mode->channels[first_chan_idx]; 150cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 151cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < num_chans; i++) { 152dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt chan = dfs_get_chan_data(mode, first_chan->freq + i * 20, 153dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt first_chan_idx); 154dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (!chan) 155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 156cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 15704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_channel_available(chan, skip_radar)) 158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 159cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 160cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 161cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 1; 162cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 163cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 1659866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface, 1669866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt struct hostapd_channel_data *chan) 1679866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{ 168dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (!iface->conf->acs_ch_list.num) 1699866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 1; 1709866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 171dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan); 1729866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt} 1739866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 1749866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 175cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/* 176cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation. 177cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this: 178cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->secondary_channel 179cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg0_idx 180cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg1_idx 181cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */ 182cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface, 183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 18404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int idx, int skip_radar) 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 187cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan; 188a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int i, channel_idx = 0, n_chans, n_chans1; 189051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 191a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt n_chans = dfs_get_used_n_chans(iface, &n_chans1); 192051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 197cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip HT40/VHT incompatible channels */ 198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && 199cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel && 200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt !dfs_is_chan_allowed(chan, n_chans)) 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip incompatible chandefs */ 20404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) 205cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 2079866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (!is_in_chanlist(iface, chan)) 2089866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt continue; 2099866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 213051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, 223cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan, 224344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt int secondary_channel, 225cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 235cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 236cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 238344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (secondary_channel == 1) 239cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 240344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt else if (secondary_channel == -1) 241cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 24268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 243cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 246cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 25068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 2537d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 257cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 258cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 259cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 264a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start) 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 268cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 270a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int chan_seg1 = -1; 271a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt 272a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt *seg1_start = -1; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 275cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 279cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 280cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 285cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 289cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 291a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt case VHT_CHANWIDTH_80P80MHZ: 292a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt channel_no = 293a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 294a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt chan_seg1 = 295a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx - 6; 296a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt break; 297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 299a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt "DFS only VHT20/40/80/160/80+80 is supported now"); 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 306cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 310051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 315a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt if (res != -1 && chan_seg1 > -1) { 316a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int found = 0; 317a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt 318a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt /* Get idx for seg1 */ 319a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt mode = iface->current_mode; 320a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 321a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt chan = &mode->channels[i]; 322a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt if (chan->chan == chan_seg1) { 323a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt *seg1_start = i; 324a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt found = 1; 325a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt break; 326a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt } 327a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt } 328a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt if (!found) 329a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt res = -1; 330a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt } 331a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt 3329866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (res == -1) { 3339866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt wpa_printf(MSG_DEBUG, 3349866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d", 3359866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt mode->num_channels, channel_no, iface->conf->channel, 3369866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->ieee80211n, 3379866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->secondary_channel, 3389866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_chwidth); 3399866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 3409866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 3419866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt wpa_printf(MSG_DEBUG, "Available channel: %d", 3429866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt mode->channels[i].chan); 3439866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 3449866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 351cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 352cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 371cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 378cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 380f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 382f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 383f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 384f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 385f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 386f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 387f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 388f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 390051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 399cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 407cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 409f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 422cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 425cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 42604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 42704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 431cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 432cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 4367d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *secondary_channel = 0; 4377d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 4387d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 440cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 443cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 447cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 44804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 449cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 450cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) 4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt _rand = os_random(); 454cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 45504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 456cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 457cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 458cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 459cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 460cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 461cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 462cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 463cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 464344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt *secondary_channel, 465cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 466cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 472cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 478cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 483cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 484cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 498cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 507cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 521cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 522cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 545cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 553cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 556a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int start_chan_idx, start_chan_idx1; 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 559a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1; 560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 565a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); 566a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt n_chans = dfs_get_used_n_chans(iface, &n_chans1); 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 56868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 569cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 57068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 57168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 577cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 589051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 590051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 591051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 592051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 593051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 60268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 60368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 608051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 609051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 610051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 611051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 614051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 615051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 616051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 617051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 618df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic unsigned int dfs_get_cac_time(struct hostapd_iface *iface, 619df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int start_chan_idx, int n_chans) 620df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{ 621df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt struct hostapd_channel_data *channel; 622df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt struct hostapd_hw_modes *mode; 623df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int i; 624df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt unsigned int cac_time_ms = 0; 625df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 626df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt mode = iface->current_mode; 627df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 628df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt for (i = 0; i < n_chans; i++) { 629df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 630df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 631df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt continue; 632df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (channel->dfs_cac_ms > cac_time_ms) 633df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt cac_time_ms = channel->dfs_cac_ms; 634df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt } 635df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 636df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return cac_time_ms; 637df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt} 638df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 639df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 641051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 642051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 646cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 647051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 648051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 649a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1; 65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 651051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!iface->current_mode) { 6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This can happen with drivers that do not provide mode 6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * information and as such, cannot really use hostapd for DFS. 6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, 6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "DFS: No current_mode information - assume no need to perform DFS operations by hostapd"); 6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 1; 6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 662cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 663cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 664051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 665051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 666a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface, 667a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt &start_chan_idx1); 668051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 669051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 670051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 671051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 672a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt n_chans = dfs_get_used_n_chans(iface, &n_chans1); 673051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 674df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt /* Setup CAC time */ 675df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx, 676df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt n_chans); 677df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 678051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 679cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 680051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 681051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 682051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 683051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 684051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 685051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 686051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 687cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 688051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 689051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 690051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 691051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 692051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 693051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 694051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 695cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 696051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 697051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 698051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 699051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 70096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt int sec = 0; 70196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 cf1 = 0, cf2 = 0; 702cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 705051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 706051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 707051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 708051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 709cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 710cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 711cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 712cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 713cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 714cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 715051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 716051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 717051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 718051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 719cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 720cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 721cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 722df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", 723cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 724a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel, 725a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_chwidth, 726a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 727df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx, 728df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->dfs_cac_ms / 1000); 729a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt 730a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 731a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->freq, 732a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->channel, 733a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->ieee80211n, 734a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->ieee80211ac, 735a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->secondary_channel, 736a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_chwidth, 737a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 738a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx); 739a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt 740a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt if (res) { 741a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); 742051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 743051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 744051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 745051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 746051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 747051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 748051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 749cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 750051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 751051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 752051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 753cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 754cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 755cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 756cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 757051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 758051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 759203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 760203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt /* Complete AP configuration for the first bring up. */ 761203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (iface->state != HAPD_IFACE_ENABLED) 762203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt hostapd_setup_interface_complete(iface, 0); 763203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt else 764203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt iface->cac_started = 0; 765203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt } else { 766203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 767203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt chan_width, cf1, cf2, 768203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 769203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt iface->cac_started = 0; 770203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt hostapd_setup_interface_complete(iface, 0); 771203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt } 772051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 773051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 774051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 775051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 776051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 777051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 77804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 780051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 78104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 78296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg0_idx = 0; 78396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg1_idx = 0; 78404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 78604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 78704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 78804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 78904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 79004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 79104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 79204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 79304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 79404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 79504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 79604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 79704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 79804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 79904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 80004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 80104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 80204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 80304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 80404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 80504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 80604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 80704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 80804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 80904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 81004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 81104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 81204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 81304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 81404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 81504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 81604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 81704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 81804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 81904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 820d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtstatic int hostapd_csa_in_progress(struct hostapd_iface *iface) 821d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{ 822d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt unsigned int i; 823d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt for (i = 0; i < iface->num_bss; i++) 824d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (iface->bss[i]->csa_in_progress) 825d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return 1; 826d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return 0; 827d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt} 828d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 829d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 83004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 83104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 83204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 833cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 834cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 835cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 83604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 83704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 838d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt unsigned int i; 83904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 84004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 841344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 842344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt __func__, iface->cac_started ? "yes" : "no", 843d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt hostapd_csa_in_progress(iface) ? "yes" : "no"); 844344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt 845344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt /* Check if CSA in progress */ 846d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (hostapd_csa_in_progress(iface)) 847344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt return 0; 848051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 84904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 85004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 85104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 85204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 85304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 854cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 855cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 85604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 85704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 85804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 85904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 8609866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt /* 8619866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * If there is no channel to switch immediately to, check if 8629866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * there is another channel where we can switch even if it 8639866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * requires to perform a CAC first. 8649866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt */ 8659866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt skip_radar = 0; 8669866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 8679866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 8689866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 8699866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt skip_radar); 8709866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (!channel) { 8719866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 8729866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt hostapd_disable_iface(iface); 8739866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return err; 8749866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 8759866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 8769866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->freq = channel->freq; 8779866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->channel = channel->chan; 8789866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 8799866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 8809866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 8819866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 8829866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 8839866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 88404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 8859866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt hostapd_enable_iface(iface); 8869866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 0; 88704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 88804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 88904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 89004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 89104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 89204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 89304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 89404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 89504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 89604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 89704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 89804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 89904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 90004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 90104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 90204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 90304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 90404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 90504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 90604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 90704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 90804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 90904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 91004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 91104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 91204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 91304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 91404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 91504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 916cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 917d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt for (i = 0; i < iface->num_bss; i++) { 918d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt err = hostapd_switch_channel(iface->bss[i], &csa_settings); 919d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (err) 920d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt break; 921d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt } 922d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 92304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 92404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 92504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 926cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 927cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 928cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 929cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 930cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 931cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 932cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 933051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 934cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 93504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 93604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 93768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 938051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 93904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 94004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 94104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 94204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 943051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 944051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 945051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 946051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 947cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 948051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 949051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 950051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 951051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 952051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 953cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 954cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 955cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 956cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 957203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt /* Proceed only if DFS is not offloaded to the driver */ 958203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) 959203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 0; 960203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 961203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (!iface->conf->ieee80211h) 962203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 0; 963203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 964051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 9656aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 9666aa8ae4b6139bdf5593301474277dcdbc2528190Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); 967051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 968051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 969cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 970051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 971051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 972051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 973051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 974cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 975051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 976051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 977051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 978051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 979051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 980cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 981051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 982051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 983051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 984cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 985cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 986cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 987203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 988203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt /* Proceed only if DFS is not offloaded to the driver */ 989203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) 990203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 0; 991203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 992051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 993cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 994cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 995051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 996051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 997f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 998f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 999f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface) 1000f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1001a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res; 1002f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 100361593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt if (!iface->conf->ieee80211h || !iface->current_mode || 100461593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 100561593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt return 0; 1006f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1007f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get start (first) channel for current configuration */ 1008a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); 1009f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (start_chan_idx == -1) 1010f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 1011f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1012f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get number of used channels, depend on width */ 1013a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt n_chans = dfs_get_used_n_chans(iface, &n_chans1); 1014f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1015f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Check if any of configured channels require DFS */ 1016a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 1017a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt if (res) 1018a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt return res; 1019a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt if (start_chan_idx1 >= 0 && n_chans1 > 0) 1020a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1); 1021a7b06faf528d1765cc2712cc9a31ad45d7c3110bDmitry Shmidt return res; 1022f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1023203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1024203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1025203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtint hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, 1026203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 1027203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt int cf1, int cf2) 1028203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{ 1029203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 1030203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt "freq=%d chan=%d chan_offset=%d width=%d seg0=%d " 1031203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt "seg1=%d cac_time=%ds", 1032203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60); 1033203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt iface->cac_started = 1; 1034203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 0; 1035203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt} 1036203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1037203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1038203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt/* 1039203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * Main DFS handler for offloaded case. 1040203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 2 - continue channel/AP setup for non-DFS channel 1041203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 1 - continue channel/AP setup for DFS channel 1042203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * 0 - channel/AP setup will be continued after CAC 1043203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * -1 - hit critical error 1044203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt */ 1045203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtint hostapd_handle_dfs_offload(struct hostapd_iface *iface) 1046203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{ 1047203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", 1048203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt __func__, iface->cac_started); 1049203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1050203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt /* 1051203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * If DFS has already been started, then we are being called from a 1052203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * callback to continue AP/channel setup. Reset the CAC start flag and 1053203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt * return. 1054203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt */ 1055203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (iface->cac_started) { 1056203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", 1057203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt __func__, iface->cac_started); 1058203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt iface->cac_started = 0; 1059203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 1; 1060203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt } 1061203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1062203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt if (ieee80211_is_dfs(iface->freq)) { 1063203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS", 1064203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt __func__, iface->freq); 1065203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 0; 1066203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt } 1067203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt 1068203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt wpa_printf(MSG_DEBUG, 1069203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt "%s: freq %d MHz does not require DFS. Continue channel/AP setup", 1070203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt __func__, iface->freq); 1071203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt return 2; 1072203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt} 1073