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