1 /* 2 * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2002-2010, Atheros Communications Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: DFS specs specify various types of radars to be detected. 20 * Each separate type is called a Bin and has different characteristics. 21 * This file contains the functionality to look at a group of pulses and 22 * to detect whether we have detected a valid radar waveform. To do that, 23 * it must match the group against each different Bin's characteristics. 24 */ 25 26 #include "../dfs.h" 27 28 int dfs_bin_fixedpattern_check(struct wlan_dfs *dfs, 29 struct dfs_filter *rf, 30 uint32_t dur, 31 int ext_chan_flag) 32 { 33 struct dfs_pulseline *pl = dfs->pulses; 34 int i, n, refpri, primargin, numpulses = 0; 35 uint64_t start_ts, end_ts, event_ts, prev_event_ts; 36 uint64_t next_event_ts, window_start, window_end; 37 uint32_t index, next_index, deltadur; 38 39 /* For fixed pattern types, rf->rf_patterntype=1. */ 40 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 41 (rf->rf_patterntype == 1)); 42 43 refpri = (rf->rf_minpri + rf->rf_maxpri)/2; 44 index = pl->pl_lastelem; 45 end_ts = pl->pl_elems[index].p_time; 46 start_ts = end_ts - (refpri*rf->rf_numpulses); 47 48 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS3, 49 "lastelem ts=%llu start_ts=%llu, end_ts=%llu\n", 50 (unsigned long long)pl->pl_elems[index].p_time, 51 (unsigned long long)start_ts, 52 (unsigned long long) end_ts); 53 54 /* Find the index of first element in our window of interest. */ 55 for (i = 0; i < pl->pl_numelems; i++) { 56 index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; 57 if (pl->pl_elems[index].p_time >= start_ts) 58 continue; 59 else { 60 index = (index) & DFS_MAX_PULSE_BUFFER_MASK; 61 break; 62 } 63 } 64 for (n = 0; n <= rf->rf_numpulses; n++) { 65 window_start = (start_ts + (refpri*n))-(primargin+n); 66 window_end = window_start + 2*(primargin+n); 67 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, 68 "window_start %u window_end %u\n", 69 (uint32_t)window_start, (uint32_t)window_end); 70 71 for (i = 0; i < pl->pl_numelems; i++) { 72 prev_event_ts = pl->pl_elems[index].p_time; 73 index = (index+1) & DFS_MAX_PULSE_BUFFER_MASK; 74 event_ts = pl->pl_elems[index].p_time; 75 next_index = (index+1) & DFS_MAX_PULSE_BUFFER_MASK; 76 next_event_ts = pl->pl_elems[next_index].p_time; 77 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, "ts %u\n", 78 (uint32_t)event_ts); 79 80 if ((event_ts <= window_end) && 81 (event_ts >= window_start)) { 82 deltadur = DFS_DIFF(pl->pl_elems[index].p_dur, 83 dur); 84 if ((pl->pl_elems[index].p_dur == 1) || 85 ((dur != 1) && (deltadur <= 2))) { 86 numpulses++; 87 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, 88 "numpulses %u\n", numpulses); 89 break; 90 } 91 } else if (event_ts > window_end) { 92 index = (index-1) & DFS_MAX_PULSE_BUFFER_MASK; 93 break; 94 } else if (event_ts == prev_event_ts) { 95 if (((next_event_ts - event_ts) > refpri) || 96 ((next_event_ts - event_ts) == 0)) { 97 deltadur = 98 DFS_DIFF(pl->pl_elems[index].p_dur, 99 dur); 100 if ((pl->pl_elems[index].p_dur == 1) || 101 ((pl->pl_elems[index].p_dur != 102 1) && (deltadur <= 2))) { 103 numpulses++; 104 DFS_DPRINTK(dfs, 105 WLAN_DEBUG_DFS2, 106 "zero PRI: numpulses %u\n", 107 numpulses); 108 break; 109 } 110 } 111 } 112 } 113 } 114 if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { 115 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS1, 116 "%s FOUND filterID=%u numpulses=%d unadj thresh=%d\n", 117 __func__, rf->rf_pulseid, numpulses, rf->rf_threshold); 118 return 1; 119 } else 120 return 0; 121 } 122 123 void dfs_add_pulse(struct wlan_dfs *dfs, 124 struct dfs_filter *rf, 125 struct dfs_event *re, 126 uint32_t deltaT, 127 uint64_t this_ts) 128 { 129 uint32_t index, n, window; 130 struct dfs_delayline *dl; 131 132 dl = &rf->rf_dl; 133 /* Circular buffer of size 2^n */ 134 index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK; 135 if ((dl->dl_numelems) == DFS_MAX_DL_SIZE) 136 dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK; 137 else 138 dl->dl_numelems++; 139 dl->dl_lastelem = index; 140 dl->dl_elems[index].de_time = deltaT; 141 dl->dl_elems[index].de_ts = this_ts; 142 window = deltaT; 143 dl->dl_elems[index].de_dur = re->re_dur; 144 dl->dl_elems[index].de_rssi = re->re_rssi; 145 146 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, 147 "%s: adding: filter id %d, dur=%d, rssi=%d, ts=%llu\n", 148 __func__, rf->rf_pulseid, re->re_dur, 149 re->re_rssi, (unsigned long long int)this_ts); 150 151 for (n = 0; n < dl->dl_numelems-1; n++) { 152 index = (index-1) & DFS_MAX_DL_MASK; 153 /* 154 * Calculate window based on full time stamp instead of deltaT 155 * deltaT (de_time) may result in incorrect window value 156 */ 157 window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts); 158 159 if (window > rf->rf_filterlen) { 160 dl->dl_firstelem = (index+1) & DFS_MAX_DL_MASK; 161 dl->dl_numelems = n+1; 162 } 163 } 164 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d lastElem = %d\n", 165 dl->dl_firstelem, dl->dl_lastelem); 166 } 167 168 int dfs_bin_check(struct wlan_dfs *dfs, 169 struct dfs_filter *rf, 170 uint32_t deltaT, 171 uint32_t width, 172 int ext_chan_flag) 173 { 174 struct dfs_delayline *dl; 175 uint32_t refpri, refdur, searchpri, deltapri, deltapri_2, deltapri_3; 176 uint32_t averagerefpri, n, i, primargin, durmargin, highscore; 177 uint32_t highscoreindex; 178 int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0; 179 uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; 180 int numpulses = 0; 181 int lowprichk = 3, pri_match = 0; 182 183 dl = &rf->rf_dl; 184 if (dl->dl_numelems < (rf->rf_threshold-1)) 185 return 0; 186 187 if (deltaT > rf->rf_filterlen) 188 return 0; 189 190 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 191 (rf->rf_patterntype == 1)); 192 193 if (rf->rf_maxdur < 10) 194 durmargin = 4; 195 else 196 durmargin = 6; 197 198 if (rf->rf_patterntype == 1) { 199 found = dfs_bin_fixedpattern_check(dfs, rf, width, 200 ext_chan_flag); 201 if (found) 202 dl->dl_numelems = 0; 203 return found; 204 } 205 206 qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE); 207 /* Find out the lowest pri. */ 208 for (n = 0; n < dl->dl_numelems; n++) { 209 delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 210 refpri = dl->dl_elems[delayindex].de_time; 211 if (refpri == 0) { 212 continue; 213 } else if (refpri < lowpri) { 214 lowpri = dl->dl_elems[delayindex].de_time; 215 lowpriindex = n; 216 } 217 } 218 /* Find out the each delay element's pri score. */ 219 for (n = 0; n < dl->dl_numelems; n++) { 220 delayindex = (dl->dl_firstelem + n) & 221 DFS_MAX_DL_MASK; 222 refpri = dl->dl_elems[delayindex].de_time; 223 if (refpri == 0) 224 continue; 225 if (refpri < rf->rf_maxpri) { 226 /* Use only valid PRI range for high score. */ 227 for (i = 0; i < dl->dl_numelems; i++) { 228 dindex = (dl->dl_firstelem + i) & 229 DFS_MAX_DL_MASK; 230 searchpri = dl->dl_elems[dindex].de_time; 231 deltapri = DFS_DIFF(searchpri, refpri); 232 deltapri_2 = DFS_DIFF(searchpri, 2*refpri); 233 deltapri_3 = DFS_DIFF(searchpri, 3*refpri); 234 if (rf->rf_ignore_pri_window == 2) { 235 pri_match = ((deltapri < primargin) || 236 (deltapri_2 < primargin) || 237 (deltapri_3 < primargin)); 238 } else { 239 pri_match = (deltapri < primargin); 240 } 241 if (pri_match) 242 score[n]++; 243 } 244 } else { 245 score[n] = 0; 246 } 247 if (score[n] > rf->rf_threshold) { 248 /* 249 * We got the most possible candidate, 250 * no need to continue further. 251 */ 252 break; 253 } 254 } 255 256 /* Find out the high scorer. */ 257 highscore = 0; 258 highscoreindex = 0; 259 for (n = 0; n < dl->dl_numelems; n++) { 260 if (score[n] > highscore) { 261 highscore = score[n]; 262 highscoreindex = n; 263 } else if (score[n] == highscore) { 264 /* 265 * More than one pri has highscore take the least pri. 266 */ 267 delayindex = (dl->dl_firstelem + highscoreindex) & 268 DFS_MAX_DL_MASK; 269 dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 270 if (dl->dl_elems[dindex].de_time <= 271 dl->dl_elems[delayindex].de_time) { 272 highscoreindex = n; 273 } 274 } 275 } 276 277 /* 278 * Find the average pri of pulses around the pri of highscore 279 * or the pulses around the lowest pri. 280 */ 281 if (rf->rf_ignore_pri_window > 0) 282 lowprichk = (rf->rf_threshold >> 1)+1; 283 else 284 lowprichk = 3; 285 286 if (highscore < lowprichk) 287 scoreindex = lowpriindex; 288 else 289 scoreindex = highscoreindex; 290 291 /* We got the possible pri, save its parameters as reference. */ 292 delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK; 293 refdur = dl->dl_elems[delayindex].de_dur; 294 refpri = dl->dl_elems[delayindex].de_time; 295 averagerefpri = 0; 296 297 if (rf->rf_fixed_pri_radar_pulse) 298 refpri = (rf->rf_minpri + rf->rf_maxpri)/2; 299 300 numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri, 301 refdur, ext_chan_flag, refpri); 302 if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { 303 found = 1; 304 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS1, 305 "ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d\n", 306 ext_chan_flag, rf->rf_pulseid, numpulses, 307 rf->rf_threshold, refdur, refpri, primargin); 308 dfs_print_delayline(dfs, &rf->rf_dl); 309 dfs_print_filter(dfs, rf); 310 } 311 312 return found; 313 } 314 315 void count_the_other_delay_elements(struct wlan_dfs *dfs, 316 struct dfs_filter *rf, 317 struct dfs_delayline *dl, 318 uint32_t i, 319 uint32_t refpri, 320 uint32_t refdur, 321 uint32_t primargin, 322 uint32_t durmargin, 323 int *numpulses, 324 uint32_t *prev_good_timestamp, 325 int fundamentalpri 326 ) 327 { 328 int delayindex; 329 uint32_t searchpri, searchdur, deltadur, deltapri1, deltapri2; 330 uint32_t j = 0, delta_time_stamps, delta_ts_variance, deltapri; 331 int dindex, primatch, numpulsetochk = 2; 332 333 delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; 334 searchpri = dl->dl_elems[delayindex].de_time; 335 if (searchpri == 0) { 336 /* 337 * This events PRI is zero, take it as a valid pulse 338 * but decrement next event's PRI by refpri. 339 */ 340 dindex = (delayindex + 1) & DFS_MAX_DL_MASK; 341 dl->dl_elems[dindex].de_time -= refpri; 342 searchpri = refpri; 343 } 344 searchdur = dl->dl_elems[delayindex].de_dur; 345 deltadur = DFS_DIFF(searchdur, refdur); 346 deltapri = DFS_DIFF(searchpri, refpri); 347 deltapri1 = DFS_DIFF(searchpri, refpri); 348 deltapri2 = DFS_DIFF(searchpri, 2 * refpri); 349 primatch = 0; 350 351 if ((rf->rf_ignore_pri_window > 0) && 352 (rf->rf_patterntype != 2)) { 353 for (j = 0; j < rf->rf_numpulses; j++) { 354 deltapri1 = DFS_DIFF(searchpri, 355 (j + 1) * refpri); 356 if (deltapri1 < (2 * primargin)) { 357 primatch = 1; 358 break; 359 } 360 } 361 } else { 362 if ((deltapri1 < primargin) || 363 (deltapri2 < primargin)) { 364 primatch = 1; 365 } 366 } 367 368 if (primatch && (deltadur < durmargin)) { 369 if ((*numpulses == 1)) { 370 (*numpulses)++; 371 } else { 372 delta_time_stamps = (dl->dl_elems[delayindex].de_ts - 373 *prev_good_timestamp); 374 if ((rf->rf_ignore_pri_window > 0)) { 375 numpulsetochk = rf->rf_numpulses; 376 if ((rf->rf_patterntype == 2) && 377 (fundamentalpri < refpri + 100)) { 378 numpulsetochk = 4; 379 } 380 } else { 381 numpulsetochk = 4; 382 } 383 for (j = 0; j < numpulsetochk; j++) { 384 delta_ts_variance = DFS_DIFF(delta_time_stamps, 385 ((j + 1) * fundamentalpri)); 386 if (delta_ts_variance < 387 (2 * (j + 1) * primargin)) { 388 (*numpulses)++; 389 if (rf->rf_ignore_pri_window > 0) 390 break; 391 } 392 } 393 } 394 *prev_good_timestamp = dl->dl_elems[delayindex].de_ts; 395 396 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, 397 "rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d deltapri=%d j=%d\n", 398 rf->rf_minpri, rf->rf_maxpri, searchpri, 399 i, *numpulses, deltapri, j); 400 } 401 } 402 403 int dfs_bin_pri_check(struct wlan_dfs *dfs, 404 struct dfs_filter *rf, 405 struct dfs_delayline *dl, 406 uint32_t score, 407 uint32_t refpri, 408 uint32_t refdur, 409 int ext_chan_flag, 410 int fundamentalpri) 411 { 412 uint32_t searchpri, deltapri = 0; 413 uint32_t averagerefpri = 0, MatchCount = 0; 414 uint32_t prev_good_timestamp = 0; 415 int dindex; 416 uint32_t i, primargin, durmargin, highscore = score; 417 uint32_t highscoreindex = 0; 418 /* 419 * First pulse in the burst is most likely being filtered out based on 420 * maxfilterlen. 421 */ 422 int numpulses = 1; 423 int priscorechk = 1; 424 425 /* Use the adjusted PRI margin to reduce false alarms 426 * For non fixed pattern types, rf->rf_patterntype=0. 427 */ 428 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 429 (rf->rf_patterntype == 1)); 430 431 if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { 432 numpulses = 0; 433 return numpulses; 434 } 435 436 if (rf->rf_maxdur < 10) 437 durmargin = 4; 438 else 439 durmargin = 6; 440 441 if ((!rf->rf_fixed_pri_radar_pulse)) { 442 if (rf->rf_ignore_pri_window == 1) 443 priscorechk = (rf->rf_threshold >> 1); 444 else 445 priscorechk = 1; 446 447 MatchCount = 0; 448 if (score > priscorechk) { 449 for (i = 0; i < dl->dl_numelems; i++) { 450 dindex = (dl->dl_firstelem + i) & 451 DFS_MAX_DL_MASK; 452 searchpri = dl->dl_elems[dindex].de_time; 453 deltapri = DFS_DIFF(searchpri, refpri); 454 if (deltapri < primargin) { 455 averagerefpri += searchpri; 456 MatchCount++; 457 } 458 } 459 if (rf->rf_patterntype != 2) { 460 if (MatchCount > 0) 461 refpri = (averagerefpri / MatchCount); 462 } else { 463 refpri = (averagerefpri / score); 464 } 465 } 466 } 467 468 /* Note: Following primultiple calculation should be done 469 * once per filter during initialization stage (dfs_attach) 470 * and stored in its array atleast for fixed frequency 471 * types like FCC Bin1 to save some CPU cycles. 472 * multiplication, devide operators in the following code 473 * are left as it is for readability hoping the complier 474 * will use left/right shifts wherever possible. 475 */ 476 DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, 477 "refpri = %d high score = %d index = %d numpulses = %d\n", 478 refpri, highscore, highscoreindex, numpulses); 479 /* 480 * Count the other delay elements that have pri and dur with 481 * in the acceptable range from the reference one. 482 */ 483 for (i = 0; i < dl->dl_numelems; i++) 484 count_the_other_delay_elements(dfs, rf, dl, i, refpri, refdur, 485 primargin, durmargin, &numpulses, &prev_good_timestamp, 486 fundamentalpri); 487 488 return numpulses; 489 } 490