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