dfs.c revision 04f534e89ed127da4077485376f24debc50d80d5
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, 179cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 180cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 182cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 188cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 192cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel == 1) 193cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 194cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else if (iface->conf->secondary_channel == -1) 195cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 19668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 197cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 198051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 199051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 20468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 207051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 211cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 212cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 213051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 217cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface) 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 225cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 226051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 229cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 230cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 235cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 239cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 240051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 249051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 250cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == -1) 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); 261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 267cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 268cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 274cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 287cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 294cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for(i = 0; i < n_chans; i++) { 297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 308cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 310051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 315051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 316cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 317051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for(i = 0; i < n_chans; i++) { 319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 331cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 332cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 333cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 334cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 33504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 33604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 340cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 341cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 342051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 346cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 349cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 353cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 35404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 355cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 356cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 359cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 36004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 361cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 362cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 363cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 364cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 365cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 366cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 367cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 368cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 369cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 370cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 376cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 383051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 384051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 385051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 386051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 387cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 388cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 390051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 402cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 409051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 411cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 424051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 425cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 426cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 449cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 457cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 468cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 469cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 470cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 47268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 473cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 47468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 47568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 481cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 482cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 50668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 50768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 528cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 53204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 534cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 535cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 538cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 543cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 546cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 554cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 556051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 562cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 567cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int sec; 568cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 cf1, cf2; 569cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 57004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 57104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 576cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 577cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 579cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 580cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 581cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 586cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 587cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 588cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 589cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", 590cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 591cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel); 592cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 593cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 594cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, 595cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211n, 596cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211ac, 597cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel, 598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_chwidth, 599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 600cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx)) { 601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); 602051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 604051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 605051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 606051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 607051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 608051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 609cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 610051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 611051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 612051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 613cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 615cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 616cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 617051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 618051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 619cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 621051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 622cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 623cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 624051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 627051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 63004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 631051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 632051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 63304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 63404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 63504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 63604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 637051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 63804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 63904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 64004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 64104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 64204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 64304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 64404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 64504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 64604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 64704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 64804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 64904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 65004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 65104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 65204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 65304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 65404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 65504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 65604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 65704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 65804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 65904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 66004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 66104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 66204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 66304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 66404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 66504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 66604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 66804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 66904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 67004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 67304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 67404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 675cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 676cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 677cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 67804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 67904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 68004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 68104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 68204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s)", __func__, 68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started ? "yes" : "no"); 685051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 68604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 68704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 68804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 68904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 692cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 693cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 69404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 69504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 69604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 69804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 69904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 70004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 70104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 70204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 70304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 70404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 70504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 70604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 70704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 70804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 70904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 71004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 71104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 71204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 71304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 71404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 71504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 71604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 71804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 71904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 72104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 72204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 72404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 730cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_switch_channel(hapd, &csa_settings); 73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 735cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 736cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 737cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 738cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 739cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 740cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 741cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 742051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 743cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 74668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 747051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 752051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 753051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 754051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 755051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 756cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 757051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 758051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 759051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 760051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 761051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 762cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211h) 763051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 764051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 765cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 766cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 767cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 768cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 769051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 770cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = set_dfs_state(iface, freq, ht_enabled, chan_offset, 771051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 772051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 773051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 774051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 775cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 776051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 777051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 778051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 780cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 781051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 782051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 783051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 784051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 786cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 787051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 788051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 789051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 790cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 791cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 792cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 793051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 794cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 795cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 796051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 797051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 798