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