xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision dae10a5fbc53d54c53c4ba24fa018ad8b1e7c008)
1 /*
2  * Copyright (c) 2016-2018 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: This file contains NOL related functionality, NOL being the non
20  * occupancy list. After radar has been detected in a particular channel,
21  * the channel cannot be used for a period of 30 minutes which is called
22  * the non occupancy. The NOL is basically a list of all the channels that
23  * radar has been detected on. Each channel has a 30 minute timer associated
24  * with it. This file contains the functionality to add a channel to the NOL,
25  * the NOL timer  function and the functionality to remove a channel from the
26  * NOL when its time is up.
27  */
28 
29 #include "../dfs.h"
30 #include "../dfs_channel.h"
31 #include "../dfs_ioctl_private.h"
32 #include "../dfs_internal.h"
33 #include <qdf_time.h>
34 #include <wlan_dfs_mlme_api.h>
35 #include <wlan_dfs_utils_api.h>
36 #include <wlan_reg_services_api.h>
37 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
38 #include "../dfs_process_radar_found_ind.h"
39 #include "../dfs_partial_offload_radar.h"
40 #endif
41 
42 void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
43 {
44 	dfs->update_nol = val;
45 }
46 
47 bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
48 {
49 	return dfs->update_nol;
50 }
51 
52 /**
53  * dfs_nol_timeout() - NOL timeout function.
54  *
55  * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
56  */
57 static os_timer_func(dfs_nol_timeout)
58 {
59 	struct dfs_channel *c = NULL, lc;
60 	unsigned long oldest, now;
61 	struct wlan_dfs *dfs = NULL;
62 	int i;
63 	int nchans = 0;
64 
65 	c = &lc;
66 
67 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
68 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
69 
70 	now = oldest = qdf_system_ticks();
71 	for (i = 0; i < nchans; i++) {
72 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
73 				&(c->dfs_ch_freq),
74 				&(c->dfs_ch_flags),
75 				&(c->dfs_ch_flagext),
76 				&(c->dfs_ch_ieee),
77 				&(c->dfs_ch_vhtop_ch_freq_seg1),
78 				&(c->dfs_ch_vhtop_ch_freq_seg2),
79 				i);
80 		if (WLAN_IS_CHAN_RADAR(c)) {
81 			if (qdf_system_time_after_eq(now,
82 						dfs->dfs_nol_event[i] +
83 						dfs_get_nol_timeout(dfs))) {
84 				c->dfs_ch_flagext &=
85 					~WLAN_CHAN_DFS_RADAR_FOUND;
86 				if (c->dfs_ch_flags &
87 						WLAN_CHAN_DFS_RADAR) {
88 					/*
89 					 * NB: do this here so we get only one
90 					 * msg instead of one for every channel
91 					 * table entry.
92 					 */
93 					dfs_debug(dfs, WLAN_DEBUG_DFS,
94 						"radar on channel %u (%u MHz) cleared after timeout",
95 
96 						c->dfs_ch_ieee,
97 						c->dfs_ch_freq);
98 				}
99 			} else if (dfs->dfs_nol_event[i] < oldest)
100 				oldest = dfs->dfs_nol_event[i];
101 		}
102 	}
103 	if (oldest != now) {
104 		/* Arrange to process next channel up for a status change. */
105 		qdf_timer_mod(&dfs->dfs_nol_timer,
106 				dfs_get_nol_timeout(dfs) -
107 				qdf_system_ticks_to_msecs(qdf_system_ticks()));
108 	}
109 }
110 
111 /**
112  * dfs_nol_elem_free_work_cb -  Free NOL element
113  *
114  * Free the NOL element memory
115  */
116 static void dfs_nol_elem_free_work_cb(void *context)
117 {
118 	struct wlan_dfs *dfs = (struct wlan_dfs *)context;
119 	struct dfs_nolelem *tmp_nol_entry, *nol_entry;
120 
121 	WLAN_DFSNOL_LOCK(dfs);
122 	if (!TAILQ_EMPTY(&dfs->dfs_nol_free_list))
123 		TAILQ_FOREACH_SAFE(nol_entry,
124 				&dfs->dfs_nol_free_list,
125 				nolelem_list,
126 				tmp_nol_entry) {
127 			TAILQ_REMOVE(&dfs->dfs_nol_free_list,
128 					nol_entry, nolelem_list);
129 			WLAN_DFSNOL_UNLOCK(dfs);
130 			qdf_timer_free(&nol_entry->nol_timer);
131 			WLAN_DFSNOL_LOCK(dfs);
132 			qdf_mem_free(nol_entry);
133 		}
134 	WLAN_DFSNOL_UNLOCK(dfs);
135 }
136 
137 void dfs_nol_timer_init(struct wlan_dfs *dfs)
138 {
139 	qdf_timer_init(NULL,
140 			&(dfs->dfs_nol_timer),
141 			dfs_nol_timeout,
142 			(void *)(dfs),
143 			QDF_TIMER_TYPE_WAKE_APPS);
144 }
145 
146 void dfs_nol_attach(struct wlan_dfs *dfs)
147 {
148 	dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
149 	dfs_nol_timer_init(dfs);
150 	qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
151 			dfs_nol_elem_free_work_cb, dfs);
152 	TAILQ_INIT(&dfs->dfs_nol_free_list);
153 	dfs->dfs_use_nol = 1;
154 	WLAN_DFSNOL_LOCK_CREATE(dfs);
155 }
156 
157 void dfs_nol_detach(struct wlan_dfs *dfs)
158 {
159 	dfs_nol_timer_cleanup(dfs);
160 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
161 	qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
162 	WLAN_DFSNOL_LOCK_DESTROY(dfs);
163 }
164 
165 void dfs_nol_timer_detach(struct wlan_dfs *dfs)
166 {
167 	qdf_timer_free(&dfs->dfs_nol_timer);
168 }
169 
170 /**
171  * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
172  * @dfs: Pointer to wlan_dfs structure.
173  * @delfreq: Freq to delete.
174  * @delchwidth: Channel width to delete.
175  */
176 static void dfs_nol_delete(struct wlan_dfs *dfs,
177 		uint16_t delfreq,
178 		uint16_t delchwidth)
179 {
180 	struct dfs_nolelem *nol, **prev_next;
181 
182 	if (!dfs) {
183 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
184 		return;
185 	}
186 
187 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
188 		"remove channel=%d/%d MHz from NOL",
189 		 delfreq, delchwidth);
190 	prev_next = &(dfs->dfs_nol);
191 	nol = dfs->dfs_nol;
192 	while (nol != NULL) {
193 		if (nol->nol_freq == delfreq &&
194 			nol->nol_chwidth == delchwidth) {
195 			*prev_next = nol->nol_next;
196 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
197 				"removing channel %d/%dMHz from NOL tstamp=%d",
198 				 nol->nol_freq,
199 				nol->nol_chwidth,
200 				(qdf_system_ticks_to_msecs
201 				 (qdf_system_ticks()) / 1000));
202 			TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
203 						nol, nolelem_list);
204 			nol = *prev_next;
205 
206 			/* Update the NOL counter. */
207 			dfs->dfs_nol_count--;
208 
209 			/* Be paranoid! */
210 			if (dfs->dfs_nol_count < 0) {
211 				dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
212 				dfs->dfs_nol_count = 0;
213 			}
214 
215 		} else {
216 			prev_next = &(nol->nol_next);
217 			nol = nol->nol_next;
218 		}
219 	}
220 }
221 
222 /**
223  * dfs_remove_from_nol() - Remove the freq from NOL list.
224  *
225  * When NOL times out, this function removes the channel from NOL list.
226  */
227 static os_timer_func(dfs_remove_from_nol)
228 {
229 	struct dfs_nolelem *nol_arg;
230 	struct wlan_dfs *dfs;
231 	uint16_t delfreq;
232 	uint16_t delchwidth;
233 	uint8_t chan;
234 
235 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
236 
237 	dfs = nol_arg->nol_dfs;
238 	delfreq = nol_arg->nol_freq;
239 	delchwidth = nol_arg->nol_chwidth;
240 
241 	/* Delete the given NOL entry. */
242 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
243 
244 	/* Update the wireless stack with the new NOL. */
245 	dfs_nol_update(dfs);
246 
247 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
248 	chan = utils_dfs_freq_to_chan(delfreq);
249 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
250 		    "remove channel %d from nol", chan);
251 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
252 				    &chan, 1, DFS_NOL_RESET);
253 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
254 
255 	/*
256 	 * Free the NOL element in a thread. This is to avoid freeing the
257 	 * timer object from within timer callback function . The nol element
258 	 * contains the timer Object.
259 	 */
260 	qdf_sched_work(NULL, &dfs->dfs_nol_elem_free_work);
261 }
262 
263 void dfs_print_nol(struct wlan_dfs *dfs)
264 {
265 	struct dfs_nolelem *nol;
266 	int i = 0;
267 	uint32_t diff_ms, remaining_sec;
268 
269 	if (!dfs) {
270 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
271 		return;
272 	}
273 
274 	nol = dfs->dfs_nol;
275 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
276 	while (nol != NULL) {
277 		diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
278 				nol->nol_start_ticks);
279 		diff_ms = (nol->nol_timeout_ms - diff_ms);
280 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
281 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
282 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol starttick=%llu",
283 			i++, nol->nol_freq,
284 			nol->nol_chwidth,
285 			remaining_sec,
286 			(uint64_t)nol->nol_start_ticks);
287 		nol = nol->nol_next;
288 	}
289 }
290 
291 void dfs_print_nolhistory(struct wlan_dfs *dfs)
292 {
293 	struct dfs_channel *c, lc;
294 	int i, j = 0;
295 	int nchans = 0;
296 
297 	if (!dfs) {
298 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
299 		return;
300 	}
301 
302 	c = &lc;
303 
304 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
305 	for (i = 0; i < nchans; i++) {
306 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
307 				&(c->dfs_ch_freq),
308 				&(c->dfs_ch_flags),
309 				&(c->dfs_ch_flagext),
310 				&(c->dfs_ch_ieee),
311 				&(c->dfs_ch_vhtop_ch_freq_seg1),
312 				&(c->dfs_ch_vhtop_ch_freq_seg2),
313 				i);
314 		if (WLAN_IS_CHAN_HISTORY_RADAR(c)) {
315 			dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
316 				"nolhistory:%d channel=%d MHz Flags=%llx",
317 				j, c->dfs_ch_freq, c->dfs_ch_flags);
318 			j++;
319 		}
320 	}
321 }
322 
323 void dfs_get_nol(struct wlan_dfs *dfs,
324 		struct dfsreq_nolelem *dfs_nol,
325 		int *nchan)
326 {
327 	struct dfs_nolelem *nol;
328 
329 	*nchan = 0;
330 
331 	if (!dfs) {
332 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
333 		return;
334 	}
335 
336 	nol = dfs->dfs_nol;
337 	while (nol != NULL) {
338 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
339 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
340 		dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks;
341 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
342 		++(*nchan);
343 		nol = nol->nol_next;
344 	}
345 }
346 
347 void dfs_set_nol(struct wlan_dfs *dfs,
348 		struct dfsreq_nolelem *dfs_nol,
349 		int nchan)
350 {
351 #define TIME_IN_MS 1000
352 	uint32_t nol_time_left_ms;
353 	struct dfs_channel chan;
354 	int i;
355 	uint8_t chan_num;
356 
357 	if (!dfs) {
358 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
359 		return;
360 	}
361 
362 	for (i = 0; i < nchan; i++) {
363 		nol_time_left_ms =
364 			qdf_system_ticks_to_msecs(qdf_system_ticks() -
365 				dfs_nol[i].nol_start_ticks);
366 
367 		if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
368 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
369 			chan.dfs_ch_flags = 0;
370 			chan.dfs_ch_flagext = 0;
371 			nol_time_left_ms =
372 				(dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
373 
374 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
375 					(nol_time_left_ms / TIME_IN_MS));
376 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
377 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
378 						&chan_num, 1, DFS_NOL_SET);
379 		}
380 	}
381 #undef TIME_IN_MS
382 	dfs_nol_update(dfs);
383 }
384 
385 void dfs_nol_addchan(struct wlan_dfs *dfs,
386 		uint16_t freq,
387 		uint32_t dfs_nol_timeout)
388 {
389 #define TIME_IN_MS 1000
390 #define TIME_IN_US (TIME_IN_MS * 1000)
391 	struct dfs_nolelem *nol, *elem, *prev;
392 	/* For now, assume all events are 20MHz wide. */
393 	int ch_width = 20;
394 
395 	if (!dfs) {
396 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
397 		return;
398 	}
399 	nol = dfs->dfs_nol;
400 	prev = dfs->dfs_nol;
401 	elem = NULL;
402 	while (nol != NULL) {
403 		if ((nol->nol_freq == freq) &&
404 				(nol->nol_chwidth == ch_width)) {
405 			nol->nol_start_ticks = qdf_system_ticks();
406 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
407 
408 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
409 				"Update OS Ticks for NOL %d MHz / %d MHz",
410 				 nol->nol_freq, nol->nol_chwidth);
411 
412 			qdf_timer_stop(&nol->nol_timer);
413 			qdf_timer_mod(&nol->nol_timer,
414 					dfs_nol_timeout * TIME_IN_MS);
415 			return;
416 		}
417 		prev = nol;
418 		nol = nol->nol_next;
419 	}
420 
421 	/* Add a new element to the NOL. */
422 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
423 	if (!elem)
424 		goto bad;
425 
426 	qdf_mem_zero(elem, sizeof(*elem));
427 	elem->nol_dfs = dfs;
428 	elem->nol_freq = freq;
429 	elem->nol_chwidth = ch_width;
430 	elem->nol_start_ticks = qdf_system_ticks();
431 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
432 	elem->nol_next = NULL;
433 	if (prev) {
434 		prev->nol_next = elem;
435 	} else {
436 		/* This is the first element in the NOL. */
437 		dfs->dfs_nol = elem;
438 	}
439 
440 	qdf_timer_init(NULL,
441 			&elem->nol_timer, dfs_remove_from_nol,
442 			elem, QDF_TIMER_TYPE_WAKE_APPS);
443 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
444 
445 	/* Update the NOL counter. */
446 	dfs->dfs_nol_count++;
447 
448 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
449 		"new NOL channel %d MHz / %d MHz",
450 		 elem->nol_freq, elem->nol_chwidth);
451 	return;
452 
453 bad:
454 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
455 		"failed to allocate memory for nol entry");
456 
457 #undef TIME_IN_MS
458 #undef TIME_IN_US
459 }
460 
461 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
462 		uint32_t *nol_chfreq,
463 		uint32_t *nol_chwidth,
464 		int index)
465 {
466 	if (!dfs_nol)
467 		return;
468 
469 	*nol_chfreq = dfs_nol[index].nol_freq;
470 	*nol_chwidth = dfs_nol[index].nol_chwidth;
471 }
472 
473 void dfs_nol_update(struct wlan_dfs *dfs)
474 {
475 	struct dfsreq_nolelem *dfs_nol;
476 	int nlen;
477 
478 	if (!dfs->dfs_nol_count) {
479 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
480 		return;
481 	}
482 
483 	/*
484 	 * Allocate enough entries to store the NOL. At least on Linux
485 	 * (don't ask why), if you allocate a 0 entry array, the
486 	 * returned pointer is 0x10.  Make sure you're aware of this
487 	 * when you start debugging.
488 	 */
489 	dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
490 		sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
491 
492 	if (!dfs_nol) {
493 		/*
494 		 * XXX TODO: if this fails, just schedule a task to retry
495 		 * updating the NOL at a later stage.  That way the NOL
496 		 * update _DOES_ happen - hopefully the failure was just
497 		 * temporary.
498 		 */
499 		dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS, "failed to allocate NOL update memory!");
500 		return;
501 	}
502 
503 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
504 
505 	/* Be suitably paranoid for now. */
506 	if (nlen != dfs->dfs_nol_count)
507 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
508 			 nlen, dfs->dfs_nol_count);
509 
510 	/*
511 	 * Call the driver layer to have it recalculate the NOL flags
512 	 * for each driver/umac channel. If the list is empty, pass
513 	 * NULL instead of dfs_nol. The operating system may have some
514 	 * special representation for "malloc a 0 byte memory region"
515 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
516 	 * than a valid allocation (and is likely not NULL so the
517 	 * pointer doesn't match NULL checks in any later code.
518 	 */
519 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
520 			(nlen > 0) ? dfs_nol : NULL,
521 			nlen);
522 
523 	qdf_mem_free(dfs_nol);
524 }
525 
526 void dfs_nol_free_list(struct wlan_dfs *dfs)
527 {
528 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
529 
530 	while (nol) {
531 		prev = nol;
532 		nol = nol->nol_next;
533 		qdf_mem_free(prev);
534 		/* Update the NOL counter. */
535 		dfs->dfs_nol_count--;
536 
537 		if (dfs->dfs_nol_count < 0) {
538 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
539 			ASSERT(0);
540 		}
541 	}
542 
543 	dfs->dfs_nol = NULL;
544 }
545 
546 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
547 {
548 	struct dfs_nolelem *nol;
549 
550 	WLAN_DFSNOL_LOCK(dfs);
551 	nol = dfs->dfs_nol;
552 	while (nol) {
553 		dfs->dfs_nol = nol->nol_next;
554 		dfs->dfs_nol_count--;
555 		/*
556 		 * Unlock is required so that when we sync with the
557 		 * nol_timeout timer we do not run into deadlock.
558 		 */
559 		WLAN_DFSNOL_UNLOCK(dfs);
560 		qdf_timer_free(&nol->nol_timer);
561 		WLAN_DFSNOL_LOCK(dfs);
562 
563 		qdf_mem_free(nol);
564 		nol = dfs->dfs_nol;
565 	}
566 	WLAN_DFSNOL_UNLOCK(dfs);
567 }
568 
569 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
570 {
571 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
572 }
573 
574 int dfs_get_use_nol(struct wlan_dfs *dfs)
575 {
576 	return dfs->dfs_use_nol;
577 }
578 
579 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
580 {
581 	return dfs->wlan_dfs_nol_timeout;
582 }
583 
584 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
585 {
586 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
587 
588 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
589 }
590 
591 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
592 {
593 	/* We should have a dfs_clear_nolhistory API from Regdomain. */
594 	struct dfs_channel *c, lc;
595 	int i;
596 	int nchans = 0;
597 
598 	c = &lc;
599 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
600 	for (i = 0; i < nchans; i++) {
601 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
602 				&(c->dfs_ch_freq),
603 				&(c->dfs_ch_flags),
604 				&(c->dfs_ch_flagext),
605 				&(c->dfs_ch_ieee),
606 				&(c->dfs_ch_vhtop_ch_freq_seg1),
607 				&(c->dfs_ch_vhtop_ch_freq_seg2),
608 				i);
609 		WLAN_CHAN_CLR_HISTORY_RADAR(c);
610 	}
611 }
612 
613 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
614 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
615 {
616 	struct dfs_nolelem *nol;
617 	uint8_t channels[NUM_CHANNELS_160MHZ];
618 	int i, nchans = 0;
619 
620 	nchans = dfs_get_bonding_channels(&dfs->dfs_radar_found_chan, 0,
621 					  channels);
622 
623 	WLAN_DFSNOL_LOCK(dfs);
624 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
625 		nol = dfs->dfs_nol;
626 		while (nol) {
627 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
628 				    channels[i])) {
629 				OS_SET_TIMER(&nol->nol_timer, 0);
630 				break;
631 			}
632 			nol = nol->nol_next;
633 		}
634 	}
635 	WLAN_DFSNOL_UNLOCK(dfs);
636 
637 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
638 				    channels, nchans, DFS_NOL_RESET);
639 }
640 #endif
641