linux/drivers/staging/rtl8712/rtl871x_recv.c
<<
>>
Prefs
   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 = get_recvframe_data(precv_frame);
 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
 458
 459static sint validate_recv_data_frame(struct _adapter *adapter,
 460                                     union recv_frame *precv_frame)
 461{
 462        int res;
 463        u8 bretry;
 464        u8 *psa, *pda, *pbssid;
 465        struct sta_info *psta = NULL;
 466        u8 *ptr = precv_frame->u.hdr.rx_data;
 467        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 468        struct security_priv *psecuritypriv = &adapter->securitypriv;
 469
 470        bretry = GetRetry(ptr);
 471        pda = ieee80211_get_DA((struct ieee80211_hdr *)ptr);
 472        psa = ieee80211_get_SA((struct ieee80211_hdr *)ptr);
 473        pbssid = get_hdr_bssid(ptr);
 474        if (!pbssid)
 475                return _FAIL;
 476        memcpy(pattrib->dst, pda, ETH_ALEN);
 477        memcpy(pattrib->src, psa, ETH_ALEN);
 478        memcpy(pattrib->bssid, pbssid, ETH_ALEN);
 479        switch (pattrib->to_fr_ds) {
 480        case 0:
 481                memcpy(pattrib->ra, pda, ETH_ALEN);
 482                memcpy(pattrib->ta, psa, ETH_ALEN);
 483                res = sta2sta_data_frame(adapter, precv_frame, &psta);
 484                break;
 485        case 1:
 486                memcpy(pattrib->ra, pda, ETH_ALEN);
 487                memcpy(pattrib->ta, pbssid, ETH_ALEN);
 488                res = ap2sta_data_frame(adapter, precv_frame, &psta);
 489                break;
 490        case 2:
 491                memcpy(pattrib->ra, pbssid, ETH_ALEN);
 492                memcpy(pattrib->ta, psa, ETH_ALEN);
 493                res = sta2ap_data_frame(adapter, precv_frame, &psta);
 494                break;
 495        case 3:
 496                memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
 497                memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
 498                return _FAIL;
 499        default:
 500                return _FAIL;
 501        }
 502        if (res == _FAIL)
 503                return _FAIL;
 504        if (!psta)
 505                return _FAIL;
 506        precv_frame->u.hdr.psta = psta;
 507        pattrib->amsdu = 0;
 508        /* parsing QC field */
 509        if (pattrib->qos == 1) {
 510                pattrib->priority = GetPriority((ptr + 24));
 511                pattrib->ack_policy = GetAckpolicy((ptr + 24));
 512                pattrib->amsdu = GetAMsdu((ptr + 24));
 513                pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26;
 514        } else {
 515                pattrib->priority = 0;
 516                pattrib->hdrlen = (pattrib->to_fr_ds == 3) ? 30 : 24;
 517        }
 518
 519        if (pattrib->order)/*HT-CTRL 11n*/
 520                pattrib->hdrlen += 4;
 521        precv_frame->u.hdr.preorder_ctrl =
 522                         &psta->recvreorder_ctrl[pattrib->priority];
 523
 524        /* decache, drop duplicate recv packets */
 525        if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) ==
 526            _FAIL)
 527                return _FAIL;
 528
 529        if (pattrib->privacy) {
 530                GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
 531                               is_multicast_ether_addr(pattrib->ra));
 532                SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len,
 533                               pattrib->encrypt);
 534        } else {
 535                pattrib->encrypt = 0;
 536                pattrib->iv_len = pattrib->icv_len = 0;
 537        }
 538        return _SUCCESS;
 539}
 540
 541sint r8712_validate_recv_frame(struct _adapter *adapter,
 542                               union recv_frame *precv_frame)
 543{
 544        /*shall check frame subtype, to / from ds, da, bssid */
 545        /*then call check if rx seq/frag. duplicated.*/
 546
 547        u8 type;
 548        u8 subtype;
 549        sint retval = _SUCCESS;
 550        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 551
 552        u8 *ptr = precv_frame->u.hdr.rx_data;
 553        u8  ver = (unsigned char)(*ptr) & 0x3;
 554
 555        /*add version chk*/
 556        if (ver != 0)
 557                return _FAIL;
 558        type =  GetFrameType(ptr);
 559        subtype = GetFrameSubType(ptr); /*bit(7)~bit(2)*/
 560        pattrib->to_fr_ds = get_tofr_ds(ptr);
 561        pattrib->frag_num = GetFragNum(ptr);
 562        pattrib->seq_num = GetSequence(ptr);
 563        pattrib->pw_save = GetPwrMgt(ptr);
 564        pattrib->mfrag = GetMFrag(ptr);
 565        pattrib->mdata = GetMData(ptr);
 566        pattrib->privacy =  GetPrivacy(ptr);
 567        pattrib->order = GetOrder(ptr);
 568        switch (type) {
 569        case IEEE80211_FTYPE_MGMT:
 570                retval = validate_recv_mgnt_frame(adapter, precv_frame);
 571                break;
 572        case IEEE80211_FTYPE_CTL:
 573                retval = validate_recv_ctrl_frame(adapter, precv_frame);
 574                break;
 575        case IEEE80211_FTYPE_DATA:
 576                pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
 577                retval = validate_recv_data_frame(adapter, precv_frame);
 578                break;
 579        default:
 580                return _FAIL;
 581        }
 582        return retval;
 583}
 584
 585int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
 586{
 587        /*remove the wlanhdr and add the eth_hdr*/
 588        sint    rmv_len;
 589        u16     len;
 590        u8      bsnaphdr;
 591        u8      *psnap_type;
 592        struct ieee80211_snap_hdr *psnap;
 593        struct _adapter *adapter = precvframe->u.hdr.adapter;
 594        struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
 595
 596        u8 *ptr = get_recvframe_data(precvframe); /*point to frame_ctrl field*/
 597        struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
 598
 599        if (pattrib->encrypt)
 600                recvframe_pull_tail(precvframe, pattrib->icv_len);
 601        psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen +
 602                 pattrib->iv_len);
 603        psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
 604        /* convert hdr + possible LLC headers into Ethernet header */
 605        if ((!memcmp(psnap, (void *)rfc1042_header, SNAP_SIZE) &&
 606             (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_IPX, 2)) &&
 607            (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_APPLETALK_AARP, 2))) ||
 608             !memcmp(psnap, (void *)bridge_tunnel_header, SNAP_SIZE)) {
 609                /* remove RFC1042 or Bridge-Tunnel encapsulation and
 610                 * replace EtherType
 611                 */
 612                bsnaphdr = true;
 613        } else {
 614                /* Leave Ethernet header part of hdr and full payload */
 615                bsnaphdr = false;
 616        }
 617        rmv_len = pattrib->hdrlen + pattrib->iv_len +
 618                  (bsnaphdr ? SNAP_SIZE : 0);
 619        len = precvframe->u.hdr.len - rmv_len;
 620        if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
 621                ptr += rmv_len;
 622                *ptr = 0x87;
 623                *(ptr + 1) = 0x12;
 624                /* append rx status for mp test packets */
 625                ptr = recvframe_pull(precvframe, (rmv_len -
 626                      sizeof(struct ethhdr) + 2) - 24);
 627                if (!ptr)
 628                        return -ENOMEM;
 629                memcpy(ptr, get_rxmem(precvframe), 24);
 630                ptr += 24;
 631        } else {
 632                ptr = recvframe_pull(precvframe, (rmv_len -
 633                      sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
 634                if (!ptr)
 635                        return -ENOMEM;
 636        }
 637
 638        memcpy(ptr, pattrib->dst, ETH_ALEN);
 639        memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
 640        if (!bsnaphdr) {
 641                __be16 be_tmp = htons(len);
 642
 643                memcpy(ptr + 12, &be_tmp, 2);
 644        }
 645        return 0;
 646}
 647
 648void r8712_recv_entry(union recv_frame *precvframe)
 649{
 650        struct _adapter *padapter;
 651        struct recv_priv *precvpriv;
 652
 653        s32 ret = _SUCCESS;
 654
 655        padapter = precvframe->u.hdr.adapter;
 656        precvpriv = &(padapter->recvpriv);
 657
 658        padapter->ledpriv.LedControlHandler(padapter, LED_CTL_RX);
 659
 660        ret = recv_func(padapter, precvframe);
 661        if (ret == _FAIL)
 662                goto _recv_entry_drop;
 663        precvpriv->rx_pkts++;
 664        precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail -
 665                                precvframe->u.hdr.rx_data);
 666        return;
 667_recv_entry_drop:
 668        precvpriv->rx_drop++;
 669        padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
 670}
 671