xref: /wlan-driver/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023-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: Implements mc addr filtering offload feature API's
22  */
23 
24 #include "wlan_pmo_mc_addr_filtering.h"
25 #include "wlan_pmo_tgt_api.h"
26 #include "wlan_pmo_main.h"
27 #include "wlan_pmo_obj_mgmt_public_struct.h"
28 
29 #define PMO_INVALID_MC_ADDR_COUNT (-1)
30 
pmo_core_fill_mc_list(struct pmo_vdev_priv_obj ** vdev_ctx,struct pmo_mc_addr_list_params * ip)31 static void pmo_core_fill_mc_list(struct pmo_vdev_priv_obj **vdev_ctx,
32 	struct pmo_mc_addr_list_params *ip)
33 {
34 	struct pmo_mc_addr_list *op_list;
35 	int i, j = 0;
36 	static const uint8_t ipv6_rs[] = {
37 		0x33, 0x33, 0x00, 0x00, 0x00, 0x02};
38 	struct pmo_vdev_priv_obj *temp_ctx;
39 	uint8_t addr_fp;
40 
41 	temp_ctx = *vdev_ctx;
42 	addr_fp = temp_ctx->addr_filter_pattern;
43 	op_list = &temp_ctx->vdev_mc_list_req;
44 
45 	qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock);
46 	op_list->mc_cnt = ip->count;
47 	qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock);
48 
49 	for (i = 0; i < ip->count; i++) {
50 		/*
51 		 * Skip following addresses:
52 		 * 1)IPv6 router solicitation address
53 		 * 2)Any other address pattern if its set during
54 		 *  RXFILTER REMOVE driver command based on
55 		 *  addr_filter_pattern
56 		 */
57 		if ((!qdf_mem_cmp(ip->mc_addr[i].bytes, ipv6_rs,
58 			QDF_MAC_ADDR_SIZE)) ||
59 		   (addr_fp &&
60 		   (!qdf_mem_cmp(ip->mc_addr[i].bytes, &addr_fp, 1)))) {
61 			pmo_debug("MC/BC filtering Skip addr "QDF_MAC_ADDR_FMT,
62 				QDF_MAC_ADDR_REF(ip->mc_addr[i].bytes));
63 			qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock);
64 			op_list->mc_cnt--;
65 			qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock);
66 			continue;
67 		}
68 		qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock);
69 		qdf_mem_zero(&op_list->mc_addr[j].bytes,
70 			     QDF_MAC_ADDR_SIZE);
71 		qdf_mem_copy(&op_list->mc_addr[j].bytes,
72 			     ip->mc_addr[i].bytes, QDF_MAC_ADDR_SIZE);
73 		qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock);
74 		pmo_debug("Index = %d, mac["QDF_MAC_ADDR_FMT"]", j,
75 			  QDF_MAC_ADDR_REF(op_list->mc_addr[j].bytes));
76 		j++;
77 	}
78 }
79 
pmo_core_cache_mc_addr_list_in_vdev_priv(struct pmo_mc_addr_list_params * mc_list_config,struct wlan_objmgr_vdev * vdev)80 static QDF_STATUS pmo_core_cache_mc_addr_list_in_vdev_priv(
81 		struct pmo_mc_addr_list_params *mc_list_config,
82 		struct wlan_objmgr_vdev *vdev)
83 {
84 	struct pmo_vdev_priv_obj *vdev_ctx;
85 
86 	vdev_ctx = pmo_vdev_get_priv(vdev);
87 	pmo_core_fill_mc_list(&vdev_ctx, mc_list_config);
88 
89 	return QDF_STATUS_SUCCESS;
90 }
91 
pmo_core_flush_mc_addr_list_from_vdev_priv(struct wlan_objmgr_vdev * vdev)92 static QDF_STATUS pmo_core_flush_mc_addr_list_from_vdev_priv(
93 			struct wlan_objmgr_vdev *vdev)
94 {
95 	struct pmo_vdev_priv_obj *vdev_ctx;
96 
97 	vdev_ctx = pmo_vdev_get_priv(vdev);
98 
99 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
100 	qdf_mem_zero(&vdev_ctx->vdev_mc_list_req,
101 		sizeof(vdev_ctx->vdev_mc_list_req));
102 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
103 
104 	return QDF_STATUS_SUCCESS;
105 }
106 
pmo_core_enhanced_mc_filter_enable(struct wlan_objmgr_vdev * vdev)107 QDF_STATUS pmo_core_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev)
108 {
109 	QDF_STATUS status;
110 
111 	status = pmo_vdev_get_ref(vdev);
112 	if (QDF_IS_STATUS_ERROR(status))
113 		goto exit_with_status;
114 
115 	pmo_tgt_send_enhance_multicast_offload_req(vdev, true);
116 
117 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
118 
119 exit_with_status:
120 
121 	return status;
122 }
123 
pmo_core_enhanced_mc_filter_disable(struct wlan_objmgr_vdev * vdev)124 QDF_STATUS pmo_core_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev)
125 {
126 	QDF_STATUS status;
127 
128 	pmo_enter();
129 
130 	status = pmo_vdev_get_ref(vdev);
131 	if (QDF_IS_STATUS_ERROR(status))
132 		goto exit_with_status;
133 
134 	pmo_tgt_send_enhance_multicast_offload_req(vdev, false);
135 
136 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
137 
138 exit_with_status:
139 	pmo_exit();
140 
141 	return status;
142 }
143 
pmo_core_set_mc_filter_req(struct wlan_objmgr_vdev * vdev,struct pmo_mc_addr_list * mc_list)144 QDF_STATUS pmo_core_set_mc_filter_req(struct wlan_objmgr_vdev *vdev,
145 	struct pmo_mc_addr_list *mc_list)
146 {
147 	int i;
148 
149 	if (pmo_tgt_get_multiple_mc_filter_support(vdev)) {
150 		pmo_debug("FW supports multiple mcast filter");
151 		pmo_tgt_set_multiple_mc_filter_req(vdev, mc_list);
152 	} else {
153 		pmo_debug("FW does not support multiple mcast filter");
154 		for (i = 0; i < mc_list->mc_cnt; i++)
155 			pmo_tgt_set_mc_filter_req(vdev, mc_list->mc_addr[i]);
156 	}
157 
158 	return QDF_STATUS_SUCCESS;
159 }
160 
pmo_core_clear_mc_filter_req(struct wlan_objmgr_vdev * vdev,struct pmo_mc_addr_list * mc_list)161 QDF_STATUS pmo_core_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev,
162 	struct pmo_mc_addr_list *mc_list)
163 {
164 	int i;
165 
166 	if (pmo_tgt_get_multiple_mc_filter_support(vdev)) {
167 		pmo_debug("FW supports multiple mcast filter");
168 		pmo_tgt_clear_multiple_mc_filter_req(vdev, mc_list);
169 	} else {
170 		pmo_debug("FW does not support multiple mcast filter");
171 		for (i = 0; i < mc_list->mc_cnt; i++)
172 			pmo_tgt_clear_mc_filter_req(vdev, mc_list->mc_addr[i]);
173 	}
174 
175 	return QDF_STATUS_SUCCESS;
176 }
177 
pmo_core_do_enable_mc_addr_list(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,struct pmo_mc_addr_list * op_mc_list_req)178 static QDF_STATUS pmo_core_do_enable_mc_addr_list(struct wlan_objmgr_vdev *vdev,
179 	struct pmo_vdev_priv_obj *vdev_ctx,
180 	struct pmo_mc_addr_list *op_mc_list_req)
181 {
182 	QDF_STATUS status;
183 
184 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
185 	if (!vdev_ctx->vdev_mc_list_req.mc_cnt) {
186 		qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
187 		pmo_err("mc_cnt is zero so skip to add mc list");
188 		status = QDF_STATUS_E_INVAL;
189 		goto out;
190 	}
191 	qdf_mem_copy(op_mc_list_req, &vdev_ctx->vdev_mc_list_req,
192 		sizeof(*op_mc_list_req));
193 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
194 
195 	status = pmo_core_set_mc_filter_req(vdev, op_mc_list_req);
196 	if (status != QDF_STATUS_SUCCESS) {
197 		pmo_err("cannot apply mc filter request");
198 		status = QDF_STATUS_E_INVAL;
199 		goto out;
200 	}
201 
202 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
203 	vdev_ctx->vdev_mc_list_req.is_filter_applied = true;
204 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
205 out:
206 
207 	return status;
208 }
209 
pmo_core_do_disable_mc_addr_list(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,struct pmo_mc_addr_list * op_mc_list_req)210 static QDF_STATUS pmo_core_do_disable_mc_addr_list(
211 	struct wlan_objmgr_vdev *vdev,
212 	struct pmo_vdev_priv_obj *vdev_ctx,
213 	struct pmo_mc_addr_list *op_mc_list_req)
214 {
215 	QDF_STATUS status;
216 
217 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
218 	/* validate filter is applied before clearing in fwr */
219 	if (!vdev_ctx->vdev_mc_list_req.is_filter_applied) {
220 		qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
221 		pmo_debug("mc filter is not applied in fwr");
222 		status = QDF_STATUS_E_INVAL;
223 		goto out;
224 	}
225 	qdf_mem_copy(op_mc_list_req, &vdev_ctx->vdev_mc_list_req,
226 		sizeof(*op_mc_list_req));
227 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
228 
229 	status = pmo_core_clear_mc_filter_req(vdev, op_mc_list_req);
230 	if (status != QDF_STATUS_SUCCESS) {
231 		pmo_debug("cannot apply mc filter request");
232 		status = QDF_STATUS_E_INVAL;
233 		goto out;
234 	}
235 
236 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
237 	vdev_ctx->vdev_mc_list_req.is_filter_applied = false;
238 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
239 out:
240 
241 	return status;
242 }
243 
pmo_core_max_mc_addr_supported(struct wlan_objmgr_psoc * psoc)244 uint8_t pmo_core_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc)
245 {
246 	return PMO_MAX_MC_ADDR_LIST;
247 }
248 
pmo_core_get_mc_addr_list_count(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)249 int pmo_core_get_mc_addr_list_count(struct wlan_objmgr_psoc *psoc,
250 		uint8_t vdev_id)
251 {
252 	struct wlan_objmgr_vdev *vdev;
253 	struct pmo_vdev_priv_obj *vdev_ctx;
254 	uint8_t mc_cnt;
255 
256 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
257 	if (!vdev) {
258 		pmo_err("vdev is NULL");
259 		return PMO_INVALID_MC_ADDR_COUNT;
260 	}
261 
262 	vdev_ctx = pmo_vdev_get_priv(vdev);
263 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
264 	mc_cnt = vdev_ctx->vdev_mc_list_req.mc_cnt;
265 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
266 
267 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
268 
269 	return mc_cnt;
270 }
271 
pmo_core_set_mc_addr_list_count(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t count)272 void pmo_core_set_mc_addr_list_count(struct wlan_objmgr_psoc *psoc,
273 		uint8_t vdev_id, uint8_t count)
274 {
275 	struct pmo_vdev_priv_obj *vdev_ctx;
276 	struct wlan_objmgr_vdev *vdev;
277 
278 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
279 	if (!vdev) {
280 		pmo_err("vdev is NULL");
281 		return;
282 	}
283 
284 	vdev_ctx = pmo_vdev_get_priv(vdev);
285 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
286 	vdev_ctx->vdev_mc_list_req.mc_cnt = count;
287 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
288 
289 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
290 }
291 
pmo_core_mc_addr_flitering_sanity(struct wlan_objmgr_vdev * vdev)292 static QDF_STATUS pmo_core_mc_addr_flitering_sanity(
293 			struct wlan_objmgr_vdev *vdev)
294 {
295 	struct pmo_vdev_priv_obj *vdev_ctx;
296 
297 	if (!vdev) {
298 		pmo_err("vdev is NULL");
299 		return QDF_STATUS_E_NULL_VALUE;
300 	}
301 
302 	vdev_ctx = pmo_vdev_get_priv(vdev);
303 
304 	/* Check if INI is enabled or not, otherwise just return */
305 	if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.enable_mc_list) {
306 		pmo_debug("user disabled mc_addr_list using INI");
307 		return QDF_STATUS_E_INVAL;
308 	}
309 
310 	if (!pmo_core_is_vdev_supports_offload(vdev)) {
311 		pmo_debug("vdev in invalid opmode for mc addr filtering %d",
312 			  pmo_get_vdev_opmode(vdev));
313 		return QDF_STATUS_E_INVAL;
314 	}
315 
316 	if (vdev_ctx->vdev_mc_list_req.mc_cnt > PMO_MAX_MC_ADDR_LIST) {
317 		pmo_debug("Passed more than max supported MC address count :%d",
318 			  vdev_ctx->vdev_mc_list_req.mc_cnt);
319 		return QDF_STATUS_E_INVAL;
320 	}
321 
322 	return QDF_STATUS_SUCCESS;
323 }
pmo_core_cache_mc_addr_list(struct pmo_mc_addr_list_params * mc_list_config)324 QDF_STATUS pmo_core_cache_mc_addr_list(
325 		struct pmo_mc_addr_list_params *mc_list_config)
326 {
327 	struct wlan_objmgr_vdev *vdev;
328 	QDF_STATUS status;
329 
330 	if (!mc_list_config->psoc) {
331 		pmo_err("psoc is NULL");
332 		status = QDF_STATUS_E_NULL_VALUE;
333 		goto out;
334 	}
335 
336 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mc_list_config->psoc,
337 						    mc_list_config->vdev_id,
338 						    WLAN_PMO_ID);
339 	if (!vdev) {
340 		pmo_err("vdev is NULL");
341 		status = QDF_STATUS_E_NULL_VALUE;
342 		goto out;
343 	}
344 
345 	status = pmo_core_mc_addr_flitering_sanity(vdev);
346 	if (status != QDF_STATUS_SUCCESS)
347 		goto dec_ref;
348 
349 	pmo_debug("Cache mc addr list for vdev id: %d psoc: %pK",
350 		  mc_list_config->vdev_id, mc_list_config->psoc);
351 
352 	status = pmo_core_cache_mc_addr_list_in_vdev_priv(mc_list_config, vdev);
353 
354 dec_ref:
355 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
356 out:
357 
358 	return status;
359 }
360 
pmo_core_flush_mc_addr_list(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)361 QDF_STATUS pmo_core_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc,
362 	uint8_t vdev_id)
363 {
364 	struct wlan_objmgr_vdev *vdev;
365 	QDF_STATUS status = QDF_STATUS_SUCCESS;
366 
367 	if (!psoc) {
368 		pmo_err("psoc is NULL");
369 		status = QDF_STATUS_E_NULL_VALUE;
370 		goto out;
371 	}
372 
373 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
374 	if (!vdev) {
375 		pmo_err("vdev is NULL");
376 		status = QDF_STATUS_E_NULL_VALUE;
377 		goto out;
378 	}
379 
380 	status = pmo_core_mc_addr_flitering_sanity(vdev);
381 	if (status != QDF_STATUS_SUCCESS)
382 		goto dec_ref;
383 
384 	pmo_debug("Flush mc addr list for vdev id: %d psoc: %pK",
385 		  vdev_id, psoc);
386 
387 	status = pmo_core_flush_mc_addr_list_from_vdev_priv(vdev);
388 
389 dec_ref:
390 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
391 out:
392 
393 	return status;
394 }
395 
pmo_core_handle_enable_mc_list_trigger(struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)396 static QDF_STATUS pmo_core_handle_enable_mc_list_trigger(
397 			struct wlan_objmgr_vdev *vdev,
398 			enum pmo_offload_trigger trigger)
399 {
400 	struct pmo_vdev_priv_obj *vdev_ctx;
401 	QDF_STATUS status = QDF_STATUS_SUCCESS;
402 	struct pmo_mc_addr_list *op_mc_list_req;
403 
404 	vdev_ctx = pmo_vdev_get_priv(vdev);
405 
406 	op_mc_list_req = qdf_mem_malloc(sizeof(*op_mc_list_req));
407 	if (!op_mc_list_req) {
408 		status = QDF_STATUS_E_NOMEM;
409 		goto exit_with_status;
410 	}
411 
412 	switch (trigger) {
413 	case pmo_mc_list_change_notify:
414 		if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) {
415 			pmo_debug("active offload is disabled, skip in mode %d",
416 				  trigger);
417 			goto free_req;
418 		}
419 		status = pmo_core_do_enable_mc_addr_list(vdev, vdev_ctx,
420 							 op_mc_list_req);
421 		break;
422 	case pmo_apps_suspend:
423 		if (vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) {
424 			pmo_debug("active offload is enabled, skip in mode %d",
425 				  trigger);
426 			goto free_req;
427 		}
428 		status = pmo_core_do_enable_mc_addr_list(vdev, vdev_ctx,
429 							 op_mc_list_req);
430 		break;
431 	default:
432 		status = QDF_STATUS_E_INVAL;
433 		pmo_err("invalid pmo trigger for enable mc list");
434 		break;
435 	}
436 
437 free_req:
438 	qdf_mem_free(op_mc_list_req);
439 
440 exit_with_status:
441 
442 	return status;
443 }
444 
pmo_core_enable_mc_addr_filtering_in_fwr(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum pmo_offload_trigger trigger)445 QDF_STATUS pmo_core_enable_mc_addr_filtering_in_fwr(
446 		struct wlan_objmgr_psoc *psoc,
447 		uint8_t vdev_id,
448 		enum pmo_offload_trigger trigger)
449 {
450 	QDF_STATUS status;
451 	struct wlan_objmgr_vdev *vdev;
452 
453 	status = pmo_psoc_get_ref(psoc);
454 	if (QDF_IS_STATUS_ERROR(status))
455 		goto exit_with_status;
456 
457 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
458 	if (!vdev) {
459 		pmo_err("vdev is NULL");
460 		status = QDF_STATUS_E_INVAL;
461 		goto put_psoc;
462 	}
463 
464 	status = pmo_core_mc_addr_flitering_sanity(vdev);
465 	if (status != QDF_STATUS_SUCCESS)
466 		goto put_vdev;
467 
468 	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) {
469 		status = QDF_STATUS_E_INVAL;
470 		goto put_vdev;
471 	}
472 
473 	pmo_debug("enable mclist trigger: %d", trigger);
474 	status = pmo_core_handle_enable_mc_list_trigger(vdev, trigger);
475 
476 put_vdev:
477 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
478 
479 put_psoc:
480 	pmo_psoc_put_ref(psoc);
481 
482 exit_with_status:
483 
484 	return status;
485 }
486 
pmo_core_handle_disable_mc_list_trigger(struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)487 static QDF_STATUS pmo_core_handle_disable_mc_list_trigger(
488 			struct wlan_objmgr_vdev *vdev,
489 			enum pmo_offload_trigger trigger)
490 {
491 	QDF_STATUS status = QDF_STATUS_SUCCESS;
492 	struct pmo_vdev_priv_obj *vdev_ctx;
493 	struct pmo_mc_addr_list *op_mc_list_req;
494 
495 	vdev_ctx = pmo_vdev_get_priv(vdev);
496 
497 	op_mc_list_req = qdf_mem_malloc(sizeof(*op_mc_list_req));
498 	if (!op_mc_list_req) {
499 		status = QDF_STATUS_E_NOMEM;
500 		goto out;
501 	}
502 
503 	switch (trigger) {
504 	case pmo_peer_disconnect:
505 	case pmo_mc_list_change_notify:
506 		if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) {
507 			pmo_debug("active offload is disabled, skip in mode %d",
508 				  trigger);
509 			goto free_req;
510 		}
511 		status = pmo_core_do_disable_mc_addr_list(vdev, vdev_ctx,
512 							  op_mc_list_req);
513 		break;
514 	case pmo_apps_resume:
515 		if (vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) {
516 			pmo_debug("active offload is enabled, skip in mode %d",
517 				  trigger);
518 			goto free_req;
519 		}
520 		status = pmo_core_do_disable_mc_addr_list(vdev, vdev_ctx,
521 							  op_mc_list_req);
522 		break;
523 	default:
524 		status = QDF_STATUS_E_INVAL;
525 		pmo_err("invalid pmo trigger for disable mc list");
526 		break;
527 	}
528 
529 free_req:
530 	qdf_mem_free(op_mc_list_req);
531 
532 out:
533 	return status;
534 }
535 
pmo_core_disable_mc_addr_filtering_in_fwr(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum pmo_offload_trigger trigger)536 QDF_STATUS pmo_core_disable_mc_addr_filtering_in_fwr(
537 		struct wlan_objmgr_psoc *psoc,
538 		uint8_t vdev_id,
539 		enum pmo_offload_trigger trigger)
540 {
541 	QDF_STATUS status;
542 	struct wlan_objmgr_vdev *vdev;
543 
544 	if (!psoc) {
545 		pmo_err("psoc is NULL");
546 		status = QDF_STATUS_E_INVAL;
547 		goto out;
548 	}
549 
550 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
551 	if (!vdev) {
552 		pmo_err("vdev is NULL");
553 		status = QDF_STATUS_E_NULL_VALUE;
554 		goto out;
555 	}
556 
557 	status = pmo_core_mc_addr_flitering_sanity(vdev);
558 	if (status != QDF_STATUS_SUCCESS)
559 		goto put_ref;
560 
561 	pmo_debug("disable mclist trigger: %d", trigger);
562 
563 	status = pmo_core_handle_disable_mc_list_trigger(vdev, trigger);
564 
565 put_ref:
566 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
567 
568 out:
569 
570 	return status;
571 }
572 
573 QDF_STATUS
pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,struct pmo_mc_addr_list * mc_list_req)574 pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc *psoc,
575 			  uint8_t vdev_id,
576 			  struct pmo_mc_addr_list *mc_list_req)
577 {
578 	QDF_STATUS status;
579 	struct wlan_objmgr_vdev *vdev;
580 	struct pmo_vdev_priv_obj *vdev_ctx;
581 
582 	pmo_enter();
583 
584 	if (!mc_list_req)
585 		return QDF_STATUS_E_INVAL;
586 
587 	qdf_mem_zero(mc_list_req, sizeof(*mc_list_req));
588 
589 	status = pmo_psoc_get_ref(psoc);
590 	if (QDF_IS_STATUS_ERROR(status))
591 		goto exit_with_status;
592 
593 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
594 	if (!vdev) {
595 		pmo_err("vdev is NULL");
596 		status = QDF_STATUS_E_INVAL;
597 		goto put_psoc;
598 	}
599 
600 	status = pmo_core_mc_addr_flitering_sanity(vdev);
601 	if (status != QDF_STATUS_SUCCESS)
602 		goto put_vdev;
603 
604 	vdev_ctx = pmo_vdev_get_priv(vdev);
605 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
606 	*mc_list_req = vdev_ctx->vdev_mc_list_req;
607 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
608 
609 put_vdev:
610 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
611 
612 put_psoc:
613 	pmo_psoc_put_ref(psoc);
614 
615 exit_with_status:
616 	pmo_exit();
617 
618 	return status;
619 }
620