cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtl871x_recv.c (19819B)


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