xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/mgmt_txrx/dispatcher/src/wlan_mgmt_txrx_utils_api.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
1 /*
2  * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  *  DOC:    wlan_mgmt_txrx_utils_api.c
21  *  This file contains mgmt txrx public API definitions for umac
22  *  converged components.
23  */
24 
25 #include "wlan_mgmt_txrx_utils_api.h"
26 #include "../../core/src/wlan_mgmt_txrx_main_i.h"
27 #include "wlan_objmgr_psoc_obj.h"
28 #include "wlan_objmgr_global_obj.h"
29 #include "wlan_objmgr_pdev_obj.h"
30 #include "wlan_objmgr_vdev_obj.h"
31 #include "wlan_objmgr_peer_obj.h"
32 #include "qdf_nbuf.h"
33 #include "wlan_lmac_if_api.h"
34 
35 /**
36  * wlan_mgmt_txrx_psoc_obj_create_notification() - called from objmgr when psoc
37  *                                                 is created
38  * @psoc: psoc context
39  * @arg: argument
40  *
41  * This function gets called from object manager when psoc is being created and
42  * creates mgmt_txrx context, mgmt desc pool.
43  *
44  * Return: QDF_STATUS_SUCCESS - in case of success
45  */
46 static QDF_STATUS wlan_mgmt_txrx_psoc_obj_create_notification(
47 			struct wlan_objmgr_psoc *psoc,
48 			void *arg)
49 {
50 	struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
51 	QDF_STATUS status;
52 
53 	if (!psoc) {
54 		mgmt_txrx_err("psoc context passed is NULL");
55 		status = QDF_STATUS_E_INVAL;
56 		goto err_return;
57 	}
58 
59 	mgmt_txrx_psoc_ctx = qdf_mem_malloc(sizeof(*mgmt_txrx_psoc_ctx));
60 	if (!mgmt_txrx_psoc_ctx) {
61 		mgmt_txrx_err("Failed to allocate mgmt txrx context");
62 		status = QDF_STATUS_E_NOMEM;
63 		goto err_return;
64 	}
65 
66 	mgmt_txrx_psoc_ctx->psoc = psoc;
67 
68 	qdf_spinlock_create(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
69 
70 	if (wlan_objmgr_psoc_component_obj_attach(psoc,
71 				WLAN_UMAC_COMP_MGMT_TXRX,
72 				mgmt_txrx_psoc_ctx, QDF_STATUS_SUCCESS)
73 			!= QDF_STATUS_SUCCESS) {
74 		mgmt_txrx_err("Failed to attach mgmt txrx ctx in psoc ctx");
75 		status = QDF_STATUS_E_FAILURE;
76 		goto err_psoc_attach;
77 	}
78 
79 	mgmt_txrx_info("Mgmt txrx creation successful, mgmt txrx ctx: %pK, psoc: %pK",
80 			mgmt_txrx_psoc_ctx, psoc);
81 
82 	return QDF_STATUS_SUCCESS;
83 
84 err_psoc_attach:
85 	qdf_spinlock_destroy(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
86 	qdf_mem_free(mgmt_txrx_psoc_ctx);
87 err_return:
88 	return status;
89 }
90 
91 /**
92  * wlan_mgmt_txrx_psoc_obj_destroy_notification() - called from objmgr when
93  *                                                  psoc is destroyed
94  * @psoc: psoc context
95  * @arg: argument
96  *
97  * This function gets called from object manager when psoc is being destroyed
98  * psoc deletes mgmt_txrx context, mgmt desc pool.
99  *
100  * Return: QDF_STATUS_SUCCESS - in case of success
101  */
102 static QDF_STATUS wlan_mgmt_txrx_psoc_obj_destroy_notification(
103 			struct wlan_objmgr_psoc *psoc,
104 			void *arg)
105 {
106 	struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
107 
108 	if (!psoc) {
109 		mgmt_txrx_err("psoc context passed is NULL");
110 		return QDF_STATUS_E_INVAL;
111 	}
112 
113 	mgmt_txrx_psoc_ctx = wlan_objmgr_psoc_get_comp_private_obj(
114 			psoc, WLAN_UMAC_COMP_MGMT_TXRX);
115 	if (!mgmt_txrx_psoc_ctx) {
116 		mgmt_txrx_err("mgmt txrx context is already NULL");
117 		return QDF_STATUS_E_FAILURE;
118 	}
119 
120 	mgmt_txrx_info("deleting mgmt txrx psoc obj, mgmt txrx ctx: %pK, psoc: %pK",
121 			mgmt_txrx_psoc_ctx, psoc);
122 	if (wlan_objmgr_psoc_component_obj_detach(psoc,
123 				WLAN_UMAC_COMP_MGMT_TXRX, mgmt_txrx_psoc_ctx)
124 			!= QDF_STATUS_SUCCESS) {
125 		mgmt_txrx_err("Failed to detach mgmt txrx ctx in psoc ctx");
126 		return QDF_STATUS_E_FAILURE;
127 	}
128 
129 	qdf_spinlock_destroy(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
130 	qdf_mem_free(mgmt_txrx_psoc_ctx);
131 
132 	mgmt_txrx_info("mgmt txrx deletion successful, psoc: %pK", psoc);
133 
134 	return QDF_STATUS_SUCCESS;
135 }
136 
137 /**
138  * wlan_mgmt_txrx_pdev_obj_create_notification() - called from objmgr when pdev
139  *                                                 is created
140  * @pdev: pdev context
141  * @arg: argument
142  *
143  * This function gets called from object manager when pdev is being created and
144  * creates mgmt_txrx context, mgmt desc pool.
145  *
146  * Return: QDF_STATUS_SUCCESS - in case of success
147  */
148 static QDF_STATUS wlan_mgmt_txrx_pdev_obj_create_notification(
149 			struct wlan_objmgr_pdev *pdev,
150 			void *arg)
151 {
152 	struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
153 	struct mgmt_txrx_stats_t *mgmt_txrx_stats;
154 	QDF_STATUS status;
155 
156 	if (!pdev) {
157 		mgmt_txrx_err("pdev context passed is NULL");
158 		status = QDF_STATUS_E_INVAL;
159 		goto err_return;
160 
161 	}
162 
163 	mgmt_txrx_pdev_ctx = qdf_mem_malloc(sizeof(*mgmt_txrx_pdev_ctx));
164 	if (!mgmt_txrx_pdev_ctx) {
165 		mgmt_txrx_err("Failed to allocate mgmt txrx context");
166 		status = QDF_STATUS_E_NOMEM;
167 		goto err_return;
168 	}
169 
170 	mgmt_txrx_pdev_ctx->pdev = pdev;
171 
172 	status = wlan_mgmt_txrx_desc_pool_init(mgmt_txrx_pdev_ctx,
173 					       MGMT_DESC_POOL_MAX);
174 	if (status != QDF_STATUS_SUCCESS) {
175 		mgmt_txrx_err(
176 			"Failed to initialize mgmt desc. pool with status: %u",
177 			status);
178 		goto err_desc_pool_init;
179 	}
180 
181 	mgmt_txrx_stats = qdf_mem_malloc(sizeof(*mgmt_txrx_stats));
182 	if (!mgmt_txrx_stats) {
183 		mgmt_txrx_err(
184 			"Failed to allocate memory for mgmt txrx stats structure");
185 		status = QDF_STATUS_E_NOMEM;
186 		goto err_mgmt_txrx_stats;
187 	}
188 	mgmt_txrx_pdev_ctx->mgmt_txrx_stats = mgmt_txrx_stats;
189 
190 	qdf_wake_lock_create(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp,
191 			     "mgmt_txrx tx_cmp");
192 
193 	if (wlan_objmgr_pdev_component_obj_attach(pdev,
194 			WLAN_UMAC_COMP_MGMT_TXRX,
195 			mgmt_txrx_pdev_ctx, QDF_STATUS_SUCCESS)
196 			!= QDF_STATUS_SUCCESS) {
197 		mgmt_txrx_err("Failed to attach mgmt txrx ctx in pdev ctx");
198 		status = QDF_STATUS_E_FAILURE;
199 		goto err_pdev_attach;
200 	}
201 
202 	mgmt_txrx_info(
203 		"Mgmt txrx creation successful, mgmt txrx ctx: %pK, pdev: %pK",
204 		mgmt_txrx_pdev_ctx, pdev);
205 
206 	return QDF_STATUS_SUCCESS;
207 
208 err_pdev_attach:
209 	qdf_wake_lock_destroy(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp);
210 	qdf_mem_free(mgmt_txrx_stats);
211 err_mgmt_txrx_stats:
212 	wlan_mgmt_txrx_desc_pool_deinit(mgmt_txrx_pdev_ctx);
213 err_desc_pool_init:
214 	qdf_mem_free(mgmt_txrx_pdev_ctx);
215 err_return:
216 	return status;
217 }
218 
219 /**
220  * wlan_mgmt_txrx_pdev_obj_destroy_notification() - called from objmgr when
221  *                                                  pdev is destroyed
222  * @pdev: pdev context
223  * @arg: argument
224  *
225  * This function gets called from object manager when pdev is being destroyed
226  * pdev deletes mgmt_txrx context, mgmt desc pool.
227  *
228  * Return: QDF_STATUS_SUCCESS - in case of success
229  */
230 static QDF_STATUS wlan_mgmt_txrx_pdev_obj_destroy_notification(
231 			struct wlan_objmgr_pdev *pdev,
232 			void *arg)
233 {
234 	struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
235 
236 	if (!pdev) {
237 		mgmt_txrx_err("pdev context passed is NULL");
238 		return QDF_STATUS_E_INVAL;
239 	}
240 
241 	mgmt_txrx_pdev_ctx = wlan_objmgr_pdev_get_comp_private_obj(
242 			pdev, WLAN_UMAC_COMP_MGMT_TXRX);
243 	if (!mgmt_txrx_pdev_ctx) {
244 		mgmt_txrx_err("mgmt txrx context is already NULL");
245 		return QDF_STATUS_E_FAILURE;
246 	}
247 
248 	mgmt_txrx_info("deleting mgmt txrx pdev obj, mgmt txrx ctx: %pK, pdev: %pK",
249 			mgmt_txrx_pdev_ctx, pdev);
250 	if (wlan_objmgr_pdev_component_obj_detach(pdev,
251 				WLAN_UMAC_COMP_MGMT_TXRX, mgmt_txrx_pdev_ctx)
252 			!= QDF_STATUS_SUCCESS) {
253 		mgmt_txrx_err("Failed to detach mgmt txrx ctx in pdev ctx");
254 		return QDF_STATUS_E_FAILURE;
255 	}
256 
257 	wlan_mgmt_txrx_desc_pool_deinit(mgmt_txrx_pdev_ctx);
258 	qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_txrx_stats);
259 	qdf_wake_lock_destroy(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp);
260 	qdf_mem_free(mgmt_txrx_pdev_ctx);
261 
262 	mgmt_txrx_info("mgmt txrx deletion successful, pdev: %pK", pdev);
263 
264 	return QDF_STATUS_SUCCESS;
265 }
266 
267 
268 QDF_STATUS wlan_mgmt_txrx_init(void)
269 {
270 	QDF_STATUS status = QDF_STATUS_SUCCESS;
271 
272 	status = wlan_objmgr_register_psoc_create_handler(
273 				WLAN_UMAC_COMP_MGMT_TXRX,
274 				wlan_mgmt_txrx_psoc_obj_create_notification,
275 				NULL);
276 	if (status != QDF_STATUS_SUCCESS) {
277 		mgmt_txrx_err("Failed to register mgmt txrx psoc create handler");
278 		goto err_psoc_create;
279 	}
280 
281 	status = wlan_objmgr_register_psoc_destroy_handler(
282 				WLAN_UMAC_COMP_MGMT_TXRX,
283 				wlan_mgmt_txrx_psoc_obj_destroy_notification,
284 				NULL);
285 	if (status != QDF_STATUS_SUCCESS) {
286 		mgmt_txrx_err("Failed to register mgmt txrx psoc destroy handler");
287 		goto err_psoc_delete;
288 	}
289 
290 	status = wlan_objmgr_register_pdev_create_handler(
291 				WLAN_UMAC_COMP_MGMT_TXRX,
292 				wlan_mgmt_txrx_pdev_obj_create_notification,
293 				NULL);
294 	if (status != QDF_STATUS_SUCCESS) {
295 		mgmt_txrx_err("Failed to register mgmt txrx pdev obj create handler");
296 		goto err_pdev_create;
297 	}
298 
299 	status = wlan_objmgr_register_pdev_destroy_handler(
300 				WLAN_UMAC_COMP_MGMT_TXRX,
301 				wlan_mgmt_txrx_pdev_obj_destroy_notification,
302 				NULL);
303 	if (status != QDF_STATUS_SUCCESS) {
304 		mgmt_txrx_err("Failed to register mgmt txrx obj destroy handler");
305 		goto err_pdev_delete;
306 	}
307 
308 	mgmt_txrx_info("Successfully registered create and destroy handlers with objmgr");
309 	return QDF_STATUS_SUCCESS;
310 
311 err_pdev_delete:
312 	wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
313 			wlan_mgmt_txrx_pdev_obj_create_notification, NULL);
314 err_pdev_create:
315 	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_MGMT_TXRX,
316 			wlan_mgmt_txrx_psoc_obj_destroy_notification, NULL);
317 err_psoc_delete:
318 	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
319 			wlan_mgmt_txrx_psoc_obj_create_notification, NULL);
320 err_psoc_create:
321 	return status;
322 }
323 
324 QDF_STATUS wlan_mgmt_txrx_deinit(void)
325 {
326 	if (wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
327 				wlan_mgmt_txrx_psoc_obj_create_notification,
328 				NULL)
329 			!= QDF_STATUS_SUCCESS) {
330 		return QDF_STATUS_E_FAILURE;
331 	}
332 
333 	if (wlan_objmgr_unregister_psoc_destroy_handler(
334 				WLAN_UMAC_COMP_MGMT_TXRX,
335 				wlan_mgmt_txrx_psoc_obj_destroy_notification,
336 				NULL)
337 			!= QDF_STATUS_SUCCESS) {
338 		return QDF_STATUS_E_FAILURE;
339 	}
340 
341 	if (wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
342 				wlan_mgmt_txrx_pdev_obj_create_notification,
343 				NULL)
344 			!= QDF_STATUS_SUCCESS) {
345 		return QDF_STATUS_E_FAILURE;
346 	}
347 
348 	if (wlan_objmgr_unregister_pdev_destroy_handler(
349 				WLAN_UMAC_COMP_MGMT_TXRX,
350 				wlan_mgmt_txrx_pdev_obj_destroy_notification,
351 				NULL)
352 			!= QDF_STATUS_SUCCESS) {
353 		return QDF_STATUS_E_FAILURE;
354 	}
355 
356 
357 	mgmt_txrx_info("Successfully unregistered create and destroy handlers with objmgr");
358 	return QDF_STATUS_SUCCESS;
359 }
360 
361 QDF_STATUS wlan_mgmt_txrx_mgmt_frame_tx(struct wlan_objmgr_peer *peer,
362 					void *context,
363 					qdf_nbuf_t buf,
364 					mgmt_tx_download_comp_cb tx_comp_cb,
365 					mgmt_ota_comp_cb tx_ota_comp_cb,
366 					enum wlan_umac_comp_id comp_id,
367 					void *mgmt_tx_params)
368 {
369 	struct mgmt_txrx_desc_elem_t *desc;
370 	struct wlan_objmgr_psoc *psoc;
371 	struct wlan_objmgr_pdev *pdev;
372 	struct mgmt_txrx_priv_pdev_context *txrx_ctx;
373 	struct wlan_objmgr_vdev *vdev;
374 
375 	if (!peer) {
376 		mgmt_txrx_err("peer passed is NULL");
377 		return QDF_STATUS_E_NULL_VALUE;
378 	}
379 
380 	wlan_objmgr_peer_get_ref(peer, WLAN_MGMT_NB_ID);
381 
382 	vdev = wlan_peer_get_vdev(peer);
383 	if (!vdev) {
384 		mgmt_txrx_err("vdev unavailable for peer %pK", peer);
385 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
386 		return QDF_STATUS_E_NULL_VALUE;
387 	}
388 
389 	psoc = wlan_vdev_get_psoc(vdev);
390 	if (!psoc) {
391 		mgmt_txrx_err("psoc unavailable for peer %pK vdev %pK",
392 				peer, vdev);
393 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
394 		return QDF_STATUS_E_NULL_VALUE;
395 	}
396 
397 	pdev = wlan_vdev_get_pdev(vdev);
398 	if (!pdev) {
399 		mgmt_txrx_err("pdev unavailable for peer %pK vdev %pK",
400 				peer, vdev);
401 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
402 		return QDF_STATUS_E_NULL_VALUE;
403 	}
404 
405 	txrx_ctx = (struct mgmt_txrx_priv_pdev_context *)
406 			wlan_objmgr_pdev_get_comp_private_obj(pdev,
407 				WLAN_UMAC_COMP_MGMT_TXRX);
408 	if (!txrx_ctx) {
409 		mgmt_txrx_err("No txrx context for peer %pK pdev %pK",
410 				peer, pdev);
411 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
412 		return QDF_STATUS_E_NULL_VALUE;
413 	}
414 
415 	desc = wlan_mgmt_txrx_desc_get(txrx_ctx);
416 	if (!desc) {
417 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
418 		return QDF_STATUS_E_RESOURCES;
419 	}
420 
421 	desc->nbuf = buf;
422 	desc->tx_ota_cmpl_cb = tx_ota_comp_cb;
423 	desc->tx_dwnld_cmpl_cb = tx_comp_cb;
424 	desc->peer = peer;
425 	desc->vdev_id = wlan_vdev_get_id(vdev);
426 	desc->context = context;
427 
428 	if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.mgmt_tx_send) {
429 		mgmt_txrx_err(
430 				"mgmt txrx txop to send mgmt frame is NULL for psoc: %pK",
431 				psoc);
432 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
433 		desc->nbuf = NULL;
434 		wlan_mgmt_txrx_desc_put(txrx_ctx, desc->desc_id);
435 		return QDF_STATUS_E_FAILURE;
436 	}
437 
438 	if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.mgmt_tx_send(
439 			vdev, buf, desc->desc_id, mgmt_tx_params)) {
440 		mgmt_txrx_err("Mgmt send fail for peer %pK psoc %pK pdev: %pK",
441 				peer, psoc, pdev);
442 		wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
443 		desc->nbuf = NULL;
444 		wlan_mgmt_txrx_desc_put(txrx_ctx, desc->desc_id);
445 		return QDF_STATUS_E_FAILURE;
446 	}
447 	return QDF_STATUS_SUCCESS;
448 }
449 
450 QDF_STATUS wlan_mgmt_txrx_beacon_frame_tx(struct wlan_objmgr_peer *peer,
451 					  qdf_nbuf_t buf,
452 					  enum wlan_umac_comp_id comp_id)
453 {
454 	struct wlan_objmgr_vdev *vdev;
455 	struct wlan_objmgr_psoc *psoc;
456 
457 	vdev = wlan_peer_get_vdev(peer);
458 	if (!vdev) {
459 		mgmt_txrx_err("vdev unavailable for peer %pK", peer);
460 		return QDF_STATUS_E_NULL_VALUE;
461 	}
462 
463 	psoc = wlan_vdev_get_psoc(vdev);
464 	if (!psoc) {
465 		mgmt_txrx_err("psoc unavailable for peer %pK", peer);
466 		return QDF_STATUS_E_NULL_VALUE;
467 	}
468 
469 	if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.beacon_send) {
470 		mgmt_txrx_err("mgmt txrx tx op to send beacon frame is NULL for psoc: %pK",
471 				psoc);
472 		return QDF_STATUS_E_FAILURE;
473 	}
474 
475 	if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.beacon_send(vdev, buf)) {
476 		mgmt_txrx_err("Beacon send fail for peer %pK psoc %pK",
477 				peer, psoc);
478 		return QDF_STATUS_E_FAILURE;
479 	}
480 	return QDF_STATUS_SUCCESS;
481 }
482 
483 #ifdef WLAN_SUPPORT_FILS
484 QDF_STATUS
485 wlan_mgmt_txrx_fd_action_frame_tx(struct wlan_objmgr_vdev *vdev,
486 				  qdf_nbuf_t buf,
487 				  enum wlan_umac_comp_id comp_id)
488 {
489 	struct wlan_objmgr_psoc *psoc;
490 	uint32_t vdev_id;
491 
492 	if (!vdev) {
493 		mgmt_txrx_err("Invalid vdev");
494 		return QDF_STATUS_E_NULL_VALUE;
495 	}
496 	vdev_id = wlan_vdev_get_id(vdev);
497 	psoc = wlan_vdev_get_psoc(vdev);
498 	if (!psoc) {
499 		mgmt_txrx_err("psoc unavailable for vdev %d", vdev_id);
500 		return QDF_STATUS_E_NULL_VALUE;
501 	}
502 
503 	if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.fd_action_frame_send) {
504 		mgmt_txrx_err("mgmt txrx txop to send fd action frame is NULL");
505 		return QDF_STATUS_E_FAILURE;
506 	}
507 
508 	if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.fd_action_frame_send(
509 			vdev, buf)) {
510 		mgmt_txrx_err("FD send fail for vdev %d", vdev_id);
511 		return QDF_STATUS_E_FAILURE;
512 	}
513 
514 	return QDF_STATUS_SUCCESS;
515 }
516 #endif /* WLAN_SUPPORT_FILS */
517 
518 /**
519  * wlan_mgmt_txrx_create_rx_handler() - creates rx handler node for umac comp.
520  * @mgmt_txrx_psoc_ctx: mgmt txrx context
521  * @mgmt_rx_cb: mgmt rx callback to be registered
522  * @comp_id: umac component id
523  * @frm_type: mgmt. frame for which cb to be registered.
524  *
525  * This function creates rx handler node for frame type and
526  * umac component passed in the func.
527  *
528  * Return: QDF_STATUS_SUCCESS - in case of success
529  */
530 static QDF_STATUS wlan_mgmt_txrx_create_rx_handler(
531 				struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx,
532 				mgmt_frame_rx_callback mgmt_rx_cb,
533 				enum wlan_umac_comp_id comp_id,
534 				enum mgmt_frame_type frm_type)
535 {
536 	struct mgmt_rx_handler *rx_handler;
537 
538 	rx_handler = qdf_mem_malloc(sizeof(*rx_handler));
539 	if (!rx_handler) {
540 		mgmt_txrx_err("Couldn't allocate memory for rx handler");
541 		return QDF_STATUS_E_NOMEM;
542 	}
543 
544 	rx_handler->comp_id = comp_id;
545 	rx_handler->rx_cb = mgmt_rx_cb;
546 
547 	qdf_spin_lock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
548 	rx_handler->next = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type];
549 	mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type] = rx_handler;
550 	qdf_spin_unlock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
551 
552 	mgmt_txrx_info("Callback registered for comp_id: %d, frm_type: %d",
553 			comp_id, frm_type);
554 	return QDF_STATUS_SUCCESS;
555 }
556 
557 /**
558  * wlan_mgmt_txrx_delete_rx_handler() - deletes rx handler node for umac comp.
559  * @mgmt_txrx_psoc_ctx: mgmt txrx context
560  * @mgmt_rx_cb: mgmt rx callback to be deregistered
561  * @comp_id: umac component id
562  * @frm_type: mgmt. frame for which cb to be registered.
563  *
564  * This function deletes rx handler node for frame type and
565  * umac component passed in the func.
566  *
567  * Return: QDF_STATUS_SUCCESS - in case of success
568  */
569 static QDF_STATUS wlan_mgmt_txrx_delete_rx_handler(
570 		struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx,
571 		mgmt_frame_rx_callback mgmt_rx_cb,
572 		enum wlan_umac_comp_id comp_id,
573 		enum mgmt_frame_type frm_type)
574 {
575 	struct mgmt_rx_handler *rx_handler = NULL, *rx_handler_prev = NULL;
576 	bool delete = false;
577 
578 	qdf_spin_lock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
579 	rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type];
580 	while (rx_handler) {
581 		if (rx_handler->comp_id == comp_id &&
582 				rx_handler->rx_cb == mgmt_rx_cb) {
583 			if (rx_handler_prev)
584 				rx_handler_prev->next =
585 					rx_handler->next;
586 			else
587 				mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type] =
588 					rx_handler->next;
589 
590 			qdf_mem_free(rx_handler);
591 			delete = true;
592 			break;
593 		}
594 
595 		rx_handler_prev = rx_handler;
596 		rx_handler = rx_handler->next;
597 	}
598 	qdf_spin_unlock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
599 
600 	if (!delete) {
601 		mgmt_txrx_err("No callback registered for comp_id: %d, frm_type: %d",
602 				comp_id, frm_type);
603 		return QDF_STATUS_E_FAILURE;
604 	}
605 
606 	mgmt_txrx_info("Callback deregistered for comp_id: %d, frm_type: %d",
607 			comp_id, frm_type);
608 	return QDF_STATUS_SUCCESS;
609 }
610 
611 QDF_STATUS wlan_mgmt_txrx_register_rx_cb(
612 			struct wlan_objmgr_psoc *psoc,
613 			enum wlan_umac_comp_id comp_id,
614 			struct mgmt_txrx_mgmt_frame_cb_info *frm_cb_info,
615 			uint8_t num_entries)
616 {
617 	struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
618 	QDF_STATUS status;
619 	uint8_t i, j;
620 
621 	if (!psoc) {
622 		mgmt_txrx_err("psoc context is NULL");
623 		return QDF_STATUS_E_INVAL;
624 	}
625 
626 	if (comp_id >= WLAN_UMAC_MAX_COMPONENTS) {
627 		mgmt_txrx_err("Invalid component id %d passed", comp_id);
628 		return QDF_STATUS_E_INVAL;
629 	}
630 
631 	if (!num_entries || num_entries >= MGMT_MAX_FRAME_TYPE) {
632 		mgmt_txrx_err("Invalid value for num_entries: %d passed",
633 				num_entries);
634 		return QDF_STATUS_E_INVAL;
635 	}
636 
637 	if (!frm_cb_info) {
638 		mgmt_txrx_err("frame cb info pointer is NULL");
639 		return QDF_STATUS_E_INVAL;
640 	}
641 
642 	mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)
643 			wlan_objmgr_psoc_get_comp_private_obj(psoc,
644 				WLAN_UMAC_COMP_MGMT_TXRX);
645 	if (!mgmt_txrx_psoc_ctx) {
646 		mgmt_txrx_err("mgmt txrx context is NULL");
647 		return QDF_STATUS_E_FAILURE;
648 	}
649 
650 	for (i = 0; i < num_entries; i++) {
651 		status = wlan_mgmt_txrx_create_rx_handler(mgmt_txrx_psoc_ctx,
652 				frm_cb_info[i].mgmt_rx_cb, comp_id,
653 				frm_cb_info[i].frm_type);
654 		if (status != QDF_STATUS_SUCCESS) {
655 			for (j = 0; j < i; j++) {
656 				wlan_mgmt_txrx_delete_rx_handler(
657 					mgmt_txrx_psoc_ctx,
658 					frm_cb_info[j].mgmt_rx_cb,
659 					comp_id, frm_cb_info[j].frm_type);
660 			}
661 			return status;
662 		}
663 	}
664 
665 	return QDF_STATUS_SUCCESS;
666 }
667 
668 QDF_STATUS wlan_mgmt_txrx_deregister_rx_cb(
669 			struct wlan_objmgr_psoc *psoc,
670 			enum wlan_umac_comp_id comp_id,
671 			struct mgmt_txrx_mgmt_frame_cb_info *frm_cb_info,
672 			uint8_t num_entries)
673 {
674 	struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
675 	uint8_t i;
676 
677 	if (!psoc) {
678 		mgmt_txrx_err("psoc context is NULL");
679 		return QDF_STATUS_E_INVAL;
680 	}
681 
682 	if (comp_id >= WLAN_UMAC_MAX_COMPONENTS) {
683 		mgmt_txrx_err("Invalid component id %d passed", comp_id);
684 		return QDF_STATUS_E_INVAL;
685 	}
686 
687 	if (!num_entries || num_entries >= MGMT_MAX_FRAME_TYPE) {
688 		mgmt_txrx_err("Invalid value for num_entries: %d passed",
689 				num_entries);
690 		return QDF_STATUS_E_INVAL;
691 	}
692 
693 	if (!frm_cb_info) {
694 		mgmt_txrx_err("frame cb info pointer is NULL");
695 		return QDF_STATUS_E_INVAL;
696 	}
697 
698 	mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)
699 			wlan_objmgr_psoc_get_comp_private_obj(psoc,
700 				WLAN_UMAC_COMP_MGMT_TXRX);
701 	if (!mgmt_txrx_psoc_ctx) {
702 		mgmt_txrx_err("mgmt txrx context is NULL");
703 		return QDF_STATUS_E_FAILURE;
704 	}
705 
706 	for (i = 0; i < num_entries; i++) {
707 		wlan_mgmt_txrx_delete_rx_handler(mgmt_txrx_psoc_ctx,
708 				frm_cb_info[i].mgmt_rx_cb, comp_id,
709 				frm_cb_info[i].frm_type);
710 	}
711 
712 	return QDF_STATUS_SUCCESS;
713 }
714 
715 QDF_STATUS wlan_mgmt_txrx_psoc_open(struct wlan_objmgr_psoc *psoc)
716 {
717 	return QDF_STATUS_SUCCESS;
718 }
719 
720 QDF_STATUS wlan_mgmt_txrx_psoc_close(struct wlan_objmgr_psoc *psoc)
721 {
722 	return QDF_STATUS_SUCCESS;
723 }
724 
725 QDF_STATUS wlan_mgmt_txrx_pdev_open(struct wlan_objmgr_pdev *pdev)
726 {
727 	return QDF_STATUS_SUCCESS;
728 }
729 
730 QDF_STATUS wlan_mgmt_txrx_pdev_close(struct wlan_objmgr_pdev *pdev)
731 {
732 	struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
733 	struct mgmt_txrx_desc_elem_t *mgmt_desc;
734 	uint32_t pool_size;
735 	uint32_t index;
736 
737 	if (!pdev) {
738 		mgmt_txrx_err("pdev context is NULL");
739 		return QDF_STATUS_E_INVAL;
740 	}
741 
742 	mgmt_txrx_pdev_ctx = (struct mgmt_txrx_priv_pdev_context *)
743 		wlan_objmgr_pdev_get_comp_private_obj(pdev,
744 		WLAN_UMAC_COMP_MGMT_TXRX);
745 
746 	if (!mgmt_txrx_pdev_ctx) {
747 		mgmt_txrx_err("mgmt txrx context is NULL");
748 		return QDF_STATUS_E_FAILURE;
749 	}
750 
751 	pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size;
752 	if (!pool_size) {
753 		mgmt_txrx_err("pool size is 0");
754 		return QDF_STATUS_E_FAILURE;
755 	}
756 
757 	for (index = 0; index < pool_size; index++) {
758 		if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[index].in_use) {
759 			mgmt_txrx_info(
760 				"mgmt descriptor with desc id: %d not in freelist",
761 				index);
762 			mgmt_desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[index];
763 			qdf_nbuf_free(mgmt_desc->nbuf);
764 			wlan_objmgr_peer_release_ref(mgmt_desc->peer,
765 				WLAN_MGMT_NB_ID);
766 			wlan_mgmt_txrx_desc_put(mgmt_txrx_pdev_ctx, index);
767 		}
768 	}
769 
770 	return QDF_STATUS_SUCCESS;
771 }
772 
773 QDF_STATUS wlan_mgmt_txrx_peer_drain(struct wlan_objmgr_peer *peer,
774 				     mgmt_frame_nbuf_op mgmt_nbuf_op)
775 {
776 	struct wlan_objmgr_pdev *pdev;
777 	struct wlan_objmgr_vdev *vdev;
778 	struct mgmt_txrx_priv_pdev_context *mgmt_txrx_ctx;
779 	struct mgmt_txrx_desc_elem_t *mgmt_desc;
780 	struct wlan_objmgr_peer *des_peer;
781 	uint32_t pool_size;
782 	int i;
783 
784 	vdev = wlan_peer_get_vdev(peer);
785 	if (!vdev) {
786 		mgmt_txrx_err("vdev context is NULL");
787 		return QDF_STATUS_E_INVAL;
788 	}
789 
790 	pdev = wlan_vdev_get_pdev(vdev);
791 	if (!pdev) {
792 		mgmt_txrx_err("pdev context is NULL");
793 		return QDF_STATUS_E_INVAL;
794 	}
795 
796 	mgmt_txrx_ctx = wlan_objmgr_pdev_get_comp_private_obj(pdev,
797 						WLAN_UMAC_COMP_MGMT_TXRX);
798 	if (!mgmt_txrx_ctx) {
799 		mgmt_txrx_err("mgmt txrx context is NULL");
800 		return QDF_STATUS_E_FAILURE;
801 	}
802 
803 	pool_size = mgmt_txrx_ctx->mgmt_desc_pool.free_list.max_size;
804 	if (!pool_size) {
805 		mgmt_txrx_err("pool size is 0");
806 		return QDF_STATUS_E_FAILURE;
807 	}
808 
809 	for (i = 0; i < pool_size; i++) {
810 		if (mgmt_txrx_ctx->mgmt_desc_pool.pool[i].in_use) {
811 			mgmt_desc = &mgmt_txrx_ctx->mgmt_desc_pool.pool[i];
812 			des_peer = mgmt_txrx_get_peer(pdev, mgmt_desc->desc_id);
813 			if (peer == des_peer) {
814 				if (mgmt_nbuf_op)
815 					mgmt_nbuf_op(peer, mgmt_desc->nbuf);
816 				mgmt_txrx_tx_completion_handler(pdev,
817 						mgmt_desc->desc_id, 0, 0);
818 			}
819 		}
820 	}
821 
822 	return QDF_STATUS_SUCCESS;
823 }
824 
825 QDF_STATUS wlan_mgmt_txrx_vdev_drain(struct wlan_objmgr_vdev *vdev,
826 				mgmt_frame_fill_peer_cb mgmt_fill_peer_cb,
827 				void *status)
828 {
829 	struct wlan_objmgr_pdev *pdev;
830 	struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
831 	struct mgmt_txrx_desc_elem_t *mgmt_desc;
832 	struct wlan_objmgr_peer *peer;
833 	struct wlan_objmgr_vdev *peer_vdev;
834 	uint32_t pool_size;
835 	int i;
836 
837 	if (!vdev) {
838 		mgmt_txrx_err("vdev context is NULL");
839 		return QDF_STATUS_E_INVAL;
840 	}
841 
842 	pdev = wlan_vdev_get_pdev(vdev);
843 	if (!pdev) {
844 		mgmt_txrx_err("pdev context is NULL");
845 		return QDF_STATUS_E_INVAL;
846 	}
847 	mgmt_txrx_pdev_ctx = (struct mgmt_txrx_priv_pdev_context *)
848 		wlan_objmgr_pdev_get_comp_private_obj(pdev,
849 			WLAN_UMAC_COMP_MGMT_TXRX);
850 	if (!mgmt_txrx_pdev_ctx) {
851 		mgmt_txrx_err("mgmt txrx context is NULL");
852 		return QDF_STATUS_E_FAILURE;
853 	}
854 
855 	pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size;
856 	if (!pool_size) {
857 		mgmt_txrx_err("pool size is 0");
858 		return QDF_STATUS_E_FAILURE;
859 	}
860 
861 	for (i = 0; i < pool_size; i++) {
862 		if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use) {
863 			mgmt_desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i];
864 			peer = mgmt_txrx_get_peer(pdev, mgmt_desc->desc_id);
865 			if (peer) {
866 				peer_vdev = wlan_peer_get_vdev(peer);
867 				if (peer_vdev == vdev) {
868 					if (mgmt_fill_peer_cb)
869 						mgmt_fill_peer_cb(peer, mgmt_desc->nbuf);
870 					mgmt_txrx_tx_completion_handler(pdev,
871 						mgmt_desc->desc_id, 0, status);
872 				}
873 			}
874 		}
875 	}
876 
877 	return QDF_STATUS_SUCCESS;
878 }
879