PageRenderTime 66ms CodeModel.GetById 38ms app.highlight 22ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/rtl8712/rtl871x_recv.c

https://bitbucket.org/wisechild/galaxy-nexus
C | 695 lines | 565 code | 52 blank | 78 comment | 130 complexity | f51ac214806abdcf5ecb53f87b88f7a2 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/******************************************************************************
  2 * rtl871x_recv.c
  3 *
  4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
  5 * Linux device driver for RTL8192SU
  6 *
  7 * This program is free software; you can redistribute it and/or modify it
  8 * under the terms of version 2 of the GNU General Public License as
  9 * published by the Free Software Foundation.
 10 *
 11 * This program is distributed in the hope that it will be useful, but WITHOUT
 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 14 * more details.
 15 *
 16 * You should have received a copy of the GNU General Public License along with
 17 * this program; if not, write to the Free Software Foundation, Inc.,
 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 19 *
 20 * Modifications for inclusion into the Linux staging tree are
 21 * Copyright(c) 2010 Larry Finger. All rights reserved.
 22 *
 23 * Contact information:
 24 * WLAN FAE <wlanfae@realtek.com>
 25 * Larry Finger <Larry.Finger@lwfinger.net>
 26 *
 27 ******************************************************************************/
 28
 29#define _RTL871X_RECV_C_
 30
 31#include "osdep_service.h"
 32#include "drv_types.h"
 33#include "recv_osdep.h"
 34#include "mlme_osdep.h"
 35#include "ip.h"
 36#include "if_ether.h"
 37#include "ethernet.h"
 38#include "usb_ops.h"
 39#include "wifi.h"
 40
 41static const u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
 42
 43/* Datagram Delivery Protocol */
 44static const u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
 45
 46/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
 47static const u8 bridge_tunnel_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8};
 48
 49/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
 50static const u8 rfc1042_header[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 51
 52void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
 53{
 54	memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv));
 55	spin_lock_init(&psta_recvpriv->lock);
 56	_init_queue(&psta_recvpriv->defrag_q);
 57}
 58
 59sint _r8712_init_recv_priv(struct recv_priv *precvpriv,
 60			   struct _adapter *padapter)
 61{
 62	sint i;
 63	union recv_frame *precvframe;
 64
 65	 memset((unsigned char *)precvpriv, 0, sizeof(struct  recv_priv));
 66	spin_lock_init(&precvpriv->lock);
 67	_init_queue(&precvpriv->free_recv_queue);
 68	_init_queue(&precvpriv->recv_pending_queue);
 69	precvpriv->adapter = padapter;
 70	precvpriv->free_recvframe_cnt = NR_RECVFRAME;
 71	precvpriv->pallocated_frame_buf = _malloc(NR_RECVFRAME *
 72					   sizeof(union recv_frame) +
 73					   RXFRAME_ALIGN_SZ);
 74	if (precvpriv->pallocated_frame_buf == NULL)
 75		return _FAIL;
 76	memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME *
 77		sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
 78	precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf +
 79				    RXFRAME_ALIGN_SZ -
 80				    ((addr_t)(precvpriv->pallocated_frame_buf) &
 81				    (RXFRAME_ALIGN_SZ-1));
 82	precvframe = (union recv_frame *)precvpriv->precv_frame_buf;
 83	for (i = 0; i < NR_RECVFRAME; i++) {
 84		_init_listhead(&(precvframe->u.list));
 85		list_insert_tail(&(precvframe->u.list),
 86				 &(precvpriv->free_recv_queue.queue));
 87		r8712_os_recv_resource_alloc(padapter, precvframe);
 88		precvframe->u.hdr.adapter = padapter;
 89		precvframe++;
 90	}
 91	precvpriv->rx_pending_cnt = 1;
 92	sema_init(&precvpriv->allrxreturnevt, 0);
 93	return r8712_init_recv_priv(precvpriv, padapter);
 94}
 95
 96void _r8712_free_recv_priv(struct recv_priv *precvpriv)
 97{
 98	kfree(precvpriv->pallocated_frame_buf);
 99	r8712_free_recv_priv(precvpriv);
100}
101
102union recv_frame *r8712_alloc_recvframe(struct  __queue *pfree_recv_queue)
103{
104	unsigned long irqL;
105	union recv_frame  *precvframe;
106	struct list_head *plist, *phead;
107	struct _adapter *padapter;
108	struct recv_priv *precvpriv;
109
110	spin_lock_irqsave(&pfree_recv_queue->lock, irqL);
111	if (_queue_empty(pfree_recv_queue) == true)
112		precvframe = NULL;
113	else {
114		phead = get_list_head(pfree_recv_queue);
115		plist = get_next(phead);
116		precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
117		list_delete(&precvframe->u.hdr.list);
118		padapter = precvframe->u.hdr.adapter;
119		if (padapter != NULL) {
120			precvpriv = &padapter->recvpriv;
121			if (pfree_recv_queue == &precvpriv->free_recv_queue)
122				precvpriv->free_recvframe_cnt--;
123		}
124	}
125	spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL);
126	return precvframe;
127}
128
129/*
130caller : defrag; recvframe_chk_defrag in recv_thread  (passive)
131pframequeue: defrag_queue : will be accessed in recv_thread  (passive)
132
133using spin_lock to protect
134
135*/
136
137void r8712_free_recvframe_queue(struct  __queue *pframequeue,
138				struct  __queue *pfree_recv_queue)
139{
140	union	recv_frame *precvframe;
141	struct list_head *plist, *phead;
142
143	spin_lock(&pframequeue->lock);
144	phead = get_list_head(pframequeue);
145	plist = get_next(phead);
146	while (end_of_queue_search(phead, plist) == false) {
147		precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
148		plist = get_next(plist);
149		r8712_free_recvframe(precvframe, pfree_recv_queue);
150	}
151	spin_unlock(&pframequeue->lock);
152}
153
154sint r8712_recvframe_chkmic(struct _adapter *adapter,
155			    union recv_frame *precvframe)
156{
157	sint i, res = _SUCCESS;
158	u32	datalen;
159	u8 miccode[8];
160	u8 bmic_err = false;
161	u8 *pframe, *payload, *pframemic;
162	u8   *mickey, idx, *iv;
163	struct	sta_info *stainfo;
164	struct	rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib;
165	struct	security_priv *psecuritypriv = &adapter->securitypriv;
166
167	stainfo = r8712_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
168	if (prxattrib->encrypt == _TKIP_) {
169		/* calculate mic code */
170		if (stainfo != NULL) {
171			if (IS_MCAST(prxattrib->ra)) {
172				iv = precvframe->u.hdr.rx_data +
173				     prxattrib->hdrlen;
174				idx = iv[3];
175				mickey = &psecuritypriv->XGrprxmickey[(((idx >>
176					 6) & 0x3)) - 1].skey[0];
177				if (psecuritypriv->binstallGrpkey == false)
178					return _FAIL;
179			} else
180				mickey = &stainfo->tkiprxmickey.skey[0];
181			/*icv_len included the mic code*/
182			datalen = precvframe->u.hdr.len - prxattrib->hdrlen -
183				  prxattrib->iv_len - prxattrib->icv_len - 8;
184			pframe = precvframe->u.hdr.rx_data;
185			payload = pframe + prxattrib->hdrlen +
186				  prxattrib->iv_len;
187			seccalctkipmic(mickey, pframe, payload, datalen,
188				       &miccode[0],
189				       (unsigned char)prxattrib->priority);
190			pframemic = payload + datalen;
191			bmic_err = false;
192			for (i = 0; i < 8; i++) {
193				if (miccode[i] != *(pframemic + i))
194					bmic_err = true;
195			}
196			if (bmic_err == true) {
197				if (prxattrib->bdecrypted == true)
198					r8712_handle_tkip_mic_err(adapter,
199						(u8)IS_MCAST(prxattrib->ra));
200				res = _FAIL;
201			} else {
202				/* mic checked ok */
203				if ((psecuritypriv->bcheck_grpkey ==
204				     false) && (IS_MCAST(prxattrib->ra) ==
205				     true))
206					psecuritypriv->bcheck_grpkey = true;
207			}
208			recvframe_pull_tail(precvframe, 8);
209		}
210	}
211	return res;
212}
213
214/* decrypt and set the ivlen,icvlen of the recv_frame */
215union recv_frame *r8712_decryptor(struct _adapter *padapter,
216			    union recv_frame *precv_frame)
217{
218	struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
219	struct security_priv *psecuritypriv = &padapter->securitypriv;
220	union recv_frame *return_packet = precv_frame;
221
222	if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) ||
223	   (psecuritypriv->sw_decrypt == true))) {
224		psecuritypriv->hw_decrypted = false;
225		switch (prxattrib->encrypt) {
226		case _WEP40_:
227		case _WEP104_:
228			r8712_wep_decrypt(padapter, (u8 *)precv_frame);
229			break;
230		case _TKIP_:
231			r8712_tkip_decrypt(padapter, (u8 *)precv_frame);
232			break;
233		case _AES_:
234			r8712_aes_decrypt(padapter, (u8 *)precv_frame);
235			break;
236		default:
237				break;
238		}
239	} else if (prxattrib->bdecrypted == 1)
240		psecuritypriv->hw_decrypted = true;
241	return return_packet;
242}
243/*###set the security information in the recv_frame */
244union recv_frame *r8712_portctrl(struct _adapter *adapter,
245				 union recv_frame *precv_frame)
246{
247	u8 *psta_addr, *ptr;
248	uint auth_alg;
249	struct recv_frame_hdr *pfhdr;
250	struct sta_info *psta;
251	struct	sta_priv *pstapriv;
252	union recv_frame *prtnframe;
253	u16 ether_type = 0;
254
255	pstapriv = &adapter->stapriv;
256	ptr = get_recvframe_data(precv_frame);
257	pfhdr = &precv_frame->u.hdr;
258	psta_addr = pfhdr->attrib.ta;
259	psta = r8712_get_stainfo(pstapriv, psta_addr);
260	auth_alg = adapter->securitypriv.AuthAlgrthm;
261	if (auth_alg == 2) {
262		if ((psta != NULL) && (psta->ieee8021x_blocked)) {
263			/* blocked
264			 * only accept EAPOL frame */
265			prtnframe = precv_frame;
266			/*get ether_type */
267			ptr = ptr + pfhdr->attrib.hdrlen +
268			      pfhdr->attrib.iv_len + LLC_HEADER_SIZE;
269			memcpy(&ether_type, ptr, 2);
270			ether_type = ntohs((unsigned short)ether_type);
271			if (ether_type == 0x888e)
272				prtnframe = precv_frame;
273			else {
274				/*free this frame*/
275				r8712_free_recvframe(precv_frame,
276					 &adapter->recvpriv.free_recv_queue);
277				prtnframe = NULL;
278			}
279		} else {
280			/* allowed
281			 * check decryption status, and decrypt the
282			 * frame if needed */
283			prtnframe = precv_frame;
284			/* check is the EAPOL frame or not (Rekey) */
285			if (ether_type == 0x888e) {
286				/* check Rekey */
287				prtnframe = precv_frame;
288			}
289		}
290	} else
291		prtnframe = precv_frame;
292	return prtnframe;
293}
294
295static sint recv_decache(union recv_frame *precv_frame, u8 bretry,
296		  struct stainfo_rxcache *prxcache)
297{
298	sint tid = precv_frame->u.hdr.attrib.priority;
299	u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
300			(precv_frame->u.hdr.attrib.frag_num & 0xf);
301
302	if (tid > 15)
303		return _FAIL;
304	if (seq_ctrl == prxcache->tid_rxseq[tid])
305		return _FAIL;
306	prxcache->tid_rxseq[tid] = seq_ctrl;
307	return _SUCCESS;
308}
309
310static sint sta2sta_data_frame(struct _adapter *adapter,
311			       union recv_frame *precv_frame,
312			       struct sta_info **psta)
313{
314	u8 *ptr = precv_frame->u.hdr.rx_data;
315	sint ret = _SUCCESS;
316	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
317	struct	sta_priv *pstapriv = &adapter->stapriv;
318	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
319	u8 *mybssid  = get_bssid(pmlmepriv);
320	u8 *myhwaddr = myid(&adapter->eeprompriv);
321	u8 *sta_addr = NULL;
322	sint bmcast = IS_MCAST(pattrib->dst);
323
324	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
325	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
326		/* filter packets that SA is myself or multicast or broadcast */
327		if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN))
328			return _FAIL;
329		if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
330			return _FAIL;
331		if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
332		    !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
333		    (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
334			return _FAIL;
335		sta_addr = pattrib->src;
336	} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
337		/* For Station mode, sa and bssid should always be BSSID,
338		 * and DA is my mac-address */
339		if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN))
340			return _FAIL;
341	       sta_addr = pattrib->bssid;
342	 } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
343		if (bmcast) {
344			/* For AP mode, if DA == MCAST, then BSSID should
345			 * be also MCAST */
346			if (!IS_MCAST(pattrib->bssid))
347				return _FAIL;
348		} else { /* not mc-frame */
349			/* For AP mode, if DA is non-MCAST, then it must be
350			 *  BSSID, and bssid == BSSID */
351			if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN))
352				return _FAIL;
353			sta_addr = pattrib->src;
354		}
355	  } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
356		memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
357		memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
358		memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
359		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
360		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
361		sta_addr = mybssid;
362	  } else
363		ret  = _FAIL;
364	if (bmcast)
365		*psta = r8712_get_bcmc_stainfo(adapter);
366	else
367		*psta = r8712_get_stainfo(pstapriv, sta_addr); /* get ap_info */
368	if (*psta == NULL) {
369		if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
370			adapter->mppriv.rx_pktloss++;
371		return _FAIL;
372	}
373	return ret;
374}
375
376static sint ap2sta_data_frame(struct _adapter *adapter,
377			      union recv_frame *precv_frame,
378			      struct sta_info **psta)
379{
380	u8 *ptr = precv_frame->u.hdr.rx_data;
381	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
382	struct	sta_priv *pstapriv = &adapter->stapriv;
383	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
384	u8 *mybssid  = get_bssid(pmlmepriv);
385	u8 *myhwaddr = myid(&adapter->eeprompriv);
386	sint bmcast = IS_MCAST(pattrib->dst);
387
388	if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
389	     && (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
390		/* if NULL-frame, drop packet */
391		if ((GetFrameSubType(ptr)) == WIFI_DATA_NULL)
392			return _FAIL;
393		/* drop QoS-SubType Data, including QoS NULL,
394		 * excluding QoS-Data */
395		if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) ==
396		     WIFI_QOS_DATA_TYPE) {
397			if (GetFrameSubType(ptr) & (BIT(4) | BIT(5) | BIT(6)))
398				return _FAIL;
399		}
400
401		/* filter packets that SA is myself or multicast or broadcast */
402	       if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN))
403			return _FAIL;
404
405		/* da should be for me */
406		if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
407			return _FAIL;
408		/* check BSSID */
409		if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
410		     !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
411		     (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
412			return _FAIL;
413		if (bmcast)
414			*psta = r8712_get_bcmc_stainfo(adapter);
415		else
416		       *psta = r8712_get_stainfo(pstapriv, pattrib->bssid);
417		if (*psta == NULL)
418			return _FAIL;
419	} else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
420		   (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
421		memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
422		memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
423		memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
424		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
425		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
426		memcpy(pattrib->bssid,  mybssid, ETH_ALEN);
427		*psta = r8712_get_stainfo(pstapriv, pattrib->bssid);
428		if (*psta == NULL)
429			return _FAIL;
430	} else
431		return _FAIL;
432	return _SUCCESS;
433}
434
435static sint sta2ap_data_frame(struct _adapter *adapter,
436			      union recv_frame *precv_frame,
437			      struct sta_info **psta)
438{
439	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
440	struct	sta_priv *pstapriv = &adapter->stapriv;
441	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
442	unsigned char *mybssid  = get_bssid(pmlmepriv);
443
444	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
445		/* For AP mode, if DA is non-MCAST, then it must be BSSID,
446		 * and bssid == BSSID
447		 * For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR */
448		if (memcmp(pattrib->bssid, mybssid, ETH_ALEN))
449			return _FAIL;
450		*psta = r8712_get_stainfo(pstapriv, pattrib->src);
451		if (*psta == NULL)
452			return _FAIL;
453	}
454	return _SUCCESS;
455}
456
457static sint validate_recv_ctrl_frame(struct _adapter *adapter,
458			      union recv_frame *precv_frame)
459{
460	return _FAIL;
461}
462
463static sint validate_recv_mgnt_frame(struct _adapter *adapter,
464			      union recv_frame *precv_frame)
465{
466	return _FAIL;
467}
468
469
470static sint validate_recv_data_frame(struct _adapter *adapter,
471			      union recv_frame *precv_frame)
472{
473	int res;
474	u8 bretry;
475	u8 *psa, *pda, *pbssid;
476	struct sta_info *psta = NULL;
477	u8 *ptr = precv_frame->u.hdr.rx_data;
478	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
479	struct security_priv *psecuritypriv = &adapter->securitypriv;
480
481	bretry = GetRetry(ptr);
482	pda = get_da(ptr);
483	psa = get_sa(ptr);
484	pbssid = get_hdr_bssid(ptr);
485	if (pbssid == NULL)
486		return _FAIL;
487	memcpy(pattrib->dst, pda, ETH_ALEN);
488	memcpy(pattrib->src, psa, ETH_ALEN);
489	memcpy(pattrib->bssid, pbssid, ETH_ALEN);
490	switch (pattrib->to_fr_ds) {
491	case 0:
492		memcpy(pattrib->ra, pda, ETH_ALEN);
493		memcpy(pattrib->ta, psa, ETH_ALEN);
494		res = sta2sta_data_frame(adapter, precv_frame, &psta);
495		break;
496	case 1:
497		memcpy(pattrib->ra, pda, ETH_ALEN);
498		memcpy(pattrib->ta, pbssid, ETH_ALEN);
499		res = ap2sta_data_frame(adapter, precv_frame, &psta);
500		break;
501	case 2:
502		memcpy(pattrib->ra, pbssid, ETH_ALEN);
503		memcpy(pattrib->ta, psa, ETH_ALEN);
504		res = sta2ap_data_frame(adapter, precv_frame, &psta);
505		break;
506	case 3:
507		memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
508		memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
509		return _FAIL;
510	default:
511		return _FAIL;
512	}
513	if (res == _FAIL)
514		return _FAIL;
515	if (psta == NULL)
516		return _FAIL;
517	else
518		precv_frame->u.hdr.psta = psta;
519	pattrib->amsdu = 0;
520	/* parsing QC field */
521	if (pattrib->qos == 1) {
522		pattrib->priority = GetPriority((ptr + 24));
523		pattrib->ack_policy = GetAckpolicy((ptr + 24));
524		pattrib->amsdu = GetAMsdu((ptr + 24));
525		pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26;
526	} else {
527		pattrib->priority = 0;
528		pattrib->hdrlen = (pattrib->to_fr_ds == 3) ? 30 : 24;
529	}
530
531	if (pattrib->order)/*HT-CTRL 11n*/
532		pattrib->hdrlen += 4;
533	precv_frame->u.hdr.preorder_ctrl =
534			 &psta->recvreorder_ctrl[pattrib->priority];
535
536	/* decache, drop duplicate recv packets */
537	if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) ==
538	    _FAIL)
539		return _FAIL;
540
541	if (pattrib->privacy) {
542		GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
543			       IS_MCAST(pattrib->ra));
544		SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len,
545			       pattrib->encrypt);
546	} else {
547		pattrib->encrypt = 0;
548		pattrib->iv_len = pattrib->icv_len = 0;
549	}
550	return _SUCCESS;
551}
552
553sint r8712_validate_recv_frame(struct _adapter *adapter,
554			       union recv_frame *precv_frame)
555{
556	/*shall check frame subtype, to / from ds, da, bssid */
557	/*then call check if rx seq/frag. duplicated.*/
558
559	u8 type;
560	u8 subtype;
561	sint retval = _SUCCESS;
562	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
563
564	u8 *ptr = precv_frame->u.hdr.rx_data;
565	u8  ver = (unsigned char)(*ptr) & 0x3;
566
567	/*add version chk*/
568	if (ver != 0)
569		return _FAIL;
570	type =  GetFrameType(ptr);
571	subtype = GetFrameSubType(ptr); /*bit(7)~bit(2)*/
572	pattrib->to_fr_ds = get_tofr_ds(ptr);
573	pattrib->frag_num = GetFragNum(ptr);
574	pattrib->seq_num = GetSequence(ptr);
575	pattrib->pw_save = GetPwrMgt(ptr);
576	pattrib->mfrag = GetMFrag(ptr);
577	pattrib->mdata = GetMData(ptr);
578	pattrib->privacy =  GetPrivacy(ptr);
579	pattrib->order = GetOrder(ptr);
580	switch (type) {
581	case WIFI_MGT_TYPE: /*mgnt*/
582		retval = validate_recv_mgnt_frame(adapter, precv_frame);
583		break;
584	case WIFI_CTRL_TYPE:/*ctrl*/
585		retval = validate_recv_ctrl_frame(adapter, precv_frame);
586		break;
587	case WIFI_DATA_TYPE: /*data*/
588		pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
589		retval = validate_recv_data_frame(adapter, precv_frame);
590		break;
591	default:
592		return _FAIL;
593	}
594	return retval;
595}
596
597sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
598{
599	/*remove the wlanhdr and add the eth_hdr*/
600	sint	rmv_len;
601	u16	eth_type, len;
602	u8	bsnaphdr;
603	u8	*psnap_type;
604	struct ieee80211_snap_hdr *psnap;
605
606	sint ret = _SUCCESS;
607	struct _adapter	*adapter = precvframe->u.hdr.adapter;
608	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
609
610	u8 *ptr = get_recvframe_data(precvframe); /*point to frame_ctrl field*/
611	struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
612
613	if (pattrib->encrypt)
614		recvframe_pull_tail(precvframe, pattrib->icv_len);
615	psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen +
616		 pattrib->iv_len);
617	psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
618	/* convert hdr + possible LLC headers into Ethernet header */
619	if ((!memcmp(psnap, (void *)rfc1042_header, SNAP_SIZE) &&
620	    (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_IPX, 2)) &&
621	    (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_APPLETALK_AARP, 2))) ||
622	     !memcmp(psnap, (void *)bridge_tunnel_header, SNAP_SIZE)) {
623		/* remove RFC1042 or Bridge-Tunnel encapsulation and
624		 * replace EtherType */
625		bsnaphdr = true;
626	} else {
627		/* Leave Ethernet header part of hdr and full payload */
628		bsnaphdr = false;
629	}
630	rmv_len = pattrib->hdrlen + pattrib->iv_len +
631		  (bsnaphdr ? SNAP_SIZE : 0);
632	len = precvframe->u.hdr.len - rmv_len;
633	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) {
634		ptr += rmv_len;
635		*ptr = 0x87;
636		*(ptr+1) = 0x12;
637		eth_type = 0x8712;
638		/* append rx status for mp test packets */
639		ptr = recvframe_pull(precvframe, (rmv_len -
640		      sizeof(struct ethhdr) + 2) - 24);
641		memcpy(ptr, get_rxmem(precvframe), 24);
642		ptr += 24;
643	} else
644		ptr = recvframe_pull(precvframe, (rmv_len -
645		      sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
646
647	memcpy(ptr, pattrib->dst, ETH_ALEN);
648	memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
649	if (!bsnaphdr) {
650		len = htons(len);
651		memcpy(ptr + 12, &len, 2);
652	}
653	return ret;
654}
655
656s32 r8712_recv_entry(union recv_frame *precvframe)
657{
658	struct _adapter *padapter;
659	struct recv_priv *precvpriv;
660	struct	mlme_priv *pmlmepriv;
661	struct recv_stat *prxstat;
662	struct dvobj_priv *pdev;
663	u8 *phead, *pdata, *ptail, *pend;
664
665	struct  __queue *pfree_recv_queue, *ppending_recv_queue;
666	s32 ret = _SUCCESS;
667	struct intf_hdl *pintfhdl;
668
669	padapter = precvframe->u.hdr.adapter;
670	pintfhdl = &padapter->pio_queue->intf;
671	pmlmepriv = &padapter->mlmepriv;
672	precvpriv = &(padapter->recvpriv);
673	pdev = &padapter->dvobjpriv;
674	pfree_recv_queue = &(precvpriv->free_recv_queue);
675	ppending_recv_queue = &(precvpriv->recv_pending_queue);
676	phead = precvframe->u.hdr.rx_head;
677	pdata = precvframe->u.hdr.rx_data;
678	ptail = precvframe->u.hdr.rx_tail;
679	pend = precvframe->u.hdr.rx_end;
680	prxstat = (struct recv_stat *)phead;
681
682	padapter->ledpriv.LedControlHandler(padapter, LED_CTL_RX);
683
684	ret = recv_func(padapter, precvframe);
685	if (ret == _FAIL)
686		goto _recv_entry_drop;
687	precvpriv->rx_pkts++;
688	precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail -
689				precvframe->u.hdr.rx_data);
690	return ret;
691_recv_entry_drop:
692	precvpriv->rx_drop++;
693	padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
694	return ret;
695}