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