dfs.c revision d30ac604c9f6da71a0dd7f46d25be05a2a62cfbb
1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection 3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2013, Qualcomm Atheros, Inc. 5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details. 8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h" 11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h" 13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h" 14cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h" 15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h" 16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h" 17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h" 18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h" 19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 21cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface) 22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1; 24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 25cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel) 26051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 27051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 29cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 31051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 41051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return n_chans; 44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 4704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan, 4804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 5004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* 5104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * When radar detection happens, CSA is performed. However, there's no 5204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * time for CAC, so radar channels must be skipped when finding a new 539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * channel for CSA, unless they are available for immediate use. 5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt */ 559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) && 569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) != 579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE)) 5804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 5904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((chan->flag & HOSTAPD_CHAN_RADAR) && 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE)) 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * The tables contain first valid channel number based on channel width. 7468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * We will also choose this first channel as the control one. 7568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 184, 192 }; 7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * VHT80, valid channels based on center frequency: 8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * 42, 58, 106, 122, 138, 155 8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_80[] = { 36, 52, 100, 116, 132, 149 }; 83f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* 84f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * VHT160 valid channels based on center frequency: 85f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * 50, 114 86f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt */ 87f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int allowed_160[] = { 36, 100 }; 8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int *allowed = allowed_40; 8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt unsigned int i, allowed_no = 0; 9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt switch (n_chans) { 9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 2: 9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_40; 9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_40); 9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 4: 9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_80; 9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_80); 9968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 8: 101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed = allowed_160; 102f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_160); 103f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt default: 10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 10668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 10768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (i = 0; i < allowed_no; i++) { 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 118cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode, 11904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int first_chan_idx, int num_chans, 12004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *first_chan, *chan; 123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i; 124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 125cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan_idx + num_chans >= mode->num_channels) 126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt first_chan = &mode->channels[first_chan_idx]; 129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < num_chans; i++) { 131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &mode->channels[first_chan_idx + i]; 132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan->freq + i * 20 != chan->freq) 134cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 13604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_channel_available(chan, skip_radar)) 137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 1; 141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 1449866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidtstatic int is_in_chanlist(struct hostapd_iface *iface, 1459866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt struct hostapd_channel_data *chan) 1469866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt{ 1479866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt int *entry; 1489866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 1499866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (!iface->conf->chanlist) 1509866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 1; 1519866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 1529866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt for (entry = iface->conf->chanlist; *entry != -1; entry++) { 1539866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (*entry == chan->chan) 1549866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 1; 1559866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 1569866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 0; 1579866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt} 1589866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 1599866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 160cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/* 161cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation. 162cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this: 163cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->secondary_channel 164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg0_idx 165cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg1_idx 166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */ 167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface, 168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 16904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int idx, int skip_radar) 170051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 171051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan; 173cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, channel_idx = 0, n_chans; 174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 175cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 176cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 182cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip HT40/VHT incompatible channels */ 183cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && 184cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel && 185cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt !dfs_is_chan_allowed(chan, n_chans)) 186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 188cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip incompatible chandefs */ 18904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 1929866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (!is_in_chanlist(iface, chan)) 1939866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt continue; 1949866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 198051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 199051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 200051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 203051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 204051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, 208cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan, 209344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt int secondary_channel, 210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 211cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 219cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 220cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 223344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (secondary_channel == 1) 224cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 225344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt else if (secondary_channel == -1) 226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 22768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 231cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 234cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 23568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 2387d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 240051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 242cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 243cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 244cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface) 250051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 253cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 257cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 261cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 262cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 267cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 271cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 282cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 2919866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (res == -1) { 2929866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt wpa_printf(MSG_DEBUG, 2939866086a955d00e237cc8df3722e7dff75c02532Dmitry 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", 2949866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt mode->num_channels, channel_no, iface->conf->channel, 2959866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->ieee80211n, 2969866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->secondary_channel, 2979866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_chwidth); 2989866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 2999866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 3009866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt wpa_printf(MSG_DEBUG, "Available channel: %d", 3019866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt mode->channels[i].chan); 3029866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 3039866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 310cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 311cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 315051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 317cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 330cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 333051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 334051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 335051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 336051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 337cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 339f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 341f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 342f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 343f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 344f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 345f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 346f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 347f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 366cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 368f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 381cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 383cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 38504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 38604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 387051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 388051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 390cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 391cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 3957d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *secondary_channel = 0; 3967d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 3977d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 399cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 402cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 406cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 40704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 408cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 409cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 411cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 412cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 41304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 414cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 415cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 416cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 417cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 418cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 419cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 420cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 421cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 422344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt *secondary_channel, 423cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 430cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 436cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 441cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 442cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 456cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 465cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 479cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 480cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 503cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 511cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 522cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 523cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 524cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 52668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 527cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 52868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 52968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 535cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 536cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 556051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 56068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 56168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 568051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 576df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic unsigned int dfs_get_cac_time(struct hostapd_iface *iface, 577df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int start_chan_idx, int n_chans) 578df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{ 579df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt struct hostapd_channel_data *channel; 580df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt struct hostapd_hw_modes *mode; 581df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt int i; 582df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt unsigned int cac_time_ms = 0; 583df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 584df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt mode = iface->current_mode; 585df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 586df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt for (i = 0; i < n_chans; i++) { 587df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 588df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 589df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt continue; 590df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt if (channel->dfs_cac_ms > cac_time_ms) 591df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt cac_time_ms = channel->dfs_cac_ms; 592df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt } 593df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 594df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt return cac_time_ms; 595df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt} 596df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 597df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 602051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 604cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 60804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 609051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 610cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 615051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 616051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 617051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 618051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 619cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 621df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt /* Setup CAC time */ 622df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx, 623df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt n_chans); 624df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt 625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 626cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 634cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 635051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 636051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 637051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 638051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 641051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 642cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 64796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt int sec = 0; 64896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 cf1 = 0, cf2 = 0; 649cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 65104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 652051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 653051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 654051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 655051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 656cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 657cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 658cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 659cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 660cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 661cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 662051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 663051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 664051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 665051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 666cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 667cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 668cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 669df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", 670cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 671a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel, 672a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_chwidth, 673a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 674df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx, 675df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt iface->dfs_cac_ms / 1000); 676a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt 677a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 678a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->freq, 679a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->channel, 680a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->ieee80211n, 681a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->ieee80211ac, 682a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->secondary_channel, 683a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_chwidth, 684a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 685a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx); 686a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt 687a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt if (res) { 688a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); 689051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 690051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 691051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 692051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 693051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 694051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 695051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 696cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 697051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 698051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 699051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 700cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 701cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 702cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 703cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 704051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 705051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 706cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 707051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 708051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 709cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 710cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 711051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 712051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 713051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 714051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 715051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 716051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 718051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 719051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 72196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg0_idx = 0; 72296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg1_idx = 0; 72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 724051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 73604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 74104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 74204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 74304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 74604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 74704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 75204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 75604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 75704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 75804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 759d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtstatic int hostapd_csa_in_progress(struct hostapd_iface *iface) 760d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{ 761d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt unsigned int i; 762d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt for (i = 0; i < iface->num_bss; i++) 763d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (iface->bss[i]->csa_in_progress) 764d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return 1; 765d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return 0; 766d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt} 767d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 768d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 76904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 772cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 773cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 774cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 77504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 77604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 777d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt unsigned int i; 77804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 77904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 780344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 781344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt __func__, iface->cac_started ? "yes" : "no", 782d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt hostapd_csa_in_progress(iface) ? "yes" : "no"); 783344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt 784344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt /* Check if CSA in progress */ 785d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (hostapd_csa_in_progress(iface)) 786344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt return 0; 787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 78804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 78904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 79004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 79104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 79204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 793cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 794cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 79504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 79604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 79704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 79804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 7999866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt /* 8009866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * If there is no channel to switch immediately to, check if 8019866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * there is another channel where we can switch even if it 8029866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt * requires to perform a CAC first. 8039866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt */ 8049866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt skip_radar = 0; 8059866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 8069866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 8079866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 8089866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt skip_radar); 8099866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt if (!channel) { 8109866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 8119866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt hostapd_disable_iface(iface); 8129866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return err; 8139866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt } 8149866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 8159866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->freq = channel->freq; 8169866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->channel = channel->chan; 8179866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 8189866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 8199866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 8209866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 8219866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 8229866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt 82304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 8249866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt hostapd_enable_iface(iface); 8259866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt return 0; 82604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 82704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 82804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 82904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 83004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 83104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 83204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 83304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 83404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 83504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 83604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 83704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 83804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 83904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 84004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 84104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 84204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 84304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 84404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 84504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 84604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 84704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 84804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 84904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 85004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 85104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 85204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 85304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 85404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 855cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 856d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt for (i = 0; i < iface->num_bss; i++) { 857d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt err = hostapd_switch_channel(iface->bss[i], &csa_settings); 858d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (err) 859d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt break; 860d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt } 861d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 86204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 86304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 86404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 865cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 866cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 867cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 868cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 869cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 870cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 871cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 872051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 873cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 87404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 87504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 87668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 877051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 87804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 87904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 88004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 88104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 882051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 883051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 884051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 885051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 886cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 887051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 888051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 889051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 890051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 891051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 892cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211h) 893051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 894051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 895cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 896cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 897cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 898cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 899051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = set_dfs_state(iface, freq, ht_enabled, chan_offset, 901051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 902051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 903051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 904051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 905cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 906051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 907051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 908051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 909051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 910cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 911051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 912051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 913051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 914051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 915051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 916cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 917051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 918051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 919051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 920cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 921cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 922cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 923051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 924cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 925cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 926051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 927051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 928f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 929f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 930f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface) 931f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 932f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int n_chans, start_chan_idx; 933f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 93461593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt if (!iface->conf->ieee80211h || !iface->current_mode || 93561593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) 93661593f02176862f4880ddefcb1f54cb5f5d9f043Dmitry Shmidt return 0; 937f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 938f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get start (first) channel for current configuration */ 939f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 940f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (start_chan_idx == -1) 941f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 942f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 943f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get number of used channels, depend on width */ 944f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 945f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Check if any of configured channels require DFS */ 947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return dfs_check_chans_radar(iface, start_chan_idx, n_chans); 948f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 949