xref: /wlan-driver/qcacld-3.0/components/nan/core/src/nan_api.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: contains nan public API function definitions
22  */
23 
24 #include "nan_main_i.h"
25 #include "wlan_nan_api.h"
26 #include "target_if_nan.h"
27 #include "nan_public_structs.h"
28 #include "wlan_objmgr_cmn.h"
29 #include "wlan_objmgr_global_obj.h"
30 #include "wlan_objmgr_psoc_obj.h"
31 #include "wlan_objmgr_pdev_obj.h"
32 #include "wlan_objmgr_vdev_obj.h"
33 #include "nan_ucfg_api.h"
34 #include <wlan_mlme_api.h>
35 
nan_psoc_obj_created_notification(struct wlan_objmgr_psoc * psoc,void * arg_list)36 static QDF_STATUS nan_psoc_obj_created_notification(
37 		struct wlan_objmgr_psoc *psoc, void *arg_list)
38 {
39 	QDF_STATUS status = QDF_STATUS_SUCCESS;
40 	struct nan_psoc_priv_obj *nan_obj;
41 
42 	nan_debug("nan_psoc_create_notif called");
43 	nan_obj = qdf_mem_malloc(sizeof(*nan_obj));
44 	if (!nan_obj)
45 		return QDF_STATUS_E_NOMEM;
46 
47 	qdf_spinlock_create(&nan_obj->lock);
48 	status = wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_NAN,
49 						       nan_obj,
50 						       QDF_STATUS_SUCCESS);
51 	if (QDF_IS_STATUS_ERROR(status)) {
52 		nan_alert("obj attach with psoc failed");
53 		goto nan_psoc_notif_failed;
54 	}
55 
56 	target_if_nan_register_tx_ops(&nan_obj->tx_ops);
57 	target_if_nan_register_rx_ops(&nan_obj->rx_ops);
58 
59 	return QDF_STATUS_SUCCESS;
60 
61 nan_psoc_notif_failed:
62 
63 	qdf_spinlock_destroy(&nan_obj->lock);
64 	qdf_mem_free(nan_obj);
65 	return status;
66 }
67 
nan_psoc_obj_destroyed_notification(struct wlan_objmgr_psoc * psoc,void * arg_list)68 static QDF_STATUS nan_psoc_obj_destroyed_notification(
69 				struct wlan_objmgr_psoc *psoc, void *arg_list)
70 {
71 	QDF_STATUS status = QDF_STATUS_SUCCESS;
72 	struct nan_psoc_priv_obj *nan_obj = nan_get_psoc_priv_obj(psoc);
73 
74 	nan_debug("nan_psoc_delete_notif called");
75 	if (!nan_obj) {
76 		nan_err("nan_obj is NULL");
77 		return QDF_STATUS_E_FAULT;
78 	}
79 
80 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
81 						       WLAN_UMAC_COMP_NAN,
82 						       nan_obj);
83 	if (QDF_IS_STATUS_ERROR(status))
84 		nan_err("nan_obj detach failed");
85 
86 	nan_debug("nan_obj deleted with status %d", status);
87 	qdf_spinlock_destroy(&nan_obj->lock);
88 	qdf_mem_free(nan_obj);
89 
90 	return status;
91 }
92 
nan_vdev_obj_created_notification(struct wlan_objmgr_vdev * vdev,void * arg_list)93 static QDF_STATUS nan_vdev_obj_created_notification(
94 		struct wlan_objmgr_vdev *vdev, void *arg_list)
95 {
96 	struct nan_vdev_priv_obj *nan_obj;
97 	QDF_STATUS status = QDF_STATUS_SUCCESS;
98 	struct wlan_objmgr_psoc *psoc;
99 
100 	nan_debug("nan_vdev_create_notif called");
101 	if (ucfg_is_nan_vdev(vdev)) {
102 		psoc = wlan_vdev_get_psoc(vdev);
103 		if (!psoc) {
104 			nan_err("psoc is NULL");
105 			return QDF_STATUS_E_INVAL;
106 		}
107 		target_if_nan_set_vdev_feature_config(psoc,
108 						      wlan_vdev_get_id(vdev));
109 	}
110 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) {
111 		nan_debug("not a ndi vdev. do nothing");
112 		return QDF_STATUS_SUCCESS;
113 	}
114 
115 	nan_obj = qdf_mem_malloc(sizeof(*nan_obj));
116 	if (!nan_obj)
117 		return QDF_STATUS_E_NOMEM;
118 
119 	qdf_spinlock_create(&nan_obj->lock);
120 	status = wlan_objmgr_vdev_component_obj_attach(vdev, WLAN_UMAC_COMP_NAN,
121 						       (void *)nan_obj,
122 						       QDF_STATUS_SUCCESS);
123 	if (QDF_IS_STATUS_ERROR(status)) {
124 		nan_alert("obj attach with vdev failed");
125 		goto nan_vdev_notif_failed;
126 	}
127 
128 	return QDF_STATUS_SUCCESS;
129 
130 nan_vdev_notif_failed:
131 
132 	qdf_spinlock_destroy(&nan_obj->lock);
133 	qdf_mem_free(nan_obj);
134 	return status;
135 }
136 
nan_vdev_obj_destroyed_notification(struct wlan_objmgr_vdev * vdev,void * arg_list)137 static QDF_STATUS nan_vdev_obj_destroyed_notification(
138 				struct wlan_objmgr_vdev *vdev, void *arg_list)
139 {
140 	struct nan_vdev_priv_obj *nan_obj;
141 	QDF_STATUS status = QDF_STATUS_SUCCESS;
142 
143 	nan_debug("nan_vdev_delete_notif called");
144 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) {
145 		nan_debug("not a ndi vdev. do nothing");
146 		return QDF_STATUS_SUCCESS;
147 	}
148 
149 	nan_obj = nan_get_vdev_priv_obj(vdev);
150 	if (!nan_obj) {
151 		nan_err("nan_obj is NULL");
152 		return QDF_STATUS_E_FAULT;
153 	}
154 
155 	status = wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_NAN,
156 						       nan_obj);
157 	if (QDF_IS_STATUS_ERROR(status))
158 		nan_err("nan_obj detach failed");
159 
160 	nan_debug("nan_obj deleted with status %d", status);
161 	qdf_spinlock_destroy(&nan_obj->lock);
162 	qdf_mem_free(nan_obj);
163 
164 	return status;
165 }
166 
167 /**
168  * nan_peer_obj_created_notification() - Handler for peer object creation
169  * notification event
170  * @peer: Pointer to the PEER Object
171  * @arg_list: Pointer to private argument - NULL
172  *
173  * This function gets called from object manager when peer is being
174  * created.
175  *
176  * Return: QDF_STATUS
177  */
nan_peer_obj_created_notification(struct wlan_objmgr_peer * peer,void * arg_list)178 static QDF_STATUS nan_peer_obj_created_notification(
179 		struct wlan_objmgr_peer *peer, void *arg_list)
180 {
181 	struct nan_peer_priv_obj *nan_peer_obj;
182 	QDF_STATUS status = QDF_STATUS_SUCCESS;
183 
184 	nan_peer_obj = qdf_mem_malloc(sizeof(*nan_peer_obj));
185 	if (!nan_peer_obj)
186 		return QDF_STATUS_E_NOMEM;
187 
188 	qdf_spinlock_create(&nan_peer_obj->lock);
189 	status = wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_NAN,
190 						       (void *)nan_peer_obj,
191 						       QDF_STATUS_SUCCESS);
192 	if (QDF_IS_STATUS_ERROR(status)) {
193 		nan_alert("obj attach with peer failed");
194 		goto nan_peer_notif_failed;
195 	}
196 
197 	return QDF_STATUS_SUCCESS;
198 
199 nan_peer_notif_failed:
200 
201 	qdf_spinlock_destroy(&nan_peer_obj->lock);
202 	qdf_mem_free(nan_peer_obj);
203 	return status;
204 }
205 
206 /**
207  * nan_peer_obj_destroyed_notification() - Handler for peer object deletion
208  * notification event
209  * @peer: Pointer to the PEER Object
210  * @arg_list: Pointer to private argument - NULL
211  *
212  * This function gets called from object manager when peer is being destroyed.
213  *
214  * Return: QDF_STATUS
215  */
nan_peer_obj_destroyed_notification(struct wlan_objmgr_peer * peer,void * arg_list)216 static QDF_STATUS nan_peer_obj_destroyed_notification(
217 				struct wlan_objmgr_peer *peer, void *arg_list)
218 {
219 	struct nan_peer_priv_obj *nan_peer_obj;
220 	QDF_STATUS status = QDF_STATUS_SUCCESS;
221 
222 	nan_peer_obj = nan_get_peer_priv_obj(peer);
223 	if (!nan_peer_obj) {
224 		nan_err("nan_peer_obj is NULL");
225 		return QDF_STATUS_E_FAULT;
226 	}
227 
228 	status = wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_NAN,
229 						       nan_peer_obj);
230 	if (QDF_IS_STATUS_ERROR(status))
231 		nan_err("nan_peer_obj detach failed");
232 
233 	nan_debug("nan_peer_obj deleted with status %d", status);
234 	qdf_spinlock_destroy(&nan_peer_obj->lock);
235 	qdf_mem_free(nan_peer_obj);
236 
237 	return status;
238 }
239 
nan_init(void)240 QDF_STATUS nan_init(void)
241 {
242 	QDF_STATUS status;
243 
244 	/* register psoc create handler functions. */
245 	status = wlan_objmgr_register_psoc_create_handler(
246 		WLAN_UMAC_COMP_NAN,
247 		nan_psoc_obj_created_notification,
248 		NULL);
249 	if (QDF_IS_STATUS_ERROR(status)) {
250 		nan_err("wlan_objmgr_register_psoc_create_handler failed");
251 		return status;
252 	}
253 
254 	/* register psoc delete handler functions. */
255 	status = wlan_objmgr_register_psoc_destroy_handler(
256 		WLAN_UMAC_COMP_NAN,
257 		nan_psoc_obj_destroyed_notification,
258 		NULL);
259 	if (QDF_IS_STATUS_ERROR(status)) {
260 		nan_err("wlan_objmgr_register_psoc_destroy_handler failed");
261 		goto err_psoc_destroy_reg;
262 	}
263 
264 	/* register vdev create handler functions. */
265 	status = wlan_objmgr_register_vdev_create_handler(
266 		WLAN_UMAC_COMP_NAN,
267 		nan_vdev_obj_created_notification,
268 		NULL);
269 	if (QDF_IS_STATUS_ERROR(status)) {
270 		nan_err("wlan_objmgr_register_psoc_create_handler failed");
271 		goto err_vdev_create_reg;
272 	}
273 
274 	/* register vdev delete handler functions. */
275 	status = wlan_objmgr_register_vdev_destroy_handler(
276 		WLAN_UMAC_COMP_NAN,
277 		nan_vdev_obj_destroyed_notification,
278 		NULL);
279 	if (QDF_IS_STATUS_ERROR(status)) {
280 		nan_err("wlan_objmgr_register_psoc_destroy_handler failed");
281 		goto err_vdev_destroy_reg;
282 	}
283 
284 	/* register peer create handler functions. */
285 	status = wlan_objmgr_register_peer_create_handler(
286 		WLAN_UMAC_COMP_NAN,
287 		nan_peer_obj_created_notification,
288 		NULL);
289 	if (QDF_IS_STATUS_ERROR(status)) {
290 		nan_err("wlan_objmgr_register_peer_create_handler failed");
291 		goto err_peer_create_reg;
292 	}
293 
294 	/* register peer delete handler functions. */
295 	status = wlan_objmgr_register_peer_destroy_handler(
296 		WLAN_UMAC_COMP_NAN,
297 		nan_peer_obj_destroyed_notification,
298 		NULL);
299 	if (QDF_IS_STATUS_ERROR(status))
300 		nan_err("wlan_objmgr_register_peer_destroy_handler failed");
301 	else
302 		return QDF_STATUS_SUCCESS;
303 
304 	wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_NAN,
305 					nan_peer_obj_created_notification,
306 					NULL);
307 err_peer_create_reg:
308 	wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_NAN,
309 					nan_vdev_obj_destroyed_notification,
310 					NULL);
311 err_vdev_destroy_reg:
312 	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_NAN,
313 					nan_vdev_obj_created_notification,
314 					NULL);
315 err_vdev_create_reg:
316 	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_NAN,
317 					nan_psoc_obj_destroyed_notification,
318 					NULL);
319 err_psoc_destroy_reg:
320 	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_NAN,
321 					nan_psoc_obj_created_notification,
322 					NULL);
323 
324 	return status;
325 }
326 
nan_deinit(void)327 QDF_STATUS nan_deinit(void)
328 {
329 	QDF_STATUS ret = QDF_STATUS_SUCCESS, status;
330 
331 	/* register psoc create handler functions. */
332 	status = wlan_objmgr_unregister_psoc_create_handler(
333 		WLAN_UMAC_COMP_NAN,
334 		nan_psoc_obj_created_notification,
335 		NULL);
336 	if (QDF_IS_STATUS_ERROR(status)) {
337 		nan_err("wlan_objmgr_unregister_psoc_create_handler failed");
338 		ret = status;
339 	}
340 
341 	/* register vdev create handler functions. */
342 	status = wlan_objmgr_unregister_psoc_destroy_handler(
343 		WLAN_UMAC_COMP_NAN,
344 		nan_psoc_obj_destroyed_notification,
345 		NULL);
346 	if (QDF_IS_STATUS_ERROR(status)) {
347 		nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed");
348 		ret = status;
349 	}
350 
351 	/* de-register vdev create handler functions. */
352 	status = wlan_objmgr_unregister_vdev_create_handler(
353 		WLAN_UMAC_COMP_NAN,
354 		nan_vdev_obj_created_notification,
355 		NULL);
356 	if (QDF_IS_STATUS_ERROR(status)) {
357 		nan_err("wlan_objmgr_unregister_psoc_create_handler failed");
358 		ret = status;
359 	}
360 
361 	/* de-register vdev delete handler functions. */
362 	status = wlan_objmgr_unregister_vdev_destroy_handler(
363 		WLAN_UMAC_COMP_NAN,
364 		nan_vdev_obj_destroyed_notification,
365 		NULL);
366 	if (QDF_IS_STATUS_ERROR(status)) {
367 		nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed");
368 		ret = status;
369 	}
370 
371 	/* de-register peer create handler functions. */
372 	status = wlan_objmgr_unregister_peer_create_handler(
373 		WLAN_UMAC_COMP_NAN,
374 		nan_peer_obj_created_notification,
375 		NULL);
376 	if (QDF_IS_STATUS_ERROR(status)) {
377 		nan_err("wlan_objmgr_unregister_peer_create_handler failed");
378 		ret = status;
379 	}
380 
381 	/* de-register peer delete handler functions. */
382 	status = wlan_objmgr_unregister_peer_destroy_handler(
383 		WLAN_UMAC_COMP_NAN,
384 		nan_peer_obj_destroyed_notification,
385 		NULL);
386 	if (QDF_IS_STATUS_ERROR(status)) {
387 		nan_err("wlan_objmgr_deregister_peer_destroy_handler failed");
388 		ret = status;
389 	}
390 
391 	return ret;
392 }
393 
nan_psoc_enable(struct wlan_objmgr_psoc * psoc)394 QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc)
395 {
396 	QDF_STATUS status = target_if_nan_register_events(psoc);
397 
398 	if (QDF_IS_STATUS_ERROR(status))
399 		nan_err("target_if_nan_register_events failed");
400 
401 	return QDF_STATUS_SUCCESS;
402 }
403 
nan_psoc_disable(struct wlan_objmgr_psoc * psoc)404 QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc)
405 {
406 	QDF_STATUS status = target_if_nan_deregister_events(psoc);
407 
408 	if (QDF_IS_STATUS_ERROR(status))
409 		nan_err("target_if_nan_deregister_events failed");
410 
411 	return QDF_STATUS_SUCCESS;
412 }
413 
414 static bool
wlan_is_nan_allowed_on_6ghz_freq(struct wlan_objmgr_pdev * pdev,uint32_t freq)415 wlan_is_nan_allowed_on_6ghz_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq)
416 {
417 	QDF_STATUS status;
418 	struct regulatory_channel *chan_list;
419 	uint32_t len_6g =
420 			NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel);
421 	uint16_t i;
422 	bool ret = false;
423 
424 	chan_list = qdf_mem_malloc(len_6g);
425 	if (!chan_list)
426 		return ret;
427 
428 	status = wlan_reg_get_6g_ap_master_chan_list(pdev,
429 						     REG_VERY_LOW_POWER_AP,
430 						     chan_list);
431 
432 	for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
433 		if ((freq == chan_list[i].center_freq) &&
434 		    (chan_list[i].state == CHANNEL_STATE_ENABLE)) {
435 			ret = true;
436 			goto end;
437 		}
438 	}
439 
440 end:
441 	qdf_mem_free(chan_list);
442 	return ret;
443 }
444 
wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev * pdev,uint32_t freq)445 bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq)
446 {
447 	bool nan_allowed = true;
448 
449 	/* Check for 6GHz channels */
450 	if (wlan_reg_is_6ghz_chan_freq(freq)) {
451 		nan_allowed = wlan_is_nan_allowed_on_6ghz_freq(pdev, freq);
452 		return nan_allowed;
453 	}
454 
455 	/* Check for SRD channels */
456 	if (wlan_reg_is_etsi_srd_chan_for_freq(pdev, freq))
457 		wlan_mlme_get_srd_master_mode_for_vdev(wlan_pdev_get_psoc(pdev),
458 						       QDF_NAN_DISC_MODE,
459 						       &nan_allowed);
460 
461 	/* Check for Indoor channels */
462 	if (wlan_reg_is_freq_indoor(pdev, freq))
463 		wlan_mlme_get_indoor_support_for_nan(wlan_pdev_get_psoc(pdev),
464 						     &nan_allowed);
465 	/*
466 	 * Check for dfs only if channel is not indoor,
467 	 * Check for passive channels as well
468 	 */
469 	else if (wlan_reg_is_dfs_for_freq(pdev, freq) ||
470 		 wlan_reg_is_passive_for_freq(pdev, freq))
471 		nan_allowed = false;
472 
473 	return nan_allowed;
474 }
475 
476 #ifdef WLAN_FEATURE_11BE_MLO
wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc * psoc)477 bool wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc)
478 {
479 	struct nan_psoc_priv_obj *psoc_nan_obj;
480 
481 	psoc_nan_obj = nan_get_psoc_priv_obj(psoc);
482 	if (!psoc_nan_obj) {
483 		nan_err("psoc_nan_obj is null");
484 		return false;
485 	}
486 
487 	return psoc_nan_obj->nan_caps.mlo_sta_nan_ndi_allowed;
488 }
489 #endif
490 
491 #if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS)
nan_cstats_log_nan_enable_resp_evt(struct nan_event_params * nan_event)492 void nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event)
493 {
494 	struct cstats_nan_disc_enable_resp stat = {0};
495 	struct wlan_objmgr_vdev *vdev;
496 
497 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(nan_event->psoc,
498 						    nan_event->vdev_id,
499 						    WLAN_NAN_ID);
500 	if (!vdev) {
501 		nan_err("Invalid vdev!");
502 		return;
503 	}
504 
505 	stat.cmn.hdr.evt_id =
506 		WLAN_CHIPSET_STATS_NAN_DISCOVERY_ENABLE_RESP_EVENT_ID;
507 	stat.cmn.hdr.length = sizeof(struct cstats_nan_disc_enable_resp) -
508 			      sizeof(struct cstats_hdr);
509 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
510 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
511 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
512 	stat.cmn.time_tick = qdf_get_log_timestamp();
513 
514 	stat.is_enable_success = nan_event->is_nan_enable_success;
515 	stat.mac_id = nan_event->mac_id;
516 	stat.disc_state = nan_get_discovery_state(nan_event->psoc);
517 
518 	wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
519 
520 	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_enable_resp),
521 			       &stat);
522 }
523 
nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id,struct wlan_objmgr_psoc * psoc)524 void nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id,
525 					 struct wlan_objmgr_psoc *psoc)
526 {
527 	struct cstats_nan_disc_disable_resp stat = {0};
528 
529 	stat.cmn.hdr.evt_id =
530 	   WLAN_CHIPSET_STATS_NAN_DISCOVERY_DISABLE_RESP_EVENT_ID;
531 	stat.cmn.hdr.length =
532 		sizeof(struct cstats_nan_disc_disable_resp) -
533 		sizeof(struct cstats_hdr);
534 	stat.cmn.opmode = QDF_NAN_DISC_MODE;
535 	stat.cmn.vdev_id = vdev_id;
536 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
537 	stat.cmn.time_tick = qdf_get_log_timestamp();
538 	stat.disc_state = nan_get_discovery_state(psoc);
539 
540 	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_disable_resp),
541 			       &stat);
542 }
543 #endif /* WLAN_CHIPSET_STATS */
544