1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /** 28 * DOC: This file has the functions related to DFS CAC. 29 */ 30 31 #include "../dfs_channel.h" 32 #include "../dfs_zero_cac.h" 33 #include "../dfs_etsi_precac.h" 34 #include "wlan_dfs_utils_api.h" 35 #include "wlan_dfs_mlme_api.h" 36 #include "../dfs_internal.h" 37 38 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650)) 39 #define ADJACENT_WEATHER_RADAR_CHANNEL 5580 40 #define CH100_START_FREQ 5490 41 #define CH100 100 42 43 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout) 44 { 45 if (!dfs) 46 return -EIO; 47 48 dfs->dfs_cac_timeout_override = cac_timeout; 49 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d", 50 (cac_timeout == -1) ? "default" : "overridden", 51 cac_timeout); 52 53 return 0; 54 } 55 56 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout) 57 { 58 if (!dfs) 59 return -EIO; 60 61 (*cac_timeout) = dfs->dfs_cac_timeout_override; 62 63 return 0; 64 } 65 66 void dfs_cac_valid_reset(struct wlan_dfs *dfs, 67 uint8_t prevchan_ieee, 68 uint32_t prevchan_flags) 69 { 70 if (dfs->dfs_cac_valid_time) { 71 if ((prevchan_ieee != dfs->dfs_curchan->dfs_ch_ieee) || 72 (prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) { 73 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 74 "Cancelling timer & clearing cac_valid" 75 ); 76 qdf_timer_stop(&dfs->dfs_cac_valid_timer); 77 dfs->dfs_cac_valid = 0; 78 } 79 } 80 } 81 82 /** 83 * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer 84 * cac_valid bit will be reset in this function. 85 */ 86 static os_timer_func(dfs_cac_valid_timeout) 87 { 88 struct wlan_dfs *dfs = NULL; 89 90 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 91 dfs->dfs_cac_valid = 0; 92 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!"); 93 } 94 95 /** 96 * dfs_cac_timeout() - DFS cactimeout function. 97 * 98 * Sets dfs_cac_timer_running to 0 and dfs_cac_valid_timer. 99 */ 100 static os_timer_func(dfs_cac_timeout) 101 { 102 struct wlan_dfs *dfs = NULL; 103 104 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 105 dfs->dfs_cac_timer_running = 0; 106 107 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d", 108 dfs->dfs_curchan->dfs_ch_freq, 109 (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000)); 110 111 /* Once CAC is done, add channel to ETSI precacdone list*/ 112 if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN) 113 dfs_add_to_etsi_precac_done_list(dfs); 114 115 /* 116 * When radar is detected during a CAC we are woken up prematurely to 117 * switch to a new channel. Check the channel to decide how to act. 118 */ 119 if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) { 120 dfs_mlme_mark_dfs(dfs->dfs_pdev_obj, 121 dfs->dfs_curchan->dfs_ch_ieee, 122 dfs->dfs_curchan->dfs_ch_freq, 123 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2, 124 dfs->dfs_curchan->dfs_ch_flags); 125 dfs_debug(dfs, WLAN_DEBUG_DFS, 126 "CAC timer on channel %u (%u MHz) stopped due to radar", 127 dfs->dfs_curchan->dfs_ch_ieee, 128 dfs->dfs_curchan->dfs_ch_freq); 129 } else { 130 dfs_debug(dfs, WLAN_DEBUG_DFS, 131 "CAC timer on channel %u (%u MHz) expired; no radar detected", 132 dfs->dfs_curchan->dfs_ch_ieee, 133 dfs->dfs_curchan->dfs_ch_freq); 134 135 /* On CAC completion, set the bit 'cac_valid'. 136 * CAC will not be re-done if this bit is reset. 137 * The flag will be reset when dfs_cac_valid_timer 138 * timesout. 139 */ 140 if (dfs->dfs_cac_valid_time) { 141 dfs->dfs_cac_valid = 1; 142 qdf_timer_mod(&dfs->dfs_cac_valid_timer, 143 dfs->dfs_cac_valid_time * 1000); 144 } 145 } 146 147 /* Iterate over the nodes, processing the CAC completion event. */ 148 dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0); 149 150 /* Send a CAC timeout, VAP up event to user space */ 151 dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj); 152 153 if (dfs->dfs_defer_precac_channel_change == 1) { 154 dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj); 155 dfs->dfs_defer_precac_channel_change = 0; 156 } 157 } 158 159 void dfs_cac_timer_init(struct wlan_dfs *dfs) 160 { 161 qdf_timer_init(NULL, 162 &(dfs->dfs_cac_timer), 163 dfs_cac_timeout, 164 (void *)(dfs), 165 QDF_TIMER_TYPE_WAKE_APPS); 166 167 qdf_timer_init(NULL, 168 &(dfs->dfs_cac_valid_timer), 169 dfs_cac_valid_timeout, 170 (void *)(dfs), 171 QDF_TIMER_TYPE_WAKE_APPS); 172 } 173 174 void dfs_cac_attach(struct wlan_dfs *dfs) 175 { 176 dfs->dfs_cac_timeout_override = -1; 177 dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS; 178 dfs_cac_timer_init(dfs); 179 } 180 181 void dfs_cac_timer_reset(struct wlan_dfs *dfs) 182 { 183 qdf_timer_stop(&dfs->dfs_cac_timer); 184 dfs_get_override_cac_timeout(dfs, 185 &(dfs->dfs_cac_timeout_override)); 186 187 } 188 189 void dfs_cac_timer_detach(struct wlan_dfs *dfs) 190 { 191 qdf_timer_free(&dfs->dfs_cac_timer); 192 193 qdf_timer_free(&dfs->dfs_cac_valid_timer); 194 dfs->dfs_cac_valid = 0; 195 } 196 197 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs) 198 { 199 return dfs->dfs_cac_timer_running; 200 } 201 202 void dfs_start_cac_timer(struct wlan_dfs *dfs) 203 { 204 qdf_timer_mod(&dfs->dfs_cac_timer, 205 dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj, 206 dfs->dfs_curchan->dfs_ch_freq, 207 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2, 208 dfs->dfs_curchan->dfs_ch_flags) * 1000); 209 } 210 211 void dfs_cancel_cac_timer(struct wlan_dfs *dfs) 212 { 213 qdf_timer_stop(&dfs->dfs_cac_timer); 214 } 215 216 void dfs_cac_stop(struct wlan_dfs *dfs) 217 { 218 uint32_t phyerr; 219 220 dfs_get_debug_info(dfs, (void *)&phyerr); 221 dfs_debug(dfs, WLAN_DEBUG_DFS, 222 "Stopping CAC Timer %d procphyerr 0x%08x", 223 dfs->dfs_curchan->dfs_ch_freq, phyerr); 224 qdf_timer_stop(&dfs->dfs_cac_timer); 225 dfs->dfs_cac_timer_running = 0; 226 } 227 228 void dfs_stacac_stop(struct wlan_dfs *dfs) 229 { 230 uint32_t phyerr; 231 232 dfs_get_debug_info(dfs, (void *)&phyerr); 233 dfs_debug(dfs, WLAN_DEBUG_DFS, 234 "Stopping STA CAC Timer %d procphyerr 0x%08x", 235 dfs->dfs_curchan->dfs_ch_freq, phyerr); 236 } 237