dfs.c revision 96be6222df414a7dde5c5b1b72df22e67b1a77fc
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 }; 8168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int *allowed = allowed_40; 8268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt unsigned int i, allowed_no = 0; 8368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 8468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt switch (n_chans) { 8568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 2: 8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_40; 8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_40); 8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 4: 9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_80; 9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_80); 9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt default: 9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 97051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 9868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (i = 0; i < allowed_no; i++) { 99051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 103051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 107cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode, 10804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int first_chan_idx, int num_chans, 10904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 110cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 111cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *first_chan, *chan; 112cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i; 113cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 114cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan_idx + num_chans >= mode->num_channels) 115cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 116cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 117cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt first_chan = &mode->channels[first_chan_idx]; 118cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 119cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < num_chans; i++) { 120cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &mode->channels[first_chan_idx + i]; 121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan->freq + i * 20 != chan->freq) 123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 12504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_channel_available(chan, skip_radar)) 126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 1; 130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/* 134cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation. 135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this: 136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->secondary_channel 137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg0_idx 138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg1_idx 139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */ 140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface, 141051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 14204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int idx, int skip_radar) 143051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 144051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan; 146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, channel_idx = 0, n_chans; 147051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 150051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 151051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 152051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 153051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 154051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip HT40/VHT incompatible channels */ 156cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && 157cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel && 158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt !dfs_is_chan_allowed(chan, n_chans)) 159051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 160051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 161cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip incompatible chandefs */ 16204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) 163cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 164051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 165051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 166051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 167051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 169051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 170051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 171051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 172051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 173051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 175051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 177cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, 178cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan, 179344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt int secondary_channel, 180cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 181cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 182051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 183cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 188051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 191cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 192051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 193344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (secondary_channel == 1) 194cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 195344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt else if (secondary_channel == -1) 196cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 19768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 199051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 200051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 201cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 203051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 204cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 20568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 207051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 211cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 212cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 218cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface) 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 226cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 230cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 231cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 236cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 240cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 249051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 250051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 251cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == -1) 261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 268cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 269cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 275cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 288cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 295cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for(i = 0; i < n_chans; i++) { 298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 309cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 310051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 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_DISABLED) 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 332cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 333cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 334cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 335cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 33604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 33704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 341cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 342cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 347cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 350cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 354cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 35504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 356cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 357cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 358051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 359cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 360cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 36104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 362cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 363cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 364cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 365cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 366cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 367cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 368cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 369cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 370344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt *secondary_channel, 371cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 372cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 378cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 382051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 383051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 385051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 386051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 387051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 388051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 389cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 390cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 404cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 409051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 413cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 424051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 427cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 428cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 451cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 459cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 470cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 471cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 472cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 47468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 475cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 47668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 47768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 483cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 484cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 50868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 50968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 530cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 53404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 536cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 537cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 540cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 545cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 548cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 556cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 568051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 56996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt int sec = 0; 57096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 cf1 = 0, cf2 = 0; 571cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 57204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 57304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 579cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 580cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 581cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 582cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 583cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 588cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 589cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 590cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 591cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", 592cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 593cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel); 594cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 595cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 596cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, 597cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211n, 598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211ac, 599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel, 600cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_chwidth, 601cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 602cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx)) { 603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); 604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 608051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 609051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 610051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 613051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 614051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 615cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 616cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 617cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 618cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 619051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 621cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 622051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 623051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 624cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 625cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 63204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 633051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 634051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 63504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 63696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg0_idx = 0; 63796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg1_idx = 0; 63804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 64004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 64104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 64204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 64304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 64404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 64504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 64604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 64704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 64804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 64904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 65104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 65204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 65304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 65404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 65504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 65604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 65704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 65804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 65904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 66104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 66204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 66304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 66404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 66504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 66604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 66704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 66804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 67004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 67104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 67204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 67504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 67604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 677cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 678cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 679cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 68004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 68104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 68204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 685344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 686344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt __func__, iface->cac_started ? "yes" : "no", 687344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt iface->csa_in_progress ? "yes" : "no"); 688344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt 689344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt /* Check if CSA in progress */ 690344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (iface->csa_in_progress) 691344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt return 0; 692051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 69304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 69404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 69504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 69604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 698cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 699cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 70004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 70104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 70204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 70504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 70604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 70704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 70804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 70904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 71004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 71104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 71204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 71304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 71404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 71504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 71604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 71804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 71904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 72104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 72204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 72404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 736cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_switch_channel(hapd, &csa_settings); 73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 741cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 742cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 743cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 744cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 745cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 746cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 747cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 748051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 749cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 75268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 753051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 75604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 75704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 758051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 759051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 760051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 761051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 762cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 763051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 764051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 765051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 766051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 767051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 768cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211h) 769051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 770051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 771cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 772cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 773cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 774cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 775051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 776cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = set_dfs_state(iface, freq, ht_enabled, chan_offset, 777051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 778051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 780051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 781cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 782051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 783051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 784051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 786cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 788051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 789051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 790051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 791051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 792cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 793051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 794051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 795051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 796cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 797cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 798cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 799051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 800cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 801cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 802051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 803051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 804