1 /*
2  * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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 parsing logic for action_oui strings, extract
22  * extensions and store them using linked list. Functions defined in
23  * this file can be accessed internally in action_oui component only.
24  */
25 
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 #include <qdf_str.h>
31 #include <wlan_utility.h>
32 
33 /**
34  * action_oui_string_to_hex() - convert string to uint8_t hex array
35  * @token: string to be converted
36  * @hex: output string to hold converted string
37  * @no_of_lengths: count of possible lengths for input string
38  * @possible_lengths: array holding possible lengths
39  *
40  * This function converts the continuous input string of even length and
41  * containing hexa decimal characters into hexa decimal array of uint8_t type.
42  * Input string needs to be NULL terminated and the length should match with
43  * one of entries in @possible_lengths
44  *
45  * Return: If conversion is successful return true else false
46  */
action_oui_string_to_hex(uint8_t * token,uint8_t * hex,uint32_t no_of_lengths,uint32_t * possible_lengths)47 static bool action_oui_string_to_hex(uint8_t *token, uint8_t *hex,
48 			      uint32_t no_of_lengths,
49 			      uint32_t *possible_lengths)
50 {
51 	uint32_t token_len = qdf_str_len(token);
52 	uint32_t hex_str_len;
53 	uint32_t i;
54 	int ret;
55 
56 	if (!token_len || (token_len & 0x01)) {
57 		action_oui_err("Token len is not multiple of 2");
58 		return false;
59 	}
60 
61 	for (i = 0; i < no_of_lengths; i++)
62 		if (token_len == possible_lengths[i])
63 			break;
64 
65 	if (i == no_of_lengths) {
66 		action_oui_err("Token len doesn't match with expected len");
67 		return false;
68 	}
69 
70 	hex_str_len = token_len / 2;
71 
72 	ret = qdf_hex_str_to_binary(hex, token, hex_str_len);
73 	if (ret) {
74 		action_oui_err("Token doesn't contain hex digits");
75 		return false;
76 	}
77 
78 	return true;
79 }
80 
81 /**
82  * action_oui_token_string() - converts enum value to string
83  * @token_id: enum value to be converted to string
84  *
85  * This function converts the enum value of type action_oui_token_type
86  * to string
87  *
88  * Return: converted string
89  */
90 static
action_oui_token_string(enum action_oui_token_type token_id)91 uint8_t *action_oui_token_string(enum action_oui_token_type token_id)
92 {
93 	switch (token_id) {
94 		CASE_RETURN_STRING(ACTION_OUI_TOKEN);
95 		CASE_RETURN_STRING(ACTION_OUI_DATA_LENGTH_TOKEN);
96 		CASE_RETURN_STRING(ACTION_OUI_DATA_TOKEN);
97 		CASE_RETURN_STRING(ACTION_OUI_DATA_MASK_TOKEN);
98 		CASE_RETURN_STRING(ACTION_OUI_INFO_MASK_TOKEN);
99 		CASE_RETURN_STRING(ACTION_OUI_MAC_ADDR_TOKEN);
100 		CASE_RETURN_STRING(ACTION_OUI_MAC_MASK_TOKEN);
101 		CASE_RETURN_STRING(ACTION_OUI_CAPABILITY_TOKEN);
102 		CASE_RETURN_STRING(ACTION_OUI_END_TOKEN);
103 	}
104 
105 	return (uint8_t *) "UNKNOWN";
106 }
107 
108 /**
109  * validate_and_convert_oui() - validate and convert OUI str to hex array
110  * @token: OUI string
111  * @ext: pointer to container which holds converted hex array
112  * @action_token: next action to be parsed
113  *
114  * This is an internal function invoked from action_oui_parse to validate
115  * the OUI string for action OUI inis, convert them to hex array and store it
116  * in action_oui extension. After successful parsing update the
117  * @action_token to hold the next expected string.
118  *
119  * Return: If conversion is successful return true else false
120  */
121 static
validate_and_convert_oui(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)122 bool validate_and_convert_oui(uint8_t *token,
123 			struct action_oui_extension *ext,
124 			enum action_oui_token_type *action_token)
125 {
126 	bool valid;
127 	uint32_t expected_token_len[2] = {6, 10};
128 
129 	valid = action_oui_string_to_hex(token, ext->oui, 2,
130 					 expected_token_len);
131 	if (!valid)
132 		return false;
133 
134 	ext->oui_length = qdf_str_len(token) / 2;
135 
136 	*action_token = ACTION_OUI_DATA_LENGTH_TOKEN;
137 
138 	return valid;
139 }
140 
141 /**
142  * validate_and_convert_data_length() - validate data len str
143  * @token: data length string
144  * @ext: pointer to container which holds hex value formed from input str
145  * @action_token: next action to be parsed
146  *
147  * This is an internal function invoked from action_oui_parse to validate
148  * the data length string for action OUI inis, convert it to hex value and
149  * store it in action_oui extension. After successful parsing update the
150  * @action_token to hold the next expected string.
151  *
152  * Return: If conversion is successful return true else false
153  */
154 static bool
validate_and_convert_data_length(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)155 validate_and_convert_data_length(uint8_t *token,
156 				struct action_oui_extension *ext,
157 				enum action_oui_token_type *action_token)
158 {
159 	uint32_t token_len = qdf_str_len(token);
160 	int ret;
161 	uint8_t len = 0;
162 
163 	if (token_len != 1 && token_len != 2) {
164 		action_oui_err("Invalid str token len for action OUI data len");
165 		return false;
166 	}
167 
168 	ret = kstrtou8(token, 16, &len);
169 	if (ret) {
170 		action_oui_err("Invalid char in action OUI data len str token");
171 		return false;
172 	}
173 
174 	if ((uint32_t)len > ACTION_OUI_MAX_DATA_LENGTH) {
175 		action_oui_err("action OUI data len %d is more than %u",
176 			       len, ACTION_OUI_MAX_DATA_LENGTH);
177 		return false;
178 	}
179 
180 	ext->data_length = len;
181 
182 	if (!ext->data_length)
183 		*action_token = ACTION_OUI_INFO_MASK_TOKEN;
184 	else
185 		*action_token = ACTION_OUI_DATA_TOKEN;
186 
187 	return true;
188 }
189 
190 /**
191  * validate_and_convert_data() - validate and convert data str to hex array
192  * @token: data string
193  * @ext: pointer to container which holds converted hex array
194  * @action_token: next action to be parsed
195  *
196  * This is an internal function invoked from action_oui_parse to validate
197  * the data string for action OUI inis, convert it to hex array and store in
198  * action_oui extension. After successful parsing update the @action_token
199  * to hold the next expected string.
200  *
201  * Return: If conversion is successful return true else false
202  */
203 static bool
validate_and_convert_data(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)204 validate_and_convert_data(uint8_t *token,
205 			      struct action_oui_extension *ext,
206 			      enum action_oui_token_type *action_token)
207 {
208 	bool valid;
209 	uint32_t expected_token_len[1] = {2 * ext->data_length};
210 
211 	valid = action_oui_string_to_hex(token, ext->data, 1,
212 					 expected_token_len);
213 	if (!valid)
214 		return false;
215 
216 	*action_token = ACTION_OUI_DATA_MASK_TOKEN;
217 
218 	return true;
219 }
220 
221 /**
222  * validate_and_convert_data_mask() - validate and convert data mask str
223  * @token: data mask string
224  * @ext: pointer to container which holds converted hex array
225  * @action_token: next action to be parsed
226  *
227  * This is an internal function invoked from action_oui_parse to validate
228  * the data mask string for action OUI inis, convert it to hex array and store
229  * in action_oui extension. After successful parsing update the
230  * @action_token to hold the next expected string.
231  *
232  * Return: If conversion is successful return true else false
233  */
234 static bool
validate_and_convert_data_mask(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)235 validate_and_convert_data_mask(uint8_t *token,
236 				   struct action_oui_extension *ext,
237 				   enum action_oui_token_type *action_token)
238 {
239 	bool valid;
240 	uint32_t expected_token_len[1];
241 	uint32_t data_mask_length;
242 	uint32_t data_length = ext->data_length;
243 
244 	if (data_length % 8 == 0)
245 		data_mask_length = data_length / 8;
246 	else
247 		data_mask_length = ((data_length / 8) + 1);
248 
249 	if (data_mask_length > ACTION_OUI_MAX_DATA_MASK_LENGTH)
250 		return false;
251 
252 	expected_token_len[0] = 2 * data_mask_length;
253 
254 	valid = action_oui_string_to_hex(token, ext->data_mask, 1,
255 				  expected_token_len);
256 	if (!valid)
257 		return false;
258 
259 	ext->data_mask_length = data_mask_length;
260 
261 	*action_token = ACTION_OUI_INFO_MASK_TOKEN;
262 
263 	return valid;
264 }
265 
266 /**
267  * validate_and_convert_info_mask() - validate and convert info mask str
268  * @token: info mask string
269  * @ext: pointer to container which holds converted hex array
270  * @action_token: next action to be parsed
271  *
272  * This is an internal function invoked from action_oui_parse to validate
273  * the info mask string for action OUI inis, convert it to hex array and store
274  * in action_oui extension. After successful parsing update the
275  * @action_token to hold the next expected string.
276  *
277  * Return: If conversion is successful return true else false
278  */
279 static bool
validate_and_convert_info_mask(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)280 validate_and_convert_info_mask(uint8_t *token,
281 				   struct action_oui_extension *ext,
282 				   enum action_oui_token_type *action_token)
283 {
284 	uint32_t token_len = qdf_str_len(token);
285 	uint8_t hex_value = 0;
286 	uint32_t info_mask;
287 	int ret;
288 
289 	if (token_len != 2) {
290 		action_oui_err("action OUI info mask str token len is not of 2 chars");
291 		return false;
292 	}
293 
294 	ret = kstrtou8(token, 16, &hex_value);
295 	if (ret) {
296 		action_oui_err("Invalid char in action OUI info mask str token");
297 		return false;
298 	}
299 
300 	info_mask = hex_value;
301 
302 	ext->info_mask = info_mask;
303 
304 	if (!info_mask || !(info_mask & ~ACTION_OUI_INFO_OUI)) {
305 		*action_token = ACTION_OUI_END_TOKEN;
306 		return true;
307 	}
308 
309 	if (info_mask & ~ACTION_OUI_INFO_MASK) {
310 		action_oui_err("Invalid bits are set in action OUI info mask");
311 		return false;
312 	}
313 
314 	/*
315 	 * If OUI bit is not set in the info presence, we need to ignore the
316 	 * OUI and OUI Data. Set OUI and OUI data length to 0 here.
317 	 */
318 	if (!(info_mask & ACTION_OUI_INFO_OUI)) {
319 		ext->oui_length = 0;
320 		ext->data_length = 0;
321 		ext->data_mask_length = 0;
322 	}
323 
324 	if (info_mask & ACTION_OUI_INFO_MAC_ADDRESS) {
325 		*action_token = ACTION_OUI_MAC_ADDR_TOKEN;
326 		return true;
327 	}
328 
329 	*action_token = ACTION_OUI_CAPABILITY_TOKEN;
330 	return true;
331 }
332 
333 /**
334  * validate_and_convert_mac_addr() - validate and convert mac addr str
335  * @token: mac address string
336  * @ext: pointer to container which holds converted hex array
337  * @action_token: next action to be parsed
338  *
339  * This is an internal function invoked from action_oui_parse to validate
340  * the mac address string for action OUI inis, convert it to hex array and store
341  * in action_oui extension. After successful parsing update the
342  * @action_token to hold the next expected string.
343  *
344  * Return: If conversion is successful return true else false
345  */
346 static bool
validate_and_convert_mac_addr(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)347 validate_and_convert_mac_addr(uint8_t *token,
348 				  struct action_oui_extension *ext,
349 				  enum action_oui_token_type *action_token)
350 {
351 	uint32_t expected_token_len[1] = {2 * QDF_MAC_ADDR_SIZE};
352 	bool valid;
353 
354 	valid = action_oui_string_to_hex(token, ext->mac_addr, 1,
355 				  expected_token_len);
356 	if (!valid)
357 		return false;
358 
359 	ext->mac_addr_length = QDF_MAC_ADDR_SIZE;
360 
361 	*action_token = ACTION_OUI_MAC_MASK_TOKEN;
362 
363 	return true;
364 }
365 
366 /**
367  * validate_and_convert_mac_mask() - validate and convert mac mask
368  * @token: mac mask string
369  * @ext: pointer to container which holds converted hex value
370  * @action_token: next action to be parsed
371  *
372  * This is an internal function invoked from action_oui_parse to validate
373  * the mac mask string for action OUI inis, convert it to hex value and store
374  * in action_oui extension. After successful parsing update the
375  * @action_token to hold the next expected string.
376  *
377  * Return: If conversion is successful return true else false
378  */
379 static bool
validate_and_convert_mac_mask(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)380 validate_and_convert_mac_mask(uint8_t *token,
381 				  struct action_oui_extension *ext,
382 				  enum action_oui_token_type *action_token)
383 {
384 	uint32_t expected_token_len[1] = {2};
385 	uint32_t info_mask = ext->info_mask;
386 	bool valid;
387 	uint32_t mac_mask_length;
388 
389 	valid = action_oui_string_to_hex(token, ext->mac_mask, 1,
390 				  expected_token_len);
391 	if (!valid)
392 		return false;
393 
394 	mac_mask_length = qdf_str_len(token) / 2;
395 	if (mac_mask_length > ACTION_OUI_MAC_MASK_LENGTH) {
396 		action_oui_err("action OUI mac mask str token len is more than %u chars",
397 			expected_token_len[0]);
398 		return false;
399 	}
400 
401 	ext->mac_mask_length = mac_mask_length;
402 
403 	if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) ||
404 	    (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_HT) ||
405 	    (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_VHT) ||
406 	    (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND)) {
407 		*action_token = ACTION_OUI_CAPABILITY_TOKEN;
408 		return true;
409 	}
410 
411 	*action_token = ACTION_OUI_END_TOKEN;
412 	return true;
413 }
414 
415 /**
416  * validate_and_convert_capability() - validate and convert capability str
417  * @token: capability string
418  * @ext: pointer to container which holds converted hex value
419  * @action_token: next action to be parsed
420  *
421  * This is an internal function invoked from action_oui_parse to validate
422  * the capability string for action OUI inis, convert it to hex value and store
423  * in action_oui extension. After successful parsing update the
424  * @action_token to hold the next expected string.
425  *
426  * Return: If conversion is successful return true else false
427  */
428 static bool
validate_and_convert_capability(uint8_t * token,struct action_oui_extension * ext,enum action_oui_token_type * action_token)429 validate_and_convert_capability(uint8_t *token,
430 				struct action_oui_extension *ext,
431 				enum action_oui_token_type *action_token)
432 {
433 	uint32_t expected_token_len[1] = {2};
434 	uint32_t info_mask = ext->info_mask;
435 	uint32_t capability_length;
436 	uint8_t caps_0;
437 	bool valid;
438 
439 	valid = action_oui_string_to_hex(token, ext->capability, 1,
440 				  expected_token_len);
441 	if (!valid)
442 		return false;
443 
444 	capability_length = qdf_str_len(token) / 2;
445 	if (capability_length > ACTION_OUI_MAX_CAPABILITY_LENGTH) {
446 		action_oui_err("action OUI capability str token len is more than %u chars",
447 			expected_token_len[0]);
448 		return false;
449 	}
450 
451 	caps_0 = ext->capability[0];
452 
453 	if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) &&
454 	    (!(caps_0 & ACTION_OUI_CAPABILITY_NSS_MASK))) {
455 		action_oui_err("Info presence for NSS is set but respective bits in capability are not set");
456 		return false;
457 	}
458 
459 	if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND) &&
460 	    (!(caps_0 & ACTION_OUI_CAPABILITY_BAND_MASK))) {
461 		action_oui_err("Info presence for BAND is set but respective bits in capability are not set");
462 		return false;
463 	}
464 
465 	ext->capability_length = capability_length;
466 
467 	*action_token = ACTION_OUI_END_TOKEN;
468 
469 	return true;
470 }
471 
472 /**
473  * action_oui_extension_store() - store action oui extension
474  * @psoc_priv: pointer to action_oui priv obj
475  * @oui_priv: type of the action
476  * @ext: oui extension to store in sme
477  *
478  * This function stores the parsed oui extension
479  *
480  * Return: QDF_STATUS
481  *
482  */
483 static QDF_STATUS
action_oui_extension_store(struct action_oui_psoc_priv * psoc_priv,struct action_oui_priv * oui_priv,struct action_oui_extension ext)484 action_oui_extension_store(struct action_oui_psoc_priv *psoc_priv,
485 			   struct action_oui_priv *oui_priv,
486 			   struct action_oui_extension ext)
487 {
488 	struct action_oui_extension_priv *ext_priv;
489 
490 	qdf_mutex_acquire(&oui_priv->extension_lock);
491 	if (qdf_list_size(&oui_priv->extension_list) ==
492 			  ACTION_OUI_MAX_EXTENSIONS) {
493 		qdf_mutex_release(&oui_priv->extension_lock);
494 		action_oui_err("Reached maximum OUI extensions");
495 		return QDF_STATUS_E_FAILURE;
496 	}
497 
498 	ext_priv = qdf_mem_malloc(sizeof(*ext_priv));
499 	if (!ext_priv) {
500 		qdf_mutex_release(&oui_priv->extension_lock);
501 		return QDF_STATUS_E_NOMEM;
502 	}
503 
504 	ext_priv->extension = ext;
505 	qdf_list_insert_back(&oui_priv->extension_list, &ext_priv->item);
506 	psoc_priv->total_extensions++;
507 	qdf_mutex_release(&oui_priv->extension_lock);
508 
509 	return QDF_STATUS_SUCCESS;
510 }
511 
512 QDF_STATUS
action_oui_parse(struct action_oui_psoc_priv * psoc_priv,uint8_t * oui_string,enum action_oui_id action_id)513 action_oui_parse(struct action_oui_psoc_priv *psoc_priv,
514 		 uint8_t *oui_string, enum action_oui_id action_id)
515 {
516 	struct action_oui_extension ext = {0};
517 	enum action_oui_token_type action_token = ACTION_OUI_TOKEN;
518 	char *str1;
519 	char *str2;
520 	char *token;
521 	bool valid = true;
522 	bool oui_count_exceed = false;
523 	uint32_t oui_index = 0;
524 	QDF_STATUS status = QDF_STATUS_SUCCESS;
525 	struct action_oui_priv *oui_priv;
526 
527 	if (!oui_string) {
528 		action_oui_err("Invalid string for action oui: %u", action_id);
529 		return QDF_STATUS_E_INVAL;
530 	}
531 
532 	oui_priv = psoc_priv->oui_priv[action_id];
533 	if (!oui_priv) {
534 		action_oui_err("action oui priv not allocated");
535 		return QDF_STATUS_E_INVAL;
536 	}
537 
538 	if (!psoc_priv->action_oui_enable) {
539 		action_oui_debug("action_oui is not enable");
540 		return QDF_STATUS_SUCCESS;
541 	}
542 
543 	str1 = qdf_str_trim((char *)oui_string);
544 
545 	while (str1) {
546 		str2 = (char *)qdf_str_left_trim(str1);
547 		if (str2[0] == '\0') {
548 			action_oui_err("Invalid spaces in action oui: %u at extension: %u for token: %s",
549 				action_id,
550 				oui_index + 1,
551 				action_oui_token_string(action_token));
552 			valid = false;
553 			break;
554 		}
555 
556 		token = strsep(&str2, " ");
557 		if (!token) {
558 			action_oui_err("Invalid string for token: %s at extension: %u in action oui: %u",
559 				action_oui_token_string(action_token),
560 				oui_index + 1, action_id);
561 			valid = false;
562 			break;
563 		}
564 
565 		str1 = str2;
566 
567 		switch (action_token) {
568 
569 		case ACTION_OUI_TOKEN:
570 			valid = validate_and_convert_oui(token, &ext,
571 							 &action_token);
572 			break;
573 
574 		case ACTION_OUI_DATA_LENGTH_TOKEN:
575 			valid = validate_and_convert_data_length(token, &ext,
576 								&action_token);
577 			break;
578 
579 		case ACTION_OUI_DATA_TOKEN:
580 			valid = validate_and_convert_data(token, &ext,
581 							&action_token);
582 			break;
583 
584 		case ACTION_OUI_DATA_MASK_TOKEN:
585 			valid = validate_and_convert_data_mask(token, &ext,
586 							&action_token);
587 			break;
588 
589 		case ACTION_OUI_INFO_MASK_TOKEN:
590 			valid = validate_and_convert_info_mask(token, &ext,
591 							&action_token);
592 			break;
593 
594 		case ACTION_OUI_MAC_ADDR_TOKEN:
595 			valid = validate_and_convert_mac_addr(token, &ext,
596 							&action_token);
597 			break;
598 
599 		case ACTION_OUI_MAC_MASK_TOKEN:
600 			valid = validate_and_convert_mac_mask(token, &ext,
601 							&action_token);
602 			break;
603 
604 		case ACTION_OUI_CAPABILITY_TOKEN:
605 			valid = validate_and_convert_capability(token, &ext,
606 							&action_token);
607 			break;
608 
609 		default:
610 			valid = false;
611 			break;
612 		}
613 
614 		if (!valid) {
615 			action_oui_err("Invalid string for token: %s at extension: %u in action oui: %u",
616 				action_oui_token_string(action_token),
617 				oui_index + 1,
618 				action_id);
619 			break;
620 		}
621 
622 		if (action_token != ACTION_OUI_END_TOKEN)
623 			continue;
624 
625 		status = action_oui_extension_store(psoc_priv, oui_priv, ext);
626 		if (!QDF_IS_STATUS_SUCCESS(status)) {
627 			valid = false;
628 			action_oui_err("sme set of extension: %u for action oui: %u failed",
629 				oui_index + 1, action_id);
630 			break;
631 		}
632 
633 		if (action_id >= ACTION_OUI_HOST_ONLY) {
634 			qdf_mutex_acquire(&oui_priv->extension_lock);
635 			psoc_priv->host_only_extensions++;
636 			qdf_mutex_release(&oui_priv->extension_lock);
637 		}
638 
639 		oui_index++;
640 		if (oui_index == ACTION_OUI_MAX_EXTENSIONS) {
641 			if (str1)
642 				oui_count_exceed = true;
643 			break;
644 		}
645 
646 		/* reset the params for next action OUI parse */
647 		action_token = ACTION_OUI_TOKEN;
648 		qdf_mem_zero(&ext, sizeof(ext));
649 	}
650 
651 	if (oui_count_exceed) {
652 		action_oui_err("Reached Maximum extensions: %u in action_oui: %u, ignoring the rest",
653 			ACTION_OUI_MAX_EXTENSIONS, action_id);
654 		return QDF_STATUS_SUCCESS;
655 	}
656 
657 	if (action_token != ACTION_OUI_TOKEN &&
658 	    action_token != ACTION_OUI_END_TOKEN &&
659 	    valid && !str1) {
660 		action_oui_err("No string for token: %s at extension: %u in action oui: %u",
661 			action_oui_token_string(action_token),
662 			oui_index + 1,
663 			action_id);
664 		valid = false;
665 	}
666 
667 	if (!oui_index) {
668 		action_oui_err("Not able to parse any extension in action oui: %u",
669 			action_id);
670 		return QDF_STATUS_E_INVAL;
671 	}
672 
673 	if (valid)
674 		action_oui_debug("All extensions: %u parsed successfully in action oui: %u",
675 			  oui_index, action_id);
676 	else
677 		action_oui_err("First %u extensions parsed successfully in action oui: %u",
678 			oui_index, action_id);
679 
680 	return QDF_STATUS_SUCCESS;
681 }
682 
683 QDF_STATUS
action_oui_parse_string(struct wlan_objmgr_psoc * psoc,const uint8_t * in_str,enum action_oui_id action_id)684 action_oui_parse_string(struct wlan_objmgr_psoc *psoc,
685 			const uint8_t *in_str,
686 			enum action_oui_id action_id)
687 {
688 	struct action_oui_psoc_priv *psoc_priv;
689 	QDF_STATUS status = QDF_STATUS_E_INVAL;
690 	uint8_t *oui_str;
691 	int len;
692 
693 	ACTION_OUI_ENTER();
694 
695 	if (!psoc) {
696 		action_oui_err("psoc is NULL");
697 		goto exit;
698 	}
699 
700 	if (action_id >= ACTION_OUI_MAXIMUM_ID) {
701 		action_oui_err("Invalid action_oui id: %u", action_id);
702 		goto exit;
703 	}
704 
705 	psoc_priv = action_oui_psoc_get_priv(psoc);
706 	if (!psoc_priv) {
707 		action_oui_err("psoc priv is NULL");
708 		goto exit;
709 	}
710 
711 	len = qdf_str_len(in_str);
712 	if (len <= 0 || len > ACTION_OUI_MAX_STR_LEN - 1) {
713 		action_oui_err("Invalid string length: %u", action_id);
714 		goto exit;
715 	}
716 
717 	oui_str = qdf_mem_malloc(len + 1);
718 	if (!oui_str) {
719 		status = QDF_STATUS_E_NOMEM;
720 		goto exit;
721 	}
722 
723 	qdf_mem_copy(oui_str, in_str, len);
724 	oui_str[len] = '\0';
725 
726 	status = action_oui_parse(psoc_priv, oui_str, action_id);
727 	if (!QDF_IS_STATUS_SUCCESS(status))
728 		action_oui_err("Failed to parse: %u", action_id);
729 
730 	qdf_mem_free(oui_str);
731 
732 exit:
733 	ACTION_OUI_EXIT();
734 	return status;
735 }
736 
action_oui_send(struct action_oui_psoc_priv * psoc_priv,enum action_oui_id action_id)737 QDF_STATUS action_oui_send(struct action_oui_psoc_priv *psoc_priv,
738 			enum action_oui_id action_id)
739 {
740 	QDF_STATUS status;
741 	struct action_oui_request *req;
742 	struct action_oui_priv *oui_priv;
743 	struct action_oui_extension *extension;
744 	struct action_oui_extension_priv *ext_priv;
745 	qdf_list_node_t *node = NULL;
746 	qdf_list_node_t *next_node = NULL;
747 	qdf_list_t *extension_list;
748 	uint32_t len;
749 	uint32_t no_oui_extensions;
750 
751 	oui_priv = psoc_priv->oui_priv[action_id];
752 	if (!oui_priv)
753 		return QDF_STATUS_SUCCESS;
754 
755 	if (!psoc_priv->action_oui_enable) {
756 		action_oui_debug("action_oui is not enable");
757 		return QDF_STATUS_SUCCESS;
758 	}
759 
760 	extension_list = &oui_priv->extension_list;
761 	qdf_mutex_acquire(&oui_priv->extension_lock);
762 
763 	if (psoc_priv->max_extensions -
764 	    (psoc_priv->total_extensions - psoc_priv->host_only_extensions) < 0) {
765 		action_oui_err("total_extensions: %d exceeds max_extensions: %d, do not update",
766 			       psoc_priv->max_extensions,
767 			       (psoc_priv->total_extensions -
768 				psoc_priv->host_only_extensions));
769 		qdf_mutex_release(&oui_priv->extension_lock);
770 		return QDF_STATUS_E_FAILURE;
771 	}
772 
773 	no_oui_extensions = qdf_list_size(extension_list);
774 	len = sizeof(*req) + no_oui_extensions * sizeof(*extension);
775 	req = qdf_mem_malloc(len);
776 	if (!req) {
777 		qdf_mutex_release(&oui_priv->extension_lock);
778 		return QDF_STATUS_E_NOMEM;
779 	}
780 
781 	req->action_id = oui_priv->id;
782 	req->no_oui_extensions = no_oui_extensions;
783 	req->total_no_oui_extensions = psoc_priv->max_extensions;
784 
785 	extension = req->extension;
786 	qdf_list_peek_front(extension_list, &node);
787 	while (node) {
788 		ext_priv = qdf_container_of(node,
789 					   struct action_oui_extension_priv,
790 					   item);
791 		*extension = ext_priv->extension;
792 		status = qdf_list_peek_next(extension_list, node,
793 						&next_node);
794 		if (!QDF_IS_STATUS_SUCCESS(status))
795 			break;
796 		node = next_node;
797 		next_node = NULL;
798 		extension++;
799 	}
800 
801 	qdf_mutex_release(&oui_priv->extension_lock);
802 
803 	status = tgt_action_oui_send(psoc_priv->psoc, req);
804 	qdf_mem_free(req);
805 
806 	return status;
807 }
808 
809 /**
810  * check_for_vendor_oui_data() - compares for vendor OUI data from IE
811  * and returns true if OUI data matches with the ini
812  * @extension: pointer to action oui extension data
813  * @oui_ptr: pointer to Vendor IE in the beacon
814  *
815  * Return: true or false
816  */
817 static bool
check_for_vendor_oui_data(struct action_oui_extension * extension,const uint8_t * oui_ptr)818 check_for_vendor_oui_data(struct action_oui_extension *extension,
819 			  const uint8_t *oui_ptr)
820 {
821 	const uint8_t *data;
822 	uint8_t i, j, elem_len, data_len;
823 	uint8_t data_mask = 0x80;
824 
825 	if (!oui_ptr)
826 		return false;
827 
828 	elem_len = oui_ptr[1];
829 	if (elem_len < extension->oui_length)
830 		return false;
831 
832 	data_len = elem_len - extension->oui_length;
833 	if (data_len < extension->data_length)
834 		return false;
835 
836 	data = &oui_ptr[2 + extension->oui_length];
837 	for (i = 0, j = 0;
838 	     (i < data_len && j < extension->data_mask_length);
839 	     i++) {
840 		if ((extension->data_mask[j] & data_mask) &&
841 		    !(extension->data[i] == data[i]))
842 			return false;
843 		data_mask = data_mask >> 1;
844 		if (!data_mask) {
845 			data_mask = 0x80;
846 			j++;
847 		}
848 	}
849 
850 	return true;
851 }
852 
853 /**
854  * check_for_vendor_ap_mac() - compares for vendor AP MAC in the ini with
855  * bssid from the session and returns true if matches
856  * @extension: pointer to action oui extension data
857  * @attr: pointer to structure containing mac_addr (bssid) of AP
858  *
859  * Return: true or false
860  */
861 static bool
check_for_vendor_ap_mac(struct action_oui_extension * extension,struct action_oui_search_attr * attr)862 check_for_vendor_ap_mac(struct action_oui_extension *extension,
863 			struct action_oui_search_attr *attr)
864 {
865 	uint8_t i;
866 	uint8_t mac_mask = 0x80;
867 	uint8_t *mac_addr = attr->mac_addr;
868 
869 	for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) {
870 		if ((*extension->mac_mask & mac_mask) &&
871 		    !(extension->mac_addr[i] == mac_addr[i]))
872 			return false;
873 		mac_mask = mac_mask >> 1;
874 	}
875 
876 	return true;
877 }
878 
879 /**
880  * check_for_vendor_ap_capabilities() - Compares various Vendor AP
881  * capabilities like NSS, HT, VHT, Band from the ini with the AP's capability
882  * from the beacon and returns true if all the capability matches
883  * @extension: pointer to oui extension data
884  * @attr: pointer to structure containing type of action, ap capabilities
885  *
886  * Return: true or false
887  */
888 static bool
check_for_vendor_ap_capabilities(struct action_oui_extension * extension,struct action_oui_search_attr * attr)889 check_for_vendor_ap_capabilities(struct action_oui_extension *extension,
890 				 struct action_oui_search_attr *attr)
891 {
892 	uint8_t nss_mask;
893 
894 	if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) {
895 		nss_mask = 1 << (attr->nss - 1);
896 		if (!((*extension->capability &
897 		    ACTION_OUI_CAPABILITY_NSS_MASK) &
898 		    nss_mask))
899 		return false;
900 	}
901 
902 	if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_HT) {
903 		if (*extension->capability &
904 		    ACTION_OUI_CAPABILITY_HT_ENABLE_MASK) {
905 			if (!attr->ht_cap)
906 				return false;
907 		} else {
908 			if (attr->ht_cap)
909 				return false;
910 		}
911 	}
912 
913 	if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_VHT) {
914 		if (*extension->capability &
915 		    ACTION_OUI_CAPABILITY_VHT_ENABLE_MASK) {
916 			if (!attr->vht_cap)
917 				return false;
918 		} else {
919 			if (attr->vht_cap)
920 				return false;
921 		}
922 	}
923 
924 	if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND &&
925 	    ((attr->enable_5g &&
926 	    !(*extension->capability & ACTION_CAPABILITY_5G_BAND_MASK)) ||
927 	    (attr->enable_2g &&
928 	    !(*extension->capability & ACTION_OUI_CAPABILITY_2G_BAND_MASK))))
929 		return false;
930 
931 	return true;
932 }
933 
934 static const uint8_t *
action_oui_get_oui_ptr(struct action_oui_extension * extension,struct action_oui_search_attr * attr)935 action_oui_get_oui_ptr(struct action_oui_extension *extension,
936 		       struct action_oui_search_attr *attr)
937 {
938 	if (!attr->ie_data || !attr->ie_length)
939 		return NULL;
940 
941 	return wlan_get_vendor_ie_ptr_from_oui(extension->oui,
942 					       extension->oui_length,
943 					       attr->ie_data,
944 					       attr->ie_length);
945 }
946 
947 bool
action_oui_is_empty(struct action_oui_psoc_priv * psoc_priv,enum action_oui_id action_id)948 action_oui_is_empty(struct action_oui_psoc_priv *psoc_priv,
949 		    enum action_oui_id action_id)
950 {
951 	struct action_oui_priv *oui_priv;
952 	qdf_list_t *extension_list;
953 
954 	oui_priv = psoc_priv->oui_priv[action_id];
955 	if (!oui_priv)
956 		return true;
957 
958 	extension_list = &oui_priv->extension_list;
959 	qdf_mutex_acquire(&oui_priv->extension_lock);
960 	if (qdf_list_empty(extension_list)) {
961 		qdf_mutex_release(&oui_priv->extension_lock);
962 		return true;
963 	}
964 	qdf_mutex_release(&oui_priv->extension_lock);
965 
966 	return false;
967 }
968 
validate_vendor_oui_data(struct action_oui_extension * extension,struct action_oui_search_attr * attr)969 static bool validate_vendor_oui_data(struct action_oui_extension *extension,
970 				     struct action_oui_search_attr *attr)
971 {
972 	uint8_t elem_id, elem_len;
973 	int32_t left;
974 	uint8_t eid = WLAN_MAC_EID_VENDOR;
975 	const uint8_t *ptr = NULL;
976 	const uint8_t *oui = extension->oui;
977 
978 	if (!attr->ie_data || !attr->ie_length || !oui)
979 		return false;
980 
981 	ptr = attr->ie_data;
982 	left = attr->ie_length;
983 
984 	while (left >= 2) {
985 		elem_id  = ptr[0];
986 		elem_len = ptr[1];
987 		left -= 2;
988 
989 		if (elem_len > left)
990 			return false;
991 
992 		if (eid == elem_id) {
993 			/*
994 			 * if oui is provided and oui_size is more than left
995 			 * bytes, then we cannot have match
996 			 */
997 			if (extension->oui_length > left)
998 				return false;
999 
1000 			if (qdf_mem_cmp(&ptr[2], extension->oui,
1001 					extension->oui_length) == 0 &&
1002 			    check_for_vendor_oui_data(extension, ptr))
1003 				return true;
1004 		}
1005 
1006 		left -= elem_len;
1007 		ptr += (elem_len + 2);
1008 	}
1009 
1010 	return false;
1011 }
1012 
1013 bool
action_oui_search(struct action_oui_psoc_priv * psoc_priv,struct action_oui_search_attr * attr,enum action_oui_id action_id)1014 action_oui_search(struct action_oui_psoc_priv *psoc_priv,
1015 		  struct action_oui_search_attr *attr,
1016 		  enum action_oui_id action_id)
1017 {
1018 	struct action_oui_priv *oui_priv;
1019 	struct action_oui_extension_priv *priv_ext;
1020 	struct action_oui_extension *extension;
1021 	qdf_list_node_t *node = NULL;
1022 	qdf_list_node_t *next_node = NULL;
1023 	qdf_list_t *extension_list;
1024 	QDF_STATUS qdf_status;
1025 	const uint8_t *oui_ptr;
1026 	bool wildcard_oui = false;
1027 
1028 	oui_priv = psoc_priv->oui_priv[action_id];
1029 	if (!oui_priv) {
1030 		action_oui_debug("action oui for id %d is empty",
1031 				 action_id);
1032 		return false;
1033 	}
1034 
1035 	extension_list = &oui_priv->extension_list;
1036 	qdf_mutex_acquire(&oui_priv->extension_lock);
1037 	if (qdf_list_empty(extension_list)) {
1038 		qdf_mutex_release(&oui_priv->extension_lock);
1039 		return false;
1040 	}
1041 
1042 	qdf_list_peek_front(extension_list, &node);
1043 	while (node) {
1044 		priv_ext = qdf_container_of(node,
1045 					   struct action_oui_extension_priv,
1046 					   item);
1047 		extension = &priv_ext->extension;
1048 
1049 		/*
1050 		 * If a wildcard OUI bit is not set in the info_mask, proceed
1051 		 * to other checks skipping the OUI and vendor data checks
1052 		 */
1053 
1054 		if (!(extension->info_mask & ACTION_OUI_INFO_OUI))
1055 			wildcard_oui = true;
1056 
1057 		oui_ptr = action_oui_get_oui_ptr(extension, attr);
1058 
1059 		if (!oui_ptr  && !wildcard_oui)
1060 			goto next;
1061 
1062 		if (extension->data_length && !wildcard_oui &&
1063 		    !validate_vendor_oui_data(extension, attr))
1064 			goto next;
1065 
1066 		if ((extension->info_mask & ACTION_OUI_INFO_MAC_ADDRESS) &&
1067 		    !check_for_vendor_ap_mac(extension, attr))
1068 			goto next;
1069 
1070 		if (!check_for_vendor_ap_capabilities(extension, attr))
1071 			goto next;
1072 
1073 		action_oui_debug("Vendor AP/STA found for OUI");
1074 		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
1075 				   extension->oui, extension->oui_length);
1076 		qdf_mutex_release(&oui_priv->extension_lock);
1077 		return true;
1078 next:
1079 		qdf_status = qdf_list_peek_next(extension_list,
1080 						node, &next_node);
1081 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
1082 			break;
1083 
1084 		node = next_node;
1085 		next_node = NULL;
1086 		wildcard_oui = false;
1087 	}
1088 
1089 	qdf_mutex_release(&oui_priv->extension_lock);
1090 	return false;
1091 }
1092