1 /*
2 * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-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: Implement various notification handlers which are accessed
22 * internally in action_oui component only.
23 */
24 #include "cfg_ucfg_api.h"
25 #include "wlan_action_oui_cfg.h"
26 #include "wlan_action_oui_main.h"
27 #include "wlan_action_oui_public_struct.h"
28 #include "wlan_action_oui_tgt_api.h"
29 #include "target_if_action_oui.h"
30
31 /**
32 * action_oui_allocate() - Allocates memory for various actions.
33 * @psoc_priv: pointer to action_oui psoc priv obj
34 *
35 * This function allocates memory for all the action_oui types
36 * and initializes the respective lists to store extensions
37 * extracted from action_oui_extract().
38 *
39 * Return: QDF_STATUS
40 */
41 static QDF_STATUS
action_oui_allocate(struct action_oui_psoc_priv * psoc_priv)42 action_oui_allocate(struct action_oui_psoc_priv *psoc_priv)
43 {
44 struct action_oui_priv *oui_priv;
45 uint32_t i;
46 uint32_t j;
47
48 for (i = 0; i < ACTION_OUI_MAXIMUM_ID; i++) {
49 oui_priv = qdf_mem_malloc(sizeof(*oui_priv));
50 if (!oui_priv) {
51 action_oui_err("Mem alloc failed for oui_priv id: %u",
52 i);
53 goto free_mem;
54 }
55 oui_priv->id = i;
56 qdf_list_create(&oui_priv->extension_list,
57 ACTION_OUI_MAX_EXTENSIONS);
58 qdf_mutex_create(&oui_priv->extension_lock);
59 psoc_priv->oui_priv[i] = oui_priv;
60 }
61
62 return QDF_STATUS_SUCCESS;
63
64 free_mem:
65 for (j = 0; j < i; j++) {
66 oui_priv = psoc_priv->oui_priv[j];
67 if (!oui_priv)
68 continue;
69
70 qdf_list_destroy(&oui_priv->extension_list);
71 qdf_mutex_destroy(&oui_priv->extension_lock);
72 psoc_priv->oui_priv[j] = NULL;
73 }
74
75 return QDF_STATUS_E_NOMEM;
76 }
77
78 /**
79 * action_oui_destroy() - Deallocates memory for various actions.
80 * @psoc_priv: pointer to action_oui psoc priv obj
81 *
82 * This function Deallocates memory for all the action_oui types.
83 * As a part of deallocate, all extensions are destroyed.
84 *
85 * Return: None
86 */
87 static void
action_oui_destroy(struct action_oui_psoc_priv * psoc_priv)88 action_oui_destroy(struct action_oui_psoc_priv *psoc_priv)
89 {
90 struct action_oui_priv *oui_priv;
91 struct action_oui_extension_priv *ext_priv;
92 qdf_list_t *ext_list;
93 QDF_STATUS status;
94 qdf_list_node_t *node = NULL;
95 uint32_t i;
96
97 psoc_priv->total_extensions = 0;
98 psoc_priv->max_extensions = 0;
99 psoc_priv->host_only_extensions = 0;
100
101 for (i = 0; i < ACTION_OUI_MAXIMUM_ID; i++) {
102 oui_priv = psoc_priv->oui_priv[i];
103 psoc_priv->oui_priv[i] = NULL;
104 if (!oui_priv)
105 continue;
106
107 ext_list = &oui_priv->extension_list;
108 qdf_mutex_acquire(&oui_priv->extension_lock);
109 while (!qdf_list_empty(ext_list)) {
110 status = qdf_list_remove_front(ext_list, &node);
111 if (!QDF_IS_STATUS_SUCCESS(status)) {
112 action_oui_err("Invalid delete in action: %u",
113 oui_priv->id);
114 break;
115 }
116 ext_priv = qdf_container_of(node,
117 struct action_oui_extension_priv,
118 item);
119 qdf_mem_free(ext_priv);
120 ext_priv = NULL;
121 }
122
123 qdf_list_destroy(ext_list);
124 qdf_mutex_release(&oui_priv->extension_lock);
125 qdf_mutex_destroy(&oui_priv->extension_lock);
126 qdf_mem_free(oui_priv);
127 oui_priv = NULL;
128 }
129 }
130
action_oui_load_config(struct action_oui_psoc_priv * psoc_priv)131 static void action_oui_load_config(struct action_oui_psoc_priv *psoc_priv)
132 {
133 struct wlan_objmgr_psoc *psoc = psoc_priv->psoc;
134
135 psoc_priv->action_oui_enable =
136 cfg_get(psoc, CFG_ENABLE_ACTION_OUI);
137
138 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CONNECT_1X1],
139 cfg_get(psoc, CFG_ACTION_OUI_CONNECT_1X1),
140 ACTION_OUI_MAX_STR_LEN);
141 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ITO_EXTENSION],
142 cfg_get(psoc, CFG_ACTION_OUI_ITO_EXTENSION),
143 ACTION_OUI_MAX_STR_LEN);
144 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CCKM_1X1],
145 cfg_get(psoc, CFG_ACTION_OUI_CCKM_1X1),
146 ACTION_OUI_MAX_STR_LEN);
147 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ITO_ALTERNATE],
148 cfg_get(psoc, CFG_ACTION_OUI_ITO_ALTERNATE),
149 ACTION_OUI_MAX_STR_LEN);
150 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_SWITCH_TO_11N_MODE],
151 cfg_get(psoc, CFG_ACTION_OUI_SWITCH_TO_11N_MODE),
152 ACTION_OUI_MAX_STR_LEN);
153 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN],
154 cfg_get(psoc,
155 CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN),
156 ACTION_OUI_MAX_STR_LEN);
157 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_AGGRESSIVE_TX],
158 cfg_get(psoc,
159 CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX),
160 ACTION_OUI_MAX_STR_LEN);
161 qdf_str_lcopy(psoc_priv->action_oui_str
162 [ACTION_OUI_DISABLE_AGGRESSIVE_EDCA],
163 cfg_get(psoc,
164 CFG_ACTION_OUI_DISABLE_AGGRESSIVE_EDCA),
165 ACTION_OUI_MAX_STR_LEN);
166 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_EXTEND_WOW_ITO],
167 cfg_get(psoc, CFG_ACTION_OUI_EXTEND_WOW_ITO),
168 ACTION_OUI_MAX_STR_LEN);
169 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_TWT],
170 cfg_get(psoc, CFG_ACTION_OUI_DISABLE_TWT),
171 ACTION_OUI_MAX_STR_LEN);
172 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_HOST_RECONN],
173 cfg_get(psoc, CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT),
174 ACTION_OUI_MAX_STR_LEN);
175 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_TAKE_ALL_BAND_INFO],
176 cfg_get(psoc, CFG_ACTION_OUI_TAKE_ALL_BAND_INFO),
177 ACTION_OUI_MAX_STR_LEN);
178 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_11BE_OUI_ALLOW],
179 cfg_get(psoc, CFG_ACTION_OUI_11BE_ALLOW_LIST),
180 ACTION_OUI_MAX_STR_LEN);
181 qdf_str_lcopy(psoc_priv->action_oui_str
182 [ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE],
183 cfg_get(psoc,
184 CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE),
185 ACTION_OUI_MAX_STR_LEN);
186 qdf_str_lcopy(psoc_priv->action_oui_str
187 [ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL],
188 cfg_get(psoc,
189 CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL),
190 ACTION_OUI_MAX_STR_LEN);
191
192 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ENABLE_CTS2SELF],
193 cfg_get(psoc, CFG_ACTION_OUI_ENABLE_CTS2SELF),
194 ACTION_OUI_MAX_STR_LEN);
195
196 qdf_str_lcopy(psoc_priv->action_oui_str
197 [ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN],
198 cfg_get(psoc,
199 CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN),
200 ACTION_OUI_MAX_STR_LEN);
201 qdf_str_lcopy(psoc_priv->action_oui_str
202 [ACTION_OUI_RESTRICT_MAX_MLO_LINKS],
203 cfg_get(psoc, CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS),
204 ACTION_OUI_MAX_STR_LEN);
205 qdf_str_lcopy(psoc_priv->action_oui_str
206 [ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ],
207 cfg_get(psoc, CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ),
208 ACTION_OUI_MAX_STR_LEN);
209 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_BFORMEE],
210 cfg_get(psoc, CFG_ACTION_OUI_DISABLE_BFORMEE),
211 ACTION_OUI_MAX_STR_LEN);
212 qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_LIMIT_BW],
213 cfg_get(psoc, CFG_ACTION_OUI_LIMIT_BW),
214 ACTION_OUI_MAX_STR_LEN);
215 }
216
action_oui_parse_config(struct wlan_objmgr_psoc * psoc)217 static void action_oui_parse_config(struct wlan_objmgr_psoc *psoc)
218 {
219 QDF_STATUS status;
220 uint32_t id;
221 uint8_t *str;
222 struct action_oui_psoc_priv *psoc_priv;
223
224 if (!psoc) {
225 action_oui_err("Invalid psoc");
226 return;
227 }
228
229 psoc_priv = action_oui_psoc_get_priv(psoc);
230 if (!psoc_priv) {
231 action_oui_err("psoc priv is NULL");
232 return;
233 }
234 if (!psoc_priv->action_oui_enable) {
235 action_oui_debug("action_oui is not enable");
236 return;
237 }
238 for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) {
239 str = psoc_priv->action_oui_str[id];
240 if (!qdf_str_len(str))
241 continue;
242
243 status = action_oui_parse_string(psoc, str, id);
244 if (!QDF_IS_STATUS_SUCCESS(status))
245 action_oui_err("Failed to parse action_oui str: %u",
246 id);
247 }
248
249 /* FW allocates memory for the extensions only during init time.
250 * Therefore, send additional legspace for configuring new
251 * extensions during runtime.
252 * The current max value is default extensions count + 10.
253 */
254 psoc_priv->max_extensions = psoc_priv->total_extensions -
255 psoc_priv->host_only_extensions +
256 ACTION_OUI_MAX_ADDNL_EXTENSIONS;
257 action_oui_debug("Extensions - Max: %d Total: %d host_only %d",
258 psoc_priv->max_extensions, psoc_priv->total_extensions,
259 psoc_priv->host_only_extensions);
260 }
261
action_oui_send_config(struct wlan_objmgr_psoc * psoc)262 static QDF_STATUS action_oui_send_config(struct wlan_objmgr_psoc *psoc)
263 {
264 struct action_oui_psoc_priv *psoc_priv;
265 QDF_STATUS status = QDF_STATUS_E_INVAL;
266 uint32_t id;
267
268 if (!psoc) {
269 action_oui_err("psoc is NULL");
270 goto exit;
271 }
272
273 psoc_priv = action_oui_psoc_get_priv(psoc);
274 if (!psoc_priv) {
275 action_oui_err("psoc priv is NULL");
276 goto exit;
277 }
278 if (!psoc_priv->action_oui_enable) {
279 action_oui_debug("action_oui is not enable");
280 return QDF_STATUS_SUCCESS;
281 }
282
283 for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) {
284 if (id >= ACTION_OUI_HOST_ONLY)
285 continue;
286 status = action_oui_send(psoc_priv, id);
287 if (!QDF_IS_STATUS_SUCCESS(status))
288 action_oui_err("Failed to send: %u", id);
289 }
290
291 exit:
292 return status;
293 }
294
295 QDF_STATUS
action_oui_psoc_create_notification(struct wlan_objmgr_psoc * psoc,void * arg)296 action_oui_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg)
297 {
298 struct action_oui_psoc_priv *psoc_priv;
299 QDF_STATUS status;
300
301 ACTION_OUI_ENTER();
302
303 psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv));
304 if (!psoc_priv) {
305 status = QDF_STATUS_E_NOMEM;
306 goto exit;
307 }
308
309 status = wlan_objmgr_psoc_component_obj_attach(psoc,
310 WLAN_UMAC_COMP_ACTION_OUI,
311 (void *)psoc_priv, QDF_STATUS_SUCCESS);
312 if (!QDF_IS_STATUS_SUCCESS(status)) {
313 action_oui_err("Failed to attach priv with psoc");
314 goto free_psoc_priv;
315 }
316
317 target_if_action_oui_register_tx_ops(&psoc_priv->tx_ops);
318 psoc_priv->psoc = psoc;
319 action_oui_load_config(psoc_priv);
320 action_oui_debug("psoc priv attached");
321 goto exit;
322 free_psoc_priv:
323 qdf_mem_free(psoc_priv);
324 status = QDF_STATUS_E_INVAL;
325 exit:
326 ACTION_OUI_EXIT();
327 return status;
328 }
329
330 QDF_STATUS
action_oui_psoc_destroy_notification(struct wlan_objmgr_psoc * psoc,void * arg)331 action_oui_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg)
332 {
333 struct action_oui_psoc_priv *psoc_priv = NULL;
334 QDF_STATUS status = QDF_STATUS_E_FAILURE;
335
336 ACTION_OUI_ENTER();
337
338 psoc_priv = action_oui_psoc_get_priv(psoc);
339 if (!psoc_priv) {
340 action_oui_err("psoc priv is NULL");
341 goto exit;
342 }
343
344 status = wlan_objmgr_psoc_component_obj_detach(psoc,
345 WLAN_UMAC_COMP_ACTION_OUI,
346 (void *)psoc_priv);
347 if (!QDF_IS_STATUS_SUCCESS(status))
348 action_oui_err("Failed to detach priv with psoc");
349
350 qdf_mem_free(psoc_priv);
351
352 exit:
353 ACTION_OUI_EXIT();
354 return status;
355 }
356
action_oui_psoc_enable(struct wlan_objmgr_psoc * psoc)357 void action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc)
358 {
359 struct action_oui_psoc_priv *psoc_priv;
360 QDF_STATUS status = QDF_STATUS_E_FAILURE;
361
362 ACTION_OUI_ENTER();
363
364 psoc_priv = action_oui_psoc_get_priv(psoc);
365 if (!psoc_priv) {
366 action_oui_err("psoc priv is NULL");
367 goto exit;
368 }
369
370 status = action_oui_allocate(psoc_priv);
371 if (!QDF_IS_STATUS_SUCCESS(status)) {
372 action_oui_err("Failed to alloc action_oui");
373 goto exit;
374 }
375 action_oui_parse_config(psoc);
376 action_oui_send_config(psoc);
377 exit:
378 ACTION_OUI_EXIT();
379 }
380
action_oui_psoc_disable(struct wlan_objmgr_psoc * psoc)381 void action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc)
382 {
383 struct action_oui_psoc_priv *psoc_priv;
384
385 ACTION_OUI_ENTER();
386
387 psoc_priv = action_oui_psoc_get_priv(psoc);
388 if (!psoc_priv) {
389 action_oui_err("psoc priv is NULL");
390 goto exit;
391 }
392
393 action_oui_destroy(psoc_priv);
394 exit:
395 ACTION_OUI_EXIT();
396 }
397
wlan_action_oui_search(struct wlan_objmgr_psoc * psoc,struct action_oui_search_attr * attr,enum action_oui_id action_id)398 bool wlan_action_oui_search(struct wlan_objmgr_psoc *psoc,
399 struct action_oui_search_attr *attr,
400 enum action_oui_id action_id)
401 {
402 struct action_oui_psoc_priv *psoc_priv;
403 bool found = false;
404
405 if (!psoc || !attr) {
406 action_oui_err("Invalid psoc or search attrs");
407 goto exit;
408 }
409
410 if (action_id >= ACTION_OUI_MAXIMUM_ID) {
411 action_oui_err("Invalid action_oui id: %u", action_id);
412 goto exit;
413 }
414
415 psoc_priv = action_oui_psoc_get_priv(psoc);
416 if (!psoc_priv) {
417 action_oui_err("psoc priv is NULL");
418 goto exit;
419 }
420
421 found = action_oui_search(psoc_priv, attr, action_id);
422
423 exit:
424 return found;
425 }
426
427 QDF_STATUS
wlan_action_oui_cleanup(struct action_oui_psoc_priv * psoc_priv,enum action_oui_id action_id)428 wlan_action_oui_cleanup(struct action_oui_psoc_priv *psoc_priv,
429 enum action_oui_id action_id)
430 {
431 struct action_oui_priv *oui_priv;
432 struct action_oui_extension_priv *ext_priv;
433 qdf_list_t *ext_list;
434 QDF_STATUS status;
435 qdf_list_node_t *node = NULL;
436
437 if (action_id >= ACTION_OUI_MAXIMUM_ID)
438 return QDF_STATUS_E_INVAL;
439
440 oui_priv = psoc_priv->oui_priv[action_id];
441 if (!oui_priv)
442 return QDF_STATUS_SUCCESS;
443
444 ext_list = &oui_priv->extension_list;
445 qdf_mutex_acquire(&oui_priv->extension_lock);
446 while (!qdf_list_empty(ext_list)) {
447 status = qdf_list_remove_front(ext_list, &node);
448 if (!QDF_IS_STATUS_SUCCESS(status)) {
449 action_oui_err("Invalid delete in action: %u",
450 oui_priv->id);
451 break;
452 }
453 ext_priv = qdf_container_of(
454 node,
455 struct action_oui_extension_priv,
456 item);
457 qdf_mem_free(ext_priv);
458 ext_priv = NULL;
459 if (psoc_priv->total_extensions)
460 psoc_priv->total_extensions--;
461 else
462 action_oui_err("unexpected total_extensions 0");
463
464 if (action_id >= ACTION_OUI_HOST_ONLY) {
465 if (!psoc_priv->host_only_extensions)
466 action_oui_err("unexpected total host extensions");
467 else
468 psoc_priv->host_only_extensions--;
469 }
470 }
471 qdf_mutex_release(&oui_priv->extension_lock);
472
473 return QDF_STATUS_SUCCESS;
474 }
475
wlan_action_oui_is_empty(struct wlan_objmgr_psoc * psoc,enum action_oui_id action_id)476 bool wlan_action_oui_is_empty(struct wlan_objmgr_psoc *psoc,
477 enum action_oui_id action_id)
478 {
479 struct action_oui_psoc_priv *psoc_priv;
480 bool empty = true;
481
482 if (!psoc) {
483 action_oui_err("Invalid psoc");
484 goto exit;
485 }
486
487 if (action_id >= ACTION_OUI_MAXIMUM_ID) {
488 action_oui_err("Invalid action_oui id: %u", action_id);
489 goto exit;
490 }
491
492 psoc_priv = action_oui_psoc_get_priv(psoc);
493 if (!psoc_priv) {
494 action_oui_err("psoc priv is NULL");
495 goto exit;
496 }
497
498 empty = action_oui_is_empty(psoc_priv, action_id);
499
500 exit:
501 return empty;
502 }
503
504