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