dfs.c revision f21452aea786ac056eb01f1cbba4f553bd502747
1051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 2051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * DFS - Dynamic Frequency Selection 3051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Copyright (c) 2013, Qualcomm Atheros, Inc. 5051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 6051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 7051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * See README for more details. 8051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 9051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/includes.h" 11051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 12051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "utils/common.h" 13051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "common/ieee802_11_defs.h" 14cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt#include "common/wpa_ctrl.h" 15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h" 16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h" 17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h" 18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h" 19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 21cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_iface *iface) 22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1; 24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 25cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel) 26051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 27051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 28cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 29cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 31051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 41051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return n_chans; 44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 4704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan, 4804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 5004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* 5104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * When radar detection happens, CSA is performed. However, there's no 5204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * time for CAC, so radar channels must be skipped when finding a new 5304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * channel for CSA. 5404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt */ 5504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR) 5604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 5704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((chan->flag & HOSTAPD_CHAN_RADAR) && 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE)) 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 6868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans) 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * The tables contain first valid channel number based on channel width. 7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * We will also choose this first channel as the control one. 7368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 7468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 7568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 184, 192 }; 7668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* 7768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * VHT80, valid channels based on center frequency: 7868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt * 42, 58, 106, 122, 138, 155 7968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt */ 8068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int allowed_80[] = { 36, 52, 100, 116, 132, 149 }; 81f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* 82f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * VHT160 valid channels based on center frequency: 83f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt * 50, 114 84f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt */ 85f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int allowed_160[] = { 36, 100 }; 8668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt int *allowed = allowed_40; 8768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt unsigned int i, allowed_no = 0; 8868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 8968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt switch (n_chans) { 9068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 2: 9168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_40; 9268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_40); 9368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 9468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt case 4: 9568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed = allowed_80; 9668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_80); 9768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 98f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 8: 99f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed = allowed_160; 100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt allowed_no = ARRAY_SIZE(allowed_160); 101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 10268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt default: 10368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans); 10468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 10568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 10768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt for (i = 0; i < allowed_no; i++) { 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 116cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_chan_range_available(struct hostapd_hw_modes *mode, 11704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int first_chan_idx, int num_chans, 11804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 119cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{ 120cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *first_chan, *chan; 121cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i; 122cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 123cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan_idx + num_chans >= mode->num_channels) 124cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 125cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 126cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt first_chan = &mode->channels[first_chan_idx]; 127cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 128cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < num_chans; i++) { 129cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &mode->channels[first_chan_idx + i]; 130cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 131cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (first_chan->freq + i * 20 != chan->freq) 132cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 133cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 13404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_channel_available(chan, skip_radar)) 135cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 0; 136cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt } 137cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 138cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return 1; 139cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt} 140cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt/* 143cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * The function assumes HT40+ operation. 144cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Make sure to adjust the following variables after calling this: 145cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->secondary_channel 146cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg0_idx 147cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * - hapd->vht_oper_centr_freq_seg1_idx 148cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt */ 149cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_iface *iface, 150051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 15104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int idx, int skip_radar) 152051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 153051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 154cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan; 155cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int i, channel_idx = 0, n_chans; 156051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 157cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 158cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 159051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 160051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 161051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 162051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 163051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 164cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip HT40/VHT incompatible channels */ 165cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && 166cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel && 167cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt !dfs_is_chan_allowed(chan, n_chans)) 168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 169051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 170cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Skip incompatible chandefs */ 17104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) 172cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt continue; 173051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 175051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 182051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 186cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, 187cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt struct hostapd_channel_data *chan, 188344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt int secondary_channel, 189cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 190cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx) 191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 192cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211ac) 193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 198cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx = 0; 199cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 200cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 202344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (secondary_channel == 1) 203cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 2; 204344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt else if (secondary_channel == -1) 205cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan - 2; 20668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt else 207cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan; 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 210cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 6; 211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 213cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx = chan->chan + 14; 21468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt break; 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 220cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d", 221cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg0_idx, 222cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *vht_oper_centr_freq_seg1_idx); 223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 226051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 227cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_iface *iface) 228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 231cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int channel_no = iface->conf->channel; 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 235cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) 236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 239cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->ieee80211ac) { 240cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt switch (iface->conf->vht_oper_chwidth) { 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 245cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 6; 246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 249cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx - 14; 250051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 260cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == -1) 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); 271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 277cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_iface *iface, 278cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int start_chan_idx, int n_chans) 279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 284cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 297cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_iface *iface, 298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 304cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 306f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 308f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 309f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 310f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 311f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 312f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!(channel->flag & HOSTAPD_CHAN_RADAR)) 313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 314f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 315051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 317051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 325cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_iface *iface, 326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 333cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 334051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 335f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt for (i = 0; i < n_chans; i++) { 336051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 341051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 342051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 348cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic struct hostapd_channel_data * 349cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtdfs_get_valid_channel(struct hostapd_iface *iface, 350cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int *secondary_channel, 351cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 *vht_oper_centr_freq_seg0_idx, 35204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt u8 *vht_oper_centr_freq_seg1_idx, 35304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar) 354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 357cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int num_available_chandefs; 358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int chan_idx; 359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 363cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->current_mode == NULL) 364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 366cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 370cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* Get the count first */ 37104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 372cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (num_available_chandefs == 0) 373cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return NULL; 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 375cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 376cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan_idx = _rand % num_available_chandefs; 37704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt dfs_find_channel(iface, &chan, chan_idx, skip_radar); 378cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 379cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt /* dfs_find_channel() calculations assume HT40+ */ 380cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (iface->conf->secondary_channel) 381cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 1; 382cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt else 383cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt *secondary_channel = 0; 384cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 385cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt dfs_adjust_vht_center_freq(iface, chan, 386344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt *secondary_channel, 387cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 388cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx); 389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 390051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 394cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 400cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 405cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt for (i = 0; i < iface->current_mode->num_channels; i++) { 406cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt chan = &iface->current_mode->channels[i]; 407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 409051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 420cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 424051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 429cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 443cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 444cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 467cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt ret += set_dfs_state_freq(iface, frequency, state); 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 475cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 486cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt mode = iface->current_mode; 487cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 488cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 49068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt /* Check we are on DFS channel(s) */ 491cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) 49268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt return 0; 49368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 499cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (frequency == 0) 500cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt frequency = cf1; 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 52468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_RADAR)) 52568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt continue; 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 546cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_iface *iface) 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 55004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 552cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 553cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 556cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 561cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 564cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); 565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 568051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 572cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_available(iface, start_chan_idx, n_chans); 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 580cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_check_chans_unavailable(iface, start_chan_idx, 581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 58596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt int sec = 0; 58696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 cf1 = 0, cf2 = 0; 587cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 58804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 58904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 590051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 591051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 592051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 593051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 594cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 595cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 596cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 597cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = sec; 598cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = cf1; 599cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = cf2; 600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 602051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 603051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 604cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_set_state(iface, HAPD_IFACE_DFS); 605cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); 606cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START 607cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", 608cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 609cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, iface->conf->secondary_channel); 610cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode, 611cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq, 612cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel, 613cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211n, 614cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->ieee80211ac, 615cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel, 616cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_chwidth, 617cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx, 618cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx)) { 619051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); 620051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 621051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 622051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 623051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 624051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 625051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 626051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 627cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, 628051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 629051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 630051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 631cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED 632cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 633cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 634cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 635051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 636051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 637cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, 638051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 639051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 640cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->cac_started = 0; 641cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_setup_interface_complete(iface, 0); 642051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 643051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 644051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 645051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 646051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 647051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 64804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) 649051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 650051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 65104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int secondary_channel; 65296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg0_idx = 0; 65396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt u8 vht_oper_centr_freq_seg1_idx = 0; 65404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 0; 655051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 65604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 65704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Radar detected during active CAC */ 65804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->cac_started = 0; 65904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 66004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 66104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 66204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 66304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 66404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 66504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 66604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 66704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 66804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 66904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 67104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 67204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 67304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 67404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 67504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 67604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->freq = channel->freq; 67704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->channel = channel->chan; 67804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 67904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 68004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 68104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 68204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 68304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = 0; 68404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 68504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_setup_interface_complete(iface, err); 68604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 68704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt} 68804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 68904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 69004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) 69104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{ 69204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_channel_data *channel; 693cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt int secondary_channel; 694cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg0_idx; 695cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt u8 vht_oper_centr_freq_seg1_idx; 69604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int skip_radar = 1; 69704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct csa_settings csa_settings; 69804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt struct hostapd_data *hapd = iface->bss[0]; 69904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt int err = 1; 70004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 701344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", 702344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt __func__, iface->cac_started ? "yes" : "no", 703344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt iface->csa_in_progress ? "yes" : "no"); 704344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt 705344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt /* Check if CSA in progress */ 706344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt if (iface->csa_in_progress) 707344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt return 0; 708051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 70904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Check if active CAC */ 71004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (iface->cac_started) 71104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return hostapd_dfs_start_channel_switch_cac(iface); 71204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 71304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Perform channel switch/CSA */ 714cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt channel = dfs_get_valid_channel(iface, &secondary_channel, 715cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt &vht_oper_centr_freq_seg0_idx, 71604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt &vht_oper_centr_freq_seg1_idx, 71704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt skip_radar); 71804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 71904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (!channel) { 72004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* FIXME: Wait for channel(s) to become available */ 72104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 72204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 72304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 72404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 72504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", 72604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan); 72704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL 72804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt "freq=%d chan=%d sec_chan=%d", channel->freq, 72904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, secondary_channel); 73004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 73104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Setup CSA request */ 73204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt os_memset(&csa_settings, 0, sizeof(csa_settings)); 73304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.cs_count = 5; 73404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt csa_settings.block_tx = 1; 73504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_set_freq_params(&csa_settings.freq_params, 73604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->hw_mode, 73704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->freq, 73804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt channel->chan, 73904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211n, 74004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->ieee80211ac, 74104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt secondary_channel, 74204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->conf->vht_oper_chwidth, 74304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg0_idx, 74404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt vht_oper_centr_freq_seg1_idx, 74504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt iface->current_mode->vht_capab); 74604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 74704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 74804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 74904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_disable_iface(iface); 75004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return err; 75104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt } 752cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 75304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err = hostapd_switch_channel(hapd, &csa_settings); 75404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (err) { 75504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", 75604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt err); 757cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->freq = channel->freq; 758cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->channel = channel->chan; 759cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->secondary_channel = secondary_channel; 760cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg0_idx = 761cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg0_idx; 762cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt iface->conf->vht_oper_centr_freq_seg1_idx = 763cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt vht_oper_centr_freq_seg1_idx; 764051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 765cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt hostapd_disable_iface(iface); 76604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt hostapd_enable_iface(iface); 76704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt return 0; 76868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt } 769051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 77004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt /* Channel configuration will be updated once CSA completes and 77104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt * ch_switch_notify event is received */ 77204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt 77304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); 774051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 775051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 776051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 777051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 778cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, 779051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 780051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 781051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 782051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 783051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 784cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt if (!iface->conf->ieee80211h) 785051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 786051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 787cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED 788cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 789cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 790cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt 791051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 792cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = set_dfs_state(iface, freq, ht_enabled, chan_offset, 793051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 794051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 795051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 796051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 797cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 798051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 799051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 800051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 801051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 802cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt res = hostapd_dfs_start_channel_switch(iface); 803051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 804051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 805051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 806051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 807051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 808cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, 809051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 810051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 811051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 812cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED 813cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", 814cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt freq, ht_enabled, chan_offset, chan_width, cf1, cf2); 815051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 816cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, 817cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); 818051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 819051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 820f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 821f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 822f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtint hostapd_is_dfs_required(struct hostapd_iface *iface) 823f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 824f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int n_chans, start_chan_idx; 825f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 826f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (!iface->current_mode) 827f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 828f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 829f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get start (first) channel for current configuration */ 830f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(iface); 831f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (start_chan_idx == -1) 832f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return -1; 833f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 834f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Get number of used channels, depend on width */ 835f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt n_chans = dfs_get_used_n_chans(iface); 836f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 837f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Check if any of configured channels require DFS */ 838f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return dfs_check_chans_radar(iface, start_chan_idx, n_chans); 839f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 840