dfs.c revision 7d5c8f257a74ac0d12828962a492e8b84ef83923
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 5304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * channel for CSA. 5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt */ 5504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR) 5604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((chan->flag & HOSTAPD_CHAN_RADAR) && 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE)) 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 6868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * The tables contain first valid channel number based on channel width. 7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * We will also choose this first channel as the control one. 7368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 7468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 7568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 184, 192 }; 7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * VHT80, valid channels based on center frequency: 7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * 42, 58, 106, 122, 138, 155 7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_80[] = { 36, 52, 100, 116, 132, 149 }; 81f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* 82f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * VHT160 valid channels based on center frequency: 83f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * 50, 114 84f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt */ 85f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int allowed_160[] = { 36, 100 }; 8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int *allowed = allowed_40; 8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt unsigned int i, allowed_no = 0; 8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt switch (n_chans) { 9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 2: 9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_40; 9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_40); 9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 4: 9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_80; 9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_80); 9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 98f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 8: 99f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed = allowed_160; 100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_160); 101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt default: 10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (i = 0; i < allowed_no; i++) { 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 116cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode, 11704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int first_chan_idx, int num_chans, 11804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 119cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 120cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *first_chan, *chan; 121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i; 122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan_idx + num_chans >= mode->num_channels) 124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 125cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt first_chan = &mode->channels[first_chan_idx]; 127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < num_chans; i++) { 129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &mode->channels[first_chan_idx + i]; 130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan->freq + i * 20 != chan->freq) 132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 13404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_channel_available(chan, skip_radar)) 135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 1; 139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/* 143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation. 144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this: 145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->secondary_channel 146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg0_idx 147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg1_idx 148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */ 149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface, 150051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 15104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int idx, int skip_radar) 152051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 153051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 154cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan; 155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, channel_idx = 0, n_chans; 156051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 157cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 159051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 160051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 161051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 162051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 163051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip HT40/VHT incompatible channels */ 165cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && 166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel && 167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt !dfs_is_chan_allowed(chan, n_chans)) 168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 169051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 170cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip incompatible chandefs */ 17104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) 172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 173051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 175051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 182051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 186cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, 187cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan, 188344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt int secondary_channel, 189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 192cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 199cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 202344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (secondary_channel == 1) 203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 204344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt else if (secondary_channel == -1) 205cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 20668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 21468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 2177d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 223cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 226051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 228cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface) 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 232cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 236cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 240cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 241cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 246cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 249051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 250cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 261cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == -1) 271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 278cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 279cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 285cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 298cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 305cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 307f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 309f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 310f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 311f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 312f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 314f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 315f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 317051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 326cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 333051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 334cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 335051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 336f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 341051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 342051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 349cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 350cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 351cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 352cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 35304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 35404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 359cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 3637d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *secondary_channel = 0; 3647d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = 0; 3657d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 367cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 370cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 374cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 37504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 376cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 377cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 379cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 380cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 38104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 383cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 385cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 386cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 387cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 388cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 389cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 390344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt *secondary_channel, 391cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 392cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 398cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 404cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 409cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 410cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 424cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 433cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 447cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 448cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 471cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 479cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 490cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 491cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 492cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 49468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 495cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 49668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 49768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 503cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 504cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 52868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 52968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 550cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 55404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 556cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 557cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 560cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 565cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 576cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 584cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 58996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt int sec = 0; 59096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 cf1 = 0, cf2 = 0; 591cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 59204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 59304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 600cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 601cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 602cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 603cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 608cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 609cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 610cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", 612cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 613cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel); 614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 615cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 616cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, 617cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211n, 618cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211ac, 619cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel, 620cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_chwidth, 621cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 622cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx)) { 623051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); 624051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 631cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 634051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 635cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 636cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 637cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 638cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 640051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 641cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 642051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 644cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 645cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 647051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 648051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 649051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 650051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 651051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 65204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 653051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 654051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 65504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 65696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg0_idx = 0; 65796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg1_idx = 0; 65804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 659051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 66004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 66204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 66304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 66404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 66504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 66604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 66704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 66904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 67004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 67104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 67204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 67304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 67504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 67604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 67704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 67804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 67904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 68004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 68104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 68204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 68504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 68604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 68704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 68804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 68904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 69004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 69104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 69204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 69504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 69604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 697cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 698cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 699cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 70004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 70104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 70204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 705344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 706344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt __func__, iface->cac_started ? "yes" : "no", 707344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt iface->csa_in_progress ? "yes" : "no"); 708344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt 709344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt /* Check if CSA in progress */ 710344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (iface->csa_in_progress) 711344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt return 0; 712051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 71304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 71404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 71504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 71604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 718cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 719cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 72104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 72204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 72404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 73604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 74104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 74204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 74304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 74604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 74704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 75204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 756cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 75704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_switch_channel(hapd, &csa_settings); 75804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 75904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 76004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 761cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 762cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 763cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 764cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 765cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 766cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 767cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 768051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 769cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 77268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 773051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 77404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 77504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 77604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 77704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 778051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 780051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 781051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 782cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 783051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 784051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 786051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 788cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211h) 789051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 790051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 791cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 792cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 793cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 794cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 795051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 796cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = set_dfs_state(iface, freq, ht_enabled, chan_offset, 797051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 798051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 799051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 800051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 801cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 802051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 803051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 804051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 805051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 806cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 807051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 808051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 809051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 810051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 811051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 812cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 813051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 814051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 815051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 816cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 817cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 818cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 819051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 820cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 821cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 822051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 823051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 824f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 825f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 826f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface) 827f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 828f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int n_chans, start_chan_idx; 829f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 830f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!iface->current_mode) 831f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 832f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 833f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get start (first) channel for current configuration */ 834f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 835f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (start_chan_idx == -1) 836f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 837f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 838f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get number of used channels, depend on width */ 839f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 840f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 841f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Check if any of configured channels require DFS */ 842f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return dfs_check_chans_radar(iface, start_chan_idx, n_chans); 843f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 844