1 /*
2  * Copyright (c) 2013-2021 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  *
22  * This file lim_utils.cc contains the utility functions
23  * LIM uses.
24  * Author:        Chandra Modumudi
25  * Date:          02/13/02
26  * History:-
27  * Date           Modified by    Modification Information
28  * --------------------------------------------------------------------
29  */
30 
31 #include "ani_global.h"
32 #include "wni_api.h"
33 
34 #include "sir_common.h"
35 #include "wni_cfg.h"
36 
37 #include "utils_api.h"
38 #include "lim_utils.h"
39 #include "lim_security_utils.h"
40 #include "lim_ft_defs.h"
41 #include "lim_session.h"
42 #include <lim_assoc_utils.h>
43 
44 #define LIM_SEED_LENGTH 16
45 /*
46  * preauth node timeout value in interval of 10msec
47  */
48 #define LIM_OPENAUTH_TIMEOUT 500
49 
50 /**
51  * lim_is_auth_algo_supported()
52  *
53  ***FUNCTION:
54  * This function is called in various places within LIM code
55  * to determine whether passed authentication algorithm is enabled
56  * or not
57  *
58  ***LOGIC:
59  *
60  ***ASSUMPTIONS:
61  * NA
62  *
63  ***NOTE:
64  * NA
65  *
66  * @param authType Indicates MAC based authentication type
67  *                 (eSIR_OPEN_SYSTEM or eSIR_SHARED_KEY)
68  *                 If Shared Key authentication to be used,
69  *                 'Privacy Option Implemented' flag is also
70  *                 checked.
71  *
72  * @return true if passed authType is enabled else false
73  */
74 uint8_t
lim_is_auth_algo_supported(struct mac_context * mac,tAniAuthType authType,struct pe_session * pe_session)75 lim_is_auth_algo_supported(struct mac_context *mac, tAniAuthType authType,
76 			   struct pe_session *pe_session)
77 {
78 	bool algoEnable, privacyOptImp;
79 	struct wlan_mlme_wep_cfg *wep_params = &mac->mlme_cfg->wep_params;
80 
81 	if (authType == eSIR_OPEN_SYSTEM) {
82 
83 		if (LIM_IS_AP_ROLE(pe_session)) {
84 			if ((pe_session->authType == eSIR_OPEN_SYSTEM)
85 			    || (pe_session->authType == eSIR_AUTO_SWITCH))
86 				return true;
87 			else
88 				return false;
89 		}
90 
91 		algoEnable = wep_params->is_auth_open_system;
92 		return algoEnable > 0 ? true : false;
93 
94 	} else {
95 
96 		if (LIM_IS_AP_ROLE(pe_session)) {
97 			if ((pe_session->authType == eSIR_SHARED_KEY)
98 			    || (pe_session->authType == eSIR_AUTO_SWITCH))
99 				algoEnable = true;
100 			else
101 				algoEnable = false;
102 
103 		} else {
104 			algoEnable = wep_params->is_shared_key_auth;
105 		}
106 
107 		if (LIM_IS_AP_ROLE(pe_session))
108 			privacyOptImp = pe_session->privacy;
109 		else
110 			privacyOptImp = wep_params->is_privacy_enabled;
111 
112 		return algoEnable && privacyOptImp;
113 	}
114 } /****** end lim_is_auth_algo_supported() ******/
115 
116 /**
117  * lim_init_pre_auth_list
118  *
119  ***FUNCTION:
120  * This function is called while starting a BSS at AP
121  * to initialize MAC authenticated STA list. This may also be called
122  * while joining/starting an IBSS if MAC authentication is allowed
123  * in IBSS mode.
124  *
125  ***LOGIC:
126  *
127  ***ASSUMPTIONS:
128  *
129  ***NOTE:
130  *
131  * @param  mac - Pointer to Global MAC structure
132  * @return None
133  */
134 
lim_init_pre_auth_list(struct mac_context * mac)135 void lim_init_pre_auth_list(struct mac_context *mac)
136 {
137 	mac->lim.pLimPreAuthList = NULL;
138 
139 } /*** end lim_init_pre_auth_list() ***/
140 
141 /**
142  * lim_delete_pre_auth_list
143  *
144  ***FUNCTION:
145  * This function is called cleanup Pre-auth list either on
146  * AP or on STA when moving from one persona to other.
147  *
148  ***LOGIC:
149  *
150  ***ASSUMPTIONS:
151  *
152  ***NOTE:
153  *
154  * @param  mac - Pointer to Global MAC structure
155  * @return None
156  */
157 
lim_delete_pre_auth_list(struct mac_context * mac)158 void lim_delete_pre_auth_list(struct mac_context *mac)
159 {
160 	struct tLimPreAuthNode *pCurrNode, *pTempNode;
161 
162 	pCurrNode = pTempNode = mac->lim.pLimPreAuthList;
163 	while (pCurrNode) {
164 		pTempNode = pCurrNode->next;
165 		lim_release_pre_auth_node(mac, pCurrNode);
166 
167 		pCurrNode = pTempNode;
168 	}
169 	mac->lim.pLimPreAuthList = NULL;
170 } /*** end lim_delete_pre_auth_list() ***/
171 
172 /**
173  * lim_search_pre_auth_list
174  *
175  ***FUNCTION:
176  * This function is called when Authentication frame is received
177  * by AP (or at a STA in IBSS supporting MAC based authentication)
178  * to search if a STA is in the middle of MAC Authentication
179  * transaction sequence.
180  *
181  ***LOGIC:
182  *
183  ***ASSUMPTIONS:
184  *
185  ***NOTE:
186  *
187  * @param  macAddr - MAC address of the STA that sent
188  *                       Authentication frame.
189  *
190  * @return Pointer to pre-auth node if found, else NULL
191  */
192 
lim_search_pre_auth_list(struct mac_context * mac,tSirMacAddr macAddr)193 struct tLimPreAuthNode *lim_search_pre_auth_list(struct mac_context *mac,
194 						 tSirMacAddr macAddr)
195 {
196 	struct tLimPreAuthNode *pTempNode = mac->lim.pLimPreAuthList;
197 
198 	while (pTempNode) {
199 		if (!qdf_mem_cmp((uint8_t *) macAddr,
200 				    (uint8_t *) &pTempNode->peerMacAddr,
201 				    sizeof(tSirMacAddr)))
202 			break;
203 
204 		pTempNode = pTempNode->next;
205 	}
206 
207 	return pTempNode;
208 } /*** end lim_search_pre_auth_list() ***/
209 
210 #ifdef WLAN_FEATURE_11BE_MLO
211 struct tLimPreAuthNode *
lim_search_pre_auth_list_by_mld_addr(struct mac_context * mac,tSirMacAddr mldaddr)212 lim_search_pre_auth_list_by_mld_addr(struct mac_context *mac,
213 				     tSirMacAddr mldaddr)
214 {
215 	struct tLimPreAuthNode *pTempNode = mac->lim.pLimPreAuthList;
216 
217 	while (pTempNode) {
218 		if (!qdf_mem_cmp((uint8_t *)mldaddr,
219 				 (uint8_t *)&pTempNode->peer_mld,
220 				 sizeof(tSirMacAddr)))
221 			break;
222 
223 		pTempNode = pTempNode->next;
224 	}
225 
226 	return pTempNode;
227 }
228 #endif
229 
230 /**
231  * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes
232  * @mac_ctx: Pointer to Global MAC structure
233  *
234  * This function is called to delete any stale preauth nodes on
235  * receiving authentication frame and existing preauth nodes
236  * reached the maximum allowed limit.
237  *
238  * Return: return true if any preauthnode deleted else false
239  */
240 uint8_t
lim_delete_open_auth_pre_auth_node(struct mac_context * mac_ctx)241 lim_delete_open_auth_pre_auth_node(struct mac_context *mac_ctx)
242 {
243 	struct tLimPreAuthNode    *prev_node, *temp_node, *found_node;
244 	uint8_t auth_node_freed = false;
245 
246 	temp_node = prev_node = mac_ctx->lim.pLimPreAuthList;
247 
248 	if (!temp_node)
249 		return auth_node_freed;
250 
251 	while (temp_node) {
252 		if (temp_node->mlmState == eLIM_MLM_AUTHENTICATED_STATE &&
253 		    temp_node->authType == eSIR_OPEN_SYSTEM &&
254 		    (qdf_mc_timer_get_system_ticks() >
255 		    (LIM_OPENAUTH_TIMEOUT + temp_node->timestamp) ||
256 		    qdf_mc_timer_get_system_ticks() < temp_node->timestamp)) {
257 			/* Found node to be deleted */
258 			auth_node_freed = true;
259 			found_node = temp_node;
260 			if (mac_ctx->lim.pLimPreAuthList == temp_node) {
261 				prev_node = mac_ctx->lim.pLimPreAuthList =
262 					temp_node = found_node->next;
263 			} else {
264 				prev_node->next = temp_node->next;
265 				temp_node = prev_node->next;
266 			}
267 
268 			lim_release_pre_auth_node(mac_ctx, found_node);
269 		} else {
270 			prev_node = temp_node;
271 			temp_node = prev_node->next;
272 		}
273 	}
274 
275 	return auth_node_freed;
276 }
277 
278 /**
279  * lim_add_pre_auth_node
280  *
281  ***FUNCTION:
282  * This function is called at AP while sending Authentication
283  * frame2.
284  * This may also be called on a STA in IBSS if MAC authentication is
285  * allowed in IBSS mode.
286  *
287  ***LOGIC:
288  * Node is always added to the front of the list
289  *
290  ***ASSUMPTIONS:
291  *
292  ***NOTE:
293  *
294  * @param  mac - Pointer to Global MAC structure
295  * @param  pAuthNode - Pointer to pre-auth node to be added to the list.
296  *
297  * @return None
298  */
299 
lim_add_pre_auth_node(struct mac_context * mac,struct tLimPreAuthNode * pAuthNode)300 void lim_add_pre_auth_node(struct mac_context *mac, struct tLimPreAuthNode *pAuthNode)
301 {
302 	mac->lim.gLimNumPreAuthContexts++;
303 
304 	pAuthNode->next = mac->lim.pLimPreAuthList;
305 
306 	mac->lim.pLimPreAuthList = pAuthNode;
307 } /*** end lim_add_pre_auth_node() ***/
308 
309 /**
310  * lim_release_pre_auth_node
311  *
312  ***FUNCTION:
313  * This function is called to release the acquired
314  * pre auth node from list.
315  *
316  ***LOGIC:
317  *
318  ***ASSUMPTIONS:
319  *
320  ***NOTE:
321  *
322  * @param  mac - Pointer to Global MAC structure
323  * @param  pAuthNode - Pointer to Pre Auth node to be released
324  * @return None
325  */
326 
lim_release_pre_auth_node(struct mac_context * mac,tpLimPreAuthNode pAuthNode)327 void lim_release_pre_auth_node(struct mac_context *mac,
328 			       tpLimPreAuthNode pAuthNode)
329 {
330 	pAuthNode->fFree = 1;
331 	if (pAuthNode->authType == eSIR_AUTH_TYPE_SAE &&
332 	    pAuthNode->assoc_req.present) {
333 		tpSirAssocReq assoc =
334 			 (tpSirAssocReq)pAuthNode->assoc_req.assoc_req;
335 
336 		lim_free_assoc_req_frm_buf(assoc);
337 		qdf_mem_free(assoc);
338 		pAuthNode->assoc_req.assoc_req = NULL;
339 		pAuthNode->assoc_req.present = false;
340 	}
341 	MTRACE(mac_trace
342 		       (mac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION,
343 		       eLIM_PRE_AUTH_CLEANUP_TIMER));
344 	tx_timer_deactivate(&pAuthNode->timer);
345 	mac->lim.gLimNumPreAuthContexts--;
346 } /*** end lim_release_pre_auth_node() ***/
347 
348 /**
349  * lim_delete_pre_auth_node
350  *
351  ***FUNCTION:
352  * This function is called at AP when a pre-authenticated STA is
353  * Associated/Reassociated or when AuthFrame4 is received after
354  * Auth Response timeout.
355  * This may also be called on a STA in IBSS if MAC authentication and
356  * Association/Reassociation is allowed in IBSS mode.
357  *
358  ***LOGIC:
359  *
360  ***ASSUMPTIONS:
361  *
362  ***NOTE:
363  *
364  * @param  mac - Pointer to Global MAC structure
365  * @param  peerMacAddr - MAC address of the STA that need to be deleted
366  *                       from pre-auth node list.
367  *
368  * @return None
369  */
370 
lim_delete_pre_auth_node(struct mac_context * mac,tSirMacAddr macAddr)371 void lim_delete_pre_auth_node(struct mac_context *mac, tSirMacAddr macAddr)
372 {
373 	struct tLimPreAuthNode *pPrevNode, *pTempNode;
374 
375 	pTempNode = pPrevNode = mac->lim.pLimPreAuthList;
376 
377 	if (!pTempNode)
378 		return;
379 
380 	if (!qdf_mem_cmp((uint8_t *) macAddr,
381 			    (uint8_t *) &pTempNode->peerMacAddr,
382 			    sizeof(tSirMacAddr))) {
383 		/* First node to be deleted */
384 
385 		mac->lim.pLimPreAuthList = pTempNode->next;
386 
387 		pe_debug("fRelease data for %d peer "QDF_MAC_ADDR_FMT,
388 			 pTempNode->authNodeIdx,
389 			 QDF_MAC_ADDR_REF(macAddr));
390 		lim_release_pre_auth_node(mac, pTempNode);
391 
392 		return;
393 	}
394 
395 	pTempNode = pTempNode->next;
396 
397 	while (pTempNode) {
398 		if (!qdf_mem_cmp((uint8_t *) macAddr,
399 				    (uint8_t *) &pTempNode->peerMacAddr,
400 				    sizeof(tSirMacAddr))) {
401 			/* Found node to be deleted */
402 
403 			pPrevNode->next = pTempNode->next;
404 
405 			pe_debug("subsequent node to delete, Release data entry: %pK id %d peer "QDF_MAC_ADDR_FMT,
406 				 pTempNode, pTempNode->authNodeIdx,
407 				 QDF_MAC_ADDR_REF(macAddr));
408 			lim_release_pre_auth_node(mac, pTempNode);
409 
410 			return;
411 		}
412 
413 		pPrevNode = pTempNode;
414 		pTempNode = pTempNode->next;
415 	}
416 
417 	pe_err("peer not found in pre-auth list, addr= "QDF_MAC_ADDR_FMT,
418 	       QDF_MAC_ADDR_REF(macAddr));
419 
420 } /*** end lim_delete_pre_auth_node() ***/
421 
422 /**
423  * limRestoreFromPreAuthState
424  *
425  ***FUNCTION:
426  * This function is called on STA whenever an Authentication
427  * sequence is complete and state prior to auth need to be
428  * restored.
429  *
430  ***LOGIC:
431  * MLM_AUTH_CNF is prepared and sent to SME state machine.
432  * In case of restoring from pre-auth:
433  *     - Channel Id is programmed at LO/RF synthesizer
434  *     - BSSID is programmed at RHP
435  *
436  ***ASSUMPTIONS:
437  *
438  ***NOTE:
439  *
440  * @param  mac       - Pointer to Global MAC structure
441  * @param  resultCode - result of authentication attempt
442  * @return None
443  */
444 
445 void
lim_restore_from_auth_state(struct mac_context * mac,tSirResultCodes resultCode,uint16_t protStatusCode,struct pe_session * pe_session)446 lim_restore_from_auth_state(struct mac_context *mac, tSirResultCodes resultCode,
447 			    uint16_t protStatusCode, struct pe_session *pe_session)
448 {
449 	tSirMacAddr currentBssId;
450 	tLimMlmAuthCnf mlmAuthCnf;
451 
452 #ifdef FEATURE_WLAN_DIAG_SUPPORT
453 	lim_diag_event_report(mac, WLAN_PE_DIAG_AUTH_COMP_EVENT, pe_session,
454 			      resultCode, protStatusCode);
455 #endif
456 
457 	qdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr,
458 		     (uint8_t *) &mac->lim.gpLimMlmAuthReq->peerMacAddr,
459 		     sizeof(tSirMacAddr));
460 	mlmAuthCnf.authType = mac->lim.gpLimMlmAuthReq->authType;
461 	mlmAuthCnf.resultCode = resultCode;
462 	mlmAuthCnf.protStatusCode = protStatusCode;
463 
464 	/* Update PE session ID */
465 	mlmAuthCnf.sessionId = pe_session->peSessionId;
466 
467 	/* / Free up buffer allocated */
468 	/* / for mac->lim.gLimMlmAuthReq */
469 	qdf_mem_free(mac->lim.gpLimMlmAuthReq);
470 	mac->lim.gpLimMlmAuthReq = NULL;
471 
472 	pe_session->limMlmState = pe_session->limPrevMlmState;
473 
474 	MTRACE(mac_trace
475 		       (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId,
476 		       pe_session->limMlmState));
477 
478 	/*
479 	 * Set the auth_ack_status status flag as success as
480 	 * host have received the auth rsp and no longer auth
481 	 * retry is needed also cancel the auth rety timer
482 	 */
483 	mac->auth_ack_status = LIM_ACK_RCD_SUCCESS;
484 
485 	/* Auth retry and AUth failure timers are not started for SAE */
486 	/* 'Change' timer for future activations */
487 	if (tx_timer_running(&mac->lim.lim_timers.
488 	    g_lim_periodic_auth_retry_timer))
489 		lim_deactivate_and_change_timer(mac,
490 				eLIM_AUTH_RETRY_TIMER);
491 	/* 'Change' timer for future activations */
492 	if (tx_timer_running(&mac->lim.lim_timers.gLimAuthFailureTimer))
493 		lim_deactivate_and_change_timer(mac,
494 				eLIM_AUTH_FAIL_TIMER);
495 
496 	sir_copy_mac_addr(currentBssId, pe_session->bssId);
497 
498 	if (pe_session->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) {
499 		mac->lim.gLimPreAuthChannelNumber = 0;
500 	}
501 
502 	lim_post_sme_message(mac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf);
503 } /*** end lim_restore_from_auth_state() ***/
504 
505 /**
506  * lim_encrypt_auth_frame()
507  *
508  ***FUNCTION:
509  * This function is called in lim_process_auth_frame() function
510  * to encrypt Authentication frame3 body.
511  *
512  ***LOGIC:
513  *
514  ***ASSUMPTIONS:
515  * NA
516  *
517  ***NOTE:
518  * NA
519  *
520  * @param  mac           Pointer to Global MAC structure
521  * @param  keyId          key id to used
522  * @param  pKey           Pointer to the key to be used for encryption
523  * @param  pPlainText     Pointer to the body to be encrypted
524  * @param  pEncrBody      Pointer to the encrypted auth frame body
525  * @param  keyLength      8 (WEP40) or 16 (WEP104)
526  * @return None
527  */
528 
529 void
lim_encrypt_auth_frame(struct mac_context * mac,uint8_t keyId,uint8_t * pKey,uint8_t * pPlainText,uint8_t * pEncrBody,uint32_t keyLength)530 lim_encrypt_auth_frame(struct mac_context *mac, uint8_t keyId, uint8_t *pKey,
531 		       uint8_t *pPlainText, uint8_t *pEncrBody,
532 		       uint32_t keyLength)
533 {
534 	uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH];
535 	uint16_t frame_len;
536 
537 	frame_len = ((tpSirMacAuthFrameBody)pPlainText)->length +
538 			SIR_MAC_AUTH_FRAME_INFO_LEN + SIR_MAC_CHALLENGE_ID_LEN;
539 	keyLength += 3;
540 
541 	/*
542 	 * Make sure that IV is non-zero, because few IOT APs fails to decrypt
543 	 * auth sequence 3 encrypted frames if initialization vector value is 0
544 	 */
545 	qdf_get_random_bytes(seed, SIR_MAC_WEP_IV_LENGTH);
546 	while (!(*(uint32_t *)seed))
547 		qdf_get_random_bytes(seed, SIR_MAC_WEP_IV_LENGTH);
548 
549 	/* Bytes 3-7 of seed is key */
550 	qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3);
551 
552 	/* Compute CRC-32 and place them in last 4 bytes of plain text */
553 	lim_compute_crc32(icv, pPlainText, frame_len);
554 
555 	qdf_mem_copy(pPlainText + frame_len,
556 		     icv, SIR_MAC_WEP_ICV_LENGTH);
557 
558 	/* Run RC4 on plain text with the seed */
559 	lim_rc4(pEncrBody + SIR_MAC_WEP_IV_LENGTH,
560 		(uint8_t *) pPlainText, seed, keyLength,
561 		frame_len + SIR_MAC_WEP_ICV_LENGTH);
562 
563 	/* Prepare IV */
564 	pEncrBody[0] = seed[0];
565 	pEncrBody[1] = seed[1];
566 	pEncrBody[2] = seed[2];
567 	pEncrBody[3] = keyId << 6;
568 } /****** end lim_encrypt_auth_frame() ******/
569 
570 /**
571  * lim_compute_crc32()
572  *
573  ***FUNCTION:
574  * This function is called to compute CRC-32 on a given source.
575  * Used while encrypting/decrypting Authentication frame 3.
576  *
577  ***LOGIC:
578  *
579  ***ASSUMPTIONS:
580  * NA
581  *
582  ***NOTE:
583  * NA
584  *
585  * @param  pDest    Destination location for computed CRC
586  * @param  pSrc     Source location to be CRC computed
587  * @param  len      Length over which CRC to be computed
588  * @return None
589  */
590 
lim_compute_crc32(uint8_t * pDest,uint8_t * pSrc,uint16_t len)591 void lim_compute_crc32(uint8_t *pDest, uint8_t *pSrc, uint16_t len)
592 {
593 	uint32_t crc;
594 	int i;
595 
596 	crc = 0;
597 	crc = ~crc;
598 
599 	while (len-- > 0)
600 		crc = lim_crc_update(crc, *pSrc++);
601 
602 	crc = ~crc;
603 
604 	for (i = 0; i < SIR_MAC_WEP_IV_LENGTH; i++) {
605 		pDest[i] = (uint8_t) crc;
606 		crc >>= 8;
607 	}
608 } /****** end lim_compute_crc32() ******/
609 
610 /**
611  * lim_rc4()
612  *
613  ***FUNCTION:
614  * This function is called to run RC4 algorithm. Called while
615  * encrypting/decrypting Authentication frame 3.
616  *
617  ***LOGIC:
618  *
619  ***ASSUMPTIONS:
620  * NA
621  *
622  ***NOTE:
623  * NA
624  *
625  * @param  pDest          Destination location for encrypted text
626  * @param  pSrc           Source location to be encrypted
627  * @param  seed           Contains seed (IV + key) for PRNG
628  * @param  keyLength      8 (WEP40) or 16 (WEP104)
629  * @param  frameLen       Length of the frame
630  *
631  * @return None
632  */
633 
634 void
lim_rc4(uint8_t * pDest,uint8_t * pSrc,uint8_t * seed,uint32_t keyLength,uint16_t frameLen)635 lim_rc4(uint8_t *pDest, uint8_t *pSrc, uint8_t *seed, uint32_t keyLength,
636 	uint16_t frameLen)
637 {
638 	typedef struct {
639 		uint8_t i, j;
640 		uint8_t sbox[256];
641 	} tRC4Context;
642 
643 	tRC4Context ctx;
644 
645 	{
646 		uint16_t i, j, k;
647 
648 		/* */
649 		/* Initialize sbox using seed */
650 		/* */
651 
652 		ctx.i = ctx.j = 0;
653 		for (i = 0; i < 256; i++)
654 			ctx.sbox[i] = (uint8_t) i;
655 
656 		j = 0;
657 		k = 0;
658 		for (i = 0; i < 256; i++) {
659 			uint8_t temp;
660 
661 			if (k < LIM_SEED_LENGTH)
662 				j = (uint8_t) (j + ctx.sbox[i] + seed[k]);
663 			temp = ctx.sbox[i];
664 			ctx.sbox[i] = ctx.sbox[j];
665 			ctx.sbox[j] = temp;
666 
667 			if (++k >= keyLength)
668 				k = 0;
669 		}
670 	}
671 
672 	{
673 		uint8_t i = ctx.i;
674 		uint8_t j = ctx.j;
675 		uint16_t len = frameLen;
676 
677 		while (len-- > 0) {
678 			uint8_t temp1, temp2;
679 
680 			i = (uint8_t) (i + 1);
681 			temp1 = ctx.sbox[i];
682 			j = (uint8_t) (j + temp1);
683 
684 			ctx.sbox[i] = temp2 = ctx.sbox[j];
685 			ctx.sbox[j] = temp1;
686 
687 			temp1 = (uint8_t) (temp1 + temp2);
688 			temp1 = ctx.sbox[temp1];
689 			temp2 = (uint8_t) (pSrc ? *pSrc++ : 0);
690 
691 			*pDest++ = (uint8_t) (temp1 ^ temp2);
692 		}
693 
694 		ctx.i = i;
695 		ctx.j = j;
696 	}
697 } /****** end lim_rc4() ******/
698 
699 /**
700  * lim_decrypt_auth_frame()
701  *
702  ***FUNCTION:
703  * This function is called in lim_process_auth_frame() function
704  * to decrypt received Authentication frame3 body.
705  *
706  ***LOGIC:
707  *
708  ***ASSUMPTIONS:
709  * NA
710  *
711  ***NOTE:
712  * NA
713  *
714  * @param mac       Pointer to Global MAC structure
715  * @param pKey       Pointer to the key to be used for decryption
716  * @param pEncrBody  Pointer to the body to be decrypted
717  * @param pPlainBody Pointer to the decrypted body
718  * @param keyLength  8 (WEP40) or 16 (WEP104)
719  *
720  * @return Decrypt result - QDF_STATUS_SUCCESS for success and
721  *                          LIM_DECRYPT_ICV_FAIL for ICV mismatch.
722  *                          If decryption is a success, pBody will
723  *                          have decrypted auth frame body.
724  */
725 
726 uint8_t
lim_decrypt_auth_frame(struct mac_context * mac,uint8_t * pKey,uint8_t * pEncrBody,uint8_t * pPlainBody,uint32_t keyLength,uint16_t frameLen)727 lim_decrypt_auth_frame(struct mac_context *mac, uint8_t *pKey, uint8_t *pEncrBody,
728 		       uint8_t *pPlainBody, uint32_t keyLength, uint16_t frameLen)
729 {
730 	uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH];
731 	int i;
732 
733 	keyLength += 3;
734 
735 	/* Bytes 0-2 of seed is received IV */
736 	qdf_mem_copy((uint8_t *) seed, pEncrBody, SIR_MAC_WEP_IV_LENGTH - 1);
737 
738 	/* Bytes 3-7 of seed is key */
739 	qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3);
740 
741 	/* Run RC4 on encrypted text with the seed */
742 	lim_rc4(pPlainBody,
743 		pEncrBody + SIR_MAC_WEP_IV_LENGTH, seed, keyLength, frameLen);
744 
745 	/* Compute CRC-32 and place them in last 4 bytes of encrypted body */
746 	lim_compute_crc32(icv,
747 			  (uint8_t *) pPlainBody,
748 			  (frameLen - SIR_MAC_WEP_ICV_LENGTH));
749 
750 	/* Compare RX_ICV with computed ICV */
751 	for (i = 0; i < SIR_MAC_WEP_ICV_LENGTH; i++) {
752 		pe_debug("computed ICV%d[%x], rxed ICV%d[%x]",
753 			i, icv[i], i,
754 			pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]);
755 
756 		if (icv[i] !=
757 		    pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i])
758 			return LIM_DECRYPT_ICV_FAIL;
759 	}
760 
761 	return QDF_STATUS_SUCCESS;
762 } /****** end lim_decrypt_auth_frame() ******/
763