dfs.c revision 051af73b8f8014eff33330aead0f36944b3403e6
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" 14051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "hostapd.h" 15051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "ap_drv_ops.h" 16051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "drivers/driver.h" 17051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt#include "dfs.h" 18051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 19051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 20051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_get_used_n_chans(struct hostapd_data *hapd) 21051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 22051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1; 23051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 24051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel) 25051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 26051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 27051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iconf->ieee80211ac) { 28051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (hapd->iconf->vht_oper_chwidth) { 29051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 30051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 31051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 32051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 33051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 34051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 35051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 36051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 37051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 38051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 39051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 40051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 41051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 42051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return n_chans; 43051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 44051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 45051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 46051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_channel_available(struct hostapd_channel_data *chan) 47051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 48051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_DISABLED) 49051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 50051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((chan->flag & HOSTAPD_CHAN_RADAR) && 51051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ((chan->flag & HOSTAPD_CHAN_DFS_MASK) == 52051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE)) 53051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 54051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 55051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 56051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 57051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 58051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_is_ht40_allowed(struct hostapd_channel_data *chan) 59051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 60051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 61051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 184, 192 }; 62051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt unsigned int i; 63051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 64051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++) { 65051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == allowed[i]) 66051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 67051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 68051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 69051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 70051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 71051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 72051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 73051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_find_channel(struct hostapd_data *hapd, 74051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data **ret_chan, 75051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int idx) 76051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 77051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 78051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan, *next_chan; 79051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, j, channel_idx = 0, n_chans; 80051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 81051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 82051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = dfs_get_used_n_chans(hapd); 83051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 84051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); 85051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 86051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 87051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 88051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip not available channels */ 89051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!dfs_channel_available(chan)) 90051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 91051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 92051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip HT40/VHT uncompatible channels */ 93051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iconf->ieee80211n && 94051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->secondary_channel) { 95051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!dfs_is_ht40_allowed(chan)) 96051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 97051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 98051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 1; j < n_chans; j++) { 99051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt next_chan = &mode->channels[i + j]; 100051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!dfs_channel_available(next_chan)) 101051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 102051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 103051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (j != n_chans) 104051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt continue; 105051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 106051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Set HT40+ */ 107051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->secondary_channel = 1; 108051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 109051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 110051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (ret_chan && idx == channel_idx) { 111051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); 112051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt *ret_chan = chan; 113051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return idx; 114051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 115051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); 116051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx++; 117051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 118051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return channel_idx; 119051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 120051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 121051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 122051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic void dfs_adjust_vht_center_freq(struct hostapd_data *hapd, 123051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan) 124051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 125051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!hapd->iconf->ieee80211ac) 126051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 127051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 128051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!chan) 129051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return; 130051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 131051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (hapd->iconf->vht_oper_chwidth) { 132051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 133051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 2; 134051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 135051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 136051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6; 137051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 138051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 139051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx = 140051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan + 14; 141051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 142051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); 143051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 144051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 145051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 146051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d", 147051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx); 148051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 149051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 150051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 151051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* Return start channel idx we will use for mode->channels[idx] */ 152051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_get_start_chan_idx(struct hostapd_data *hapd) 153051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 154051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 155051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 156051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int channel_no = hapd->iconf->channel; 157051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = -1, i; 158051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 159051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* HT40- */ 160051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iconf->ieee80211n && hapd->iconf->secondary_channel == -1) 161051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no -= 4; 162051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 163051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 164051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iconf->ieee80211ac) { 165051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (hapd->iconf->vht_oper_chwidth) { 166051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_USE_HT: 167051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 168051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_80MHZ: 169051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 170051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx - 6; 171051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 172051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case VHT_CHANWIDTH_160MHZ: 173051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = 174051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx - 14; 175051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 176051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 177051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, 178051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS only VHT20/40/80/160 is supported now"); 179051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_no = -1; 180051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 181051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 182051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 183051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 184051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get idx */ 185051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 186051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < mode->num_channels; i++) { 187051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[i]; 188051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == channel_no) { 189051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = i; 190051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 191051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 192051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 193051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 194051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == -1) 195051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong: -1"); 196051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 197051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 198051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 199051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 200051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel have radar flag */ 202051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_check_chans_radar(struct hostapd_data *hapd, int start_chan_idx, 203051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 204051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 205051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 206051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 207051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 209051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 210051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 211051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 213051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_RADAR) 214051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 215051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 216051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 217051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 218051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 219051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 220051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 221051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* All channels available */ 222051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_check_chans_available(struct hostapd_data *hapd, 223051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, int n_chans) 224051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 225051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 226051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 227051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 228051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 229051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 230051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 231051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for(i = 0; i < n_chans; i++) { 232051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 233051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) != 234051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE) 235051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 236051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 237051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 238051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return i == n_chans; 239051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 240051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 241051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 242051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* At least one channel unavailable */ 243051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_check_chans_unavailable(struct hostapd_data *hapd, 244051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx, 245051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans) 246051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 247051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 248051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 249051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i, res = 0; 250051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 251051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 252051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 253051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for(i = 0; i < n_chans; i++) { 254051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = &mode->channels[start_chan_idx + i]; 255051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel->flag & HOSTAPD_CHAN_DISABLED) 256051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 257051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) == 258051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE) 259051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 260051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 261051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 262051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 263051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 264051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 265051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 266051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic struct hostapd_channel_data * dfs_get_valid_channel( 267051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_data *hapd) 268051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 269051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 270051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 271051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int channel_idx, new_channel_idx; 272051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u32 _rand; 273051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 274051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); 275051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 276051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iface->current_mode == NULL) 277051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 278051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 279051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 280051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) 281051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return NULL; 282051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 283051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* get random available channel */ 284051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel_idx = dfs_find_channel(hapd, NULL, 0); 285051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel_idx > 0) { 286051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt os_get_random((u8 *) &_rand, sizeof(_rand)); 287051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt new_channel_idx = _rand % channel_idx; 288051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs_find_channel(hapd, &chan, new_channel_idx); 289051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 290051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 291051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* VHT */ 292051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt dfs_adjust_vht_center_freq(hapd, chan); 293051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 294051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return chan; 295051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 296051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 297051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 298051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int set_dfs_state_freq(struct hostapd_data *hapd, int freq, u32 state) 299051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 300051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 301051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan = NULL; 302051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int i; 303051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 304051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 305051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 306051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 307051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 308051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq); 309051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { 310051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &hapd->iface->current_mode->channels[i]; 311051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->freq == freq) { 312051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->flag & HOSTAPD_CHAN_RADAR) { 313051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag &= ~HOSTAPD_CHAN_DFS_MASK; 314051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->flag |= state; 315051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; /* Channel found */ 316051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 317051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 318051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 319051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq); 320051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 321051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 322051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 323051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 324051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int set_dfs_state(struct hostapd_data *hapd, int freq, int ht_enabled, 325051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_offset, int chan_width, int cf1, 326051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf2, u32 state) 327051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 328051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans = 1, i; 329051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 330051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int frequency = freq; 331051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ret = 0; 332051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 333051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 334051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode == NULL) 335051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 336051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 337051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (mode->mode != HOSTAPD_MODE_IEEE80211A) { 338051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_WARNING, "current_mode != IEEE80211A"); 339051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 340051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 341051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 342051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Seems cf1 and chan_width is enough here */ 343051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 344051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 345051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 346051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 1; 347051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1; 348051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 349051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 350051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 2; 351051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 352051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 353051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 354051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 4; 355051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 356051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 357051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 358051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = 8; 359051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 360051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 361051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 362051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 363051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 364051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 365051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 366051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 367051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency, 368051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 369051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 370051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ret += set_dfs_state_freq(hapd, frequency, state); 371051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = frequency + 20; 372051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 374051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return ret; 375051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 376051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 377051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 378051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq, 379051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int chan_width, int cf1, int cf2) 380051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 381051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int start_chan_idx; 382051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_hw_modes *mode; 383051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *chan; 384051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int n_chans, i, j, frequency = freq, radar_n_chans = 1; 385051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt u8 radar_chan; 386051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res = 0; 387051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 388051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hapd->iface->freq == freq) 389051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 390051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 391051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Our configuration */ 392051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt mode = hapd->iface->current_mode; 393051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(hapd); 394051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = dfs_get_used_n_chans(hapd); 395051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 396051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Reported via radar event */ 397051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt switch (chan_width) { 398051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20_NOHT: 399051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_20: 400051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 1; 401051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1; 402051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 403051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_40: 404051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 2; 405051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 10; 406051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 407051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_80: 408051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 4; 409051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 30; 410051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 411051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt case CHAN_WIDTH_160: 412051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt radar_n_chans = 8; 413051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt frequency = cf1 - 70; 414051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 415051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt default: 416051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_INFO, "DFS chan_width %d not supported", 417051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width); 418051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt break; 419051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 420051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 421051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt ieee80211_freq_to_chan(frequency, &radar_chan); 422051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 423051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (i = 0; i < n_chans; i++) { 424051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan = &mode->channels[start_chan_idx + i]; 425051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt for (j = 0; j < radar_n_chans; j++) { 426051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d", 427051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan->chan, radar_chan + j * 4); 428051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (chan->chan == radar_chan + j * 4) 429051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res++; 430051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 431051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 432051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 433051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "overlapped: %d", res); 434051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 435051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 436051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 437051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 438051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 439051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt/* 440051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * Main DFS handler 441051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 1 - continue channel/ap setup 442051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * 0 - channel/ap setup will be continued after CAC 443051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt * -1 - hit critical error 444051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt */ 445051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtint hostapd_handle_dfs(struct hostapd_data *hapd) 446051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 447051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 448051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res, n_chans, start_chan_idx; 449051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 450051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt do { 451051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get start (first) channel for current configuration */ 452051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt start_chan_idx = dfs_get_start_chan_idx(hapd); 453051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (start_chan_idx == -1) 454051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 455051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 456051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Get number of used channels, depend on width */ 457051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans = dfs_get_used_n_chans(hapd); 458051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 459051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels require DFS */ 460051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = dfs_check_chans_radar(hapd, start_chan_idx, n_chans); 461051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 462051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS %d channels required radar detection", 463051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res); 464051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 465051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 466051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 467051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if all channels are DFS available */ 468051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = dfs_check_chans_available(hapd, start_chan_idx, n_chans); 469051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, 470051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt "DFS all channels available, (SKIP CAC): %s", 471051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res ? "yes" : "no"); 472051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) 473051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 1; 474051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 475051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Check if any of configured channels is unavailable */ 476051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = dfs_check_chans_unavailable(hapd, start_chan_idx, 477051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt n_chans); 478051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", 479051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res, res ? "yes": "no"); 480051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res) { 481051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = dfs_get_valid_channel(hapd); 482051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!channel) { 483051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "could not get valid channel"); 484051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 485051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 486051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->channel = channel->chan; 487051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iface->freq = channel->freq; 488051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 489051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } while (res); 490051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 491051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Finally start CAC */ 492051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", hapd->iface->freq); 493051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (hostapd_start_dfs_cac(hapd, hapd->iconf->hw_mode, 494051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iface->freq, 495051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->channel, 496051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->ieee80211n, 497051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->ieee80211ac, 498051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->secondary_channel, 499051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_chwidth, 500051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg0_idx, 501051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->vht_oper_centr_freq_seg1_idx)) { 502051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed"); 503051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return -1; 504051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 505051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 506051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 507051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 508051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 509051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 510051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtint hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq, 511051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 512051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 513051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 514051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 515051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 516051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 517051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (success) { 518051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Complete iface/ap configuration */ 519051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt set_dfs_state(hapd, freq, ht_enabled, chan_offset, 520051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 521051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_AVAILABLE); 522051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hostapd_setup_interface_complete(hapd->iface, 0); 523051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } else { 524051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Switch to new channel */ 525051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt set_dfs_state(hapd, freq, ht_enabled, chan_offset, 526051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 527051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 528051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = dfs_get_valid_channel(hapd); 529051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel) { 530051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->channel = channel->chan; 531051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iface->freq = channel->freq; 532051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt err = 0; 533051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } else 534051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_ERROR, "No valid channel available"); 535051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 536051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hostapd_setup_interface_complete(hapd->iface, err); 537051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 538051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 539051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 540051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 541051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 542051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 543051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtstatic int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd) 544051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 545051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt struct hostapd_channel_data *channel; 546051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int err = 1; 547051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 548051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s called", __func__); 549051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt channel = dfs_get_valid_channel(hapd); 550051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (channel) { 551051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iconf->channel = channel->chan; 552051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->iface->freq = channel->freq; 553051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt err = 0; 554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt } 555051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 556051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hapd->driver->stop_ap(hapd->drv_priv); 557051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 558051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt hostapd_setup_interface_complete(hapd->iface, err); 559051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 560051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 561051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 562051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 563051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtint hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq, 564051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 565051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 566051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 567051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int res; 568051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 569051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!hapd->iconf->ieee80211h) 570051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 571051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 572051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* mark radar frequency as invalid */ 573051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = set_dfs_state(hapd, freq, ht_enabled, chan_offset, 574051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt chan_width, cf1, cf2, 575051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_UNAVAILABLE); 576051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 577051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* Skip if reported radar event not overlapped our channels */ 578051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = dfs_are_channels_overlapped(hapd, freq, chan_width, cf1, cf2); 579051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (!res) 580051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 581051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 582051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* we are working on non-DFS channel - skip event */ 583051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt if (res == 0) 584051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 585051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 586051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* radar detected while operating, switch the channel. */ 587051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt res = hostapd_dfs_start_channel_switch(hapd); 588051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 589051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return res; 590051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 591051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 592051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt 593051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidtint hostapd_dfs_nop_finished(struct hostapd_data *hapd, int freq, 594051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int ht_enabled, int chan_offset, int chan_width, 595051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt int cf1, int cf2) 596051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt{ 597051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt /* TODO add correct implementation here */ 598051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt set_dfs_state(hapd, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, 599051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt HOSTAPD_CHAN_DFS_USABLE); 600051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt return 0; 601051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt} 602