linux/drivers/staging/rtl8712/rtl871x_recv.c
<<
>>
Prefs
   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 = _malloc(NR_RECVFRAME *
  76                                           sizeof(union recv_frame) +
  77                                           RXFRAME_ALIGN_SZ);
  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_listhead(&(precvframe->u.list));
  90                list_insert_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 (_queue_empty(pfree_recv_queue) == true)
 116                precvframe = NULL;
 117        else {
 118                phead = get_list_head(pfree_recv_queue);
 119                plist = get_next(phead);
 120                precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
 121                list_delete(&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 = get_list_head(pframequeue);
 149        plist = get_next(phead);
 150        while (end_of_queue_search(phead, plist) == false) {
 151                precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
 152                plist = get_next(plist);
 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 = 0;
 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                if ((psta != NULL) && (psta->ieee8021x_blocked)) {
 267                        /* blocked
 268                         * only accept EAPOL frame */
 269                        prtnframe = precv_frame;
 270                        /*get ether_type */
 271                        ptr = ptr + pfhdr->attrib.hdrlen +
 272                              pfhdr->attrib.iv_len + LLC_HEADER_SIZE;
 273                        memcpy(&ether_type, ptr, 2);
 274                        ether_type = ntohs((unsigned short)ether_type);
 275                        if (ether_type == 0x888e)
 276                                prtnframe = precv_frame;
 277                        else {
 278                                /*free this frame*/
 279                                r8712_free_recvframe(precv_frame,
 280                                         &adapter->recvpriv.free_recv_queue);
 281                                prtnframe = NULL;
 282                        }
 283                } else {
 284                        /* allowed
 285                         * check decryption status, and decrypt the
 286                         * frame if needed */
 287                        prtnframe = precv_frame;
 288                        /* check is the EAPOL frame or not (Rekey) */
 289                        if (ether_type == 0x888e) {
 290                                /* check Rekey */
 291                                prtnframe = precv_frame;
 292                        }
 293                }
 294        } else
 295                prtnframe = precv_frame;
 296        return prtnframe;
 297}
 298
 299static sint recv_decache(union recv_frame *precv_frame, u8 bretry,
 300                  struct stainfo_rxcache *prxcache)
 301{
 302        sint tid = precv_frame->u.hdr.attrib.priority;
 303        u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
 304                        (precv_frame->u.hdr.attrib.frag_num & 0xf);
 305
 306        if (tid > 15)
 307                return _FAIL;
 308        if (seq_ctrl == prxcache->tid_rxseq[tid])
 309                return _FAIL;
 310        prxcache->tid_rxseq[tid] = seq_ctrl;
 311        return _SUCCESS;
 312}
 313
 314static sint sta2sta_data_frame(struct _adapter *adapter,
 315                               union recv_frame *precv_frame,
 316                               struct sta_info **psta)
 317{
 318        u8 *ptr = precv_frame->u.hdr.rx_data;
 319        sint ret = _SUCCESS;
 320        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 321        struct  sta_priv *pstapriv = &adapter->stapriv;
 322        struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
 323        u8 *mybssid  = get_bssid(pmlmepriv);
 324        u8 *myhwaddr = myid(&adapter->eeprompriv);
 325        u8 *sta_addr = NULL;
 326        sint bmcast = IS_MCAST(pattrib->dst);
 327
 328        if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
 329            (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
 330                /* filter packets that SA is myself or multicast or broadcast */
 331                if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN))
 332                        return _FAIL;
 333                if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
 334                        return _FAIL;
 335                if (is_zero_ether_addr(pattrib->bssid) ||
 336                    is_zero_ether_addr(mybssid) ||
 337                    (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
 338                        return _FAIL;
 339                sta_addr = pattrib->src;
 340        } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
 341                /* For Station mode, sa and bssid should always be BSSID,
 342                 * and DA is my mac-address */
 343                if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN))
 344                        return _FAIL;
 345               sta_addr = pattrib->bssid;
 346         } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
 347                if (bmcast) {
 348                        /* For AP mode, if DA == MCAST, then BSSID should
 349                         * be also MCAST */
 350                        if (!IS_MCAST(pattrib->bssid))
 351                                return _FAIL;
 352                } else { /* not mc-frame */
 353                        /* For AP mode, if DA is non-MCAST, then it must be
 354                         *  BSSID, and bssid == BSSID */
 355                        if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN))
 356                                return _FAIL;
 357                        sta_addr = pattrib->src;
 358                }
 359          } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
 360                memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
 361                memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
 362                memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
 363                memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
 364                memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
 365                sta_addr = mybssid;
 366          } else
 367                ret  = _FAIL;
 368        if (bmcast)
 369                *psta = r8712_get_bcmc_stainfo(adapter);
 370        else
 371                *psta = r8712_get_stainfo(pstapriv, sta_addr); /* get ap_info */
 372        if (*psta == NULL) {
 373                if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
 374                        adapter->mppriv.rx_pktloss++;
 375                return _FAIL;
 376        }
 377        return ret;
 378}
 379
 380static sint ap2sta_data_frame(struct _adapter *adapter,
 381                              union recv_frame *precv_frame,
 382                              struct sta_info **psta)
 383{
 384        u8 *ptr = precv_frame->u.hdr.rx_data;
 385        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 386        struct  sta_priv *pstapriv = &adapter->stapriv;
 387        struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
 388        u8 *mybssid  = get_bssid(pmlmepriv);
 389        u8 *myhwaddr = myid(&adapter->eeprompriv);
 390        sint bmcast = IS_MCAST(pattrib->dst);
 391
 392        if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
 393             && (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
 394                /* if NULL-frame, drop packet */
 395                if ((GetFrameSubType(ptr)) == WIFI_DATA_NULL)
 396                        return _FAIL;
 397                /* drop QoS-SubType Data, including QoS NULL,
 398                 * excluding QoS-Data */
 399                if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) ==
 400                     WIFI_QOS_DATA_TYPE) {
 401                        if (GetFrameSubType(ptr) & (BIT(4) | BIT(5) | BIT(6)))
 402                                return _FAIL;
 403                }
 404
 405                /* filter packets that SA is myself or multicast or broadcast */
 406               if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN))
 407                        return _FAIL;
 408
 409                /* da should be for me */
 410                if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast))
 411                        return _FAIL;
 412                /* check BSSID */
 413                if (is_zero_ether_addr(pattrib->bssid) ||
 414                     is_zero_ether_addr(mybssid) ||
 415                     (memcmp(pattrib->bssid, mybssid, ETH_ALEN)))
 416                        return _FAIL;
 417                if (bmcast)
 418                        *psta = r8712_get_bcmc_stainfo(adapter);
 419                else
 420                       *psta = r8712_get_stainfo(pstapriv, pattrib->bssid);
 421                if (*psta == NULL)
 422                        return _FAIL;
 423        } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
 424                   (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
 425                memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
 426                memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
 427                memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
 428                memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
 429                memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
 430                memcpy(pattrib->bssid,  mybssid, ETH_ALEN);
 431                *psta = r8712_get_stainfo(pstapriv, pattrib->bssid);
 432                if (*psta == NULL)
 433                        return _FAIL;
 434        } else
 435                return _FAIL;
 436        return _SUCCESS;
 437}
 438
 439static sint sta2ap_data_frame(struct _adapter *adapter,
 440                              union recv_frame *precv_frame,
 441                              struct sta_info **psta)
 442{
 443        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 444        struct  sta_priv *pstapriv = &adapter->stapriv;
 445        struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
 446        unsigned char *mybssid  = get_bssid(pmlmepriv);
 447
 448        if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
 449                /* For AP mode, if DA is non-MCAST, then it must be BSSID,
 450                 * and bssid == BSSID
 451                 * For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR */
 452                if (memcmp(pattrib->bssid, mybssid, ETH_ALEN))
 453                        return _FAIL;
 454                *psta = r8712_get_stainfo(pstapriv, pattrib->src);
 455                if (*psta == NULL)
 456                        return _FAIL;
 457        }
 458        return _SUCCESS;
 459}
 460
 461static sint validate_recv_ctrl_frame(struct _adapter *adapter,
 462                              union recv_frame *precv_frame)
 463{
 464        return _FAIL;
 465}
 466
 467static sint validate_recv_mgnt_frame(struct _adapter *adapter,
 468                              union recv_frame *precv_frame)
 469{
 470        return _FAIL;
 471}
 472
 473
 474static sint validate_recv_data_frame(struct _adapter *adapter,
 475                              union recv_frame *precv_frame)
 476{
 477        int res;
 478        u8 bretry;
 479        u8 *psa, *pda, *pbssid;
 480        struct sta_info *psta = NULL;
 481        u8 *ptr = precv_frame->u.hdr.rx_data;
 482        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 483        struct security_priv *psecuritypriv = &adapter->securitypriv;
 484
 485        bretry = GetRetry(ptr);
 486        pda = get_da(ptr);
 487        psa = get_sa(ptr);
 488        pbssid = get_hdr_bssid(ptr);
 489        if (pbssid == NULL)
 490                return _FAIL;
 491        memcpy(pattrib->dst, pda, ETH_ALEN);
 492        memcpy(pattrib->src, psa, ETH_ALEN);
 493        memcpy(pattrib->bssid, pbssid, ETH_ALEN);
 494        switch (pattrib->to_fr_ds) {
 495        case 0:
 496                memcpy(pattrib->ra, pda, ETH_ALEN);
 497                memcpy(pattrib->ta, psa, ETH_ALEN);
 498                res = sta2sta_data_frame(adapter, precv_frame, &psta);
 499                break;
 500        case 1:
 501                memcpy(pattrib->ra, pda, ETH_ALEN);
 502                memcpy(pattrib->ta, pbssid, ETH_ALEN);
 503                res = ap2sta_data_frame(adapter, precv_frame, &psta);
 504                break;
 505        case 2:
 506                memcpy(pattrib->ra, pbssid, ETH_ALEN);
 507                memcpy(pattrib->ta, psa, ETH_ALEN);
 508                res = sta2ap_data_frame(adapter, precv_frame, &psta);
 509                break;
 510        case 3:
 511                memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
 512                memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
 513                return _FAIL;
 514        default:
 515                return _FAIL;
 516        }
 517        if (res == _FAIL)
 518                return _FAIL;
 519        if (psta == NULL)
 520                return _FAIL;
 521        else
 522                precv_frame->u.hdr.psta = psta;
 523        pattrib->amsdu = 0;
 524        /* parsing QC field */
 525        if (pattrib->qos == 1) {
 526                pattrib->priority = GetPriority((ptr + 24));
 527                pattrib->ack_policy = GetAckpolicy((ptr + 24));
 528                pattrib->amsdu = GetAMsdu((ptr + 24));
 529                pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26;
 530        } else {
 531                pattrib->priority = 0;
 532                pattrib->hdrlen = (pattrib->to_fr_ds == 3) ? 30 : 24;
 533        }
 534
 535        if (pattrib->order)/*HT-CTRL 11n*/
 536                pattrib->hdrlen += 4;
 537        precv_frame->u.hdr.preorder_ctrl =
 538                         &psta->recvreorder_ctrl[pattrib->priority];
 539
 540        /* decache, drop duplicate recv packets */
 541        if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) ==
 542            _FAIL)
 543                return _FAIL;
 544
 545        if (pattrib->privacy) {
 546                GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
 547                               IS_MCAST(pattrib->ra));
 548                SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len,
 549                               pattrib->encrypt);
 550        } else {
 551                pattrib->encrypt = 0;
 552                pattrib->iv_len = pattrib->icv_len = 0;
 553        }
 554        return _SUCCESS;
 555}
 556
 557sint r8712_validate_recv_frame(struct _adapter *adapter,
 558                               union recv_frame *precv_frame)
 559{
 560        /*shall check frame subtype, to / from ds, da, bssid */
 561        /*then call check if rx seq/frag. duplicated.*/
 562
 563        u8 type;
 564        u8 subtype;
 565        sint retval = _SUCCESS;
 566        struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
 567
 568        u8 *ptr = precv_frame->u.hdr.rx_data;
 569        u8  ver = (unsigned char)(*ptr) & 0x3;
 570
 571        /*add version chk*/
 572        if (ver != 0)
 573                return _FAIL;
 574        type =  GetFrameType(ptr);
 575        subtype = GetFrameSubType(ptr); /*bit(7)~bit(2)*/
 576        pattrib->to_fr_ds = get_tofr_ds(ptr);
 577        pattrib->frag_num = GetFragNum(ptr);
 578        pattrib->seq_num = GetSequence(ptr);
 579        pattrib->pw_save = GetPwrMgt(ptr);
 580        pattrib->mfrag = GetMFrag(ptr);
 581        pattrib->mdata = GetMData(ptr);
 582        pattrib->privacy =  GetPrivacy(ptr);
 583        pattrib->order = GetOrder(ptr);
 584        switch (type) {
 585        case WIFI_MGT_TYPE: /*mgnt*/
 586                retval = validate_recv_mgnt_frame(adapter, precv_frame);
 587                break;
 588        case WIFI_CTRL_TYPE:/*ctrl*/
 589                retval = validate_recv_ctrl_frame(adapter, precv_frame);
 590                break;
 591        case WIFI_DATA_TYPE: /*data*/
 592                pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
 593                retval = validate_recv_data_frame(adapter, precv_frame);
 594                break;
 595        default:
 596                return _FAIL;
 597        }
 598        return retval;
 599}
 600
 601sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
 602{
 603        /*remove the wlanhdr and add the eth_hdr*/
 604        sint    rmv_len;
 605        u16     eth_type, len;
 606        u8      bsnaphdr;
 607        u8      *psnap_type;
 608        struct ieee80211_snap_hdr *psnap;
 609
 610        sint ret = _SUCCESS;
 611        struct _adapter *adapter = precvframe->u.hdr.adapter;
 612        struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
 613
 614        u8 *ptr = get_recvframe_data(precvframe); /*point to frame_ctrl field*/
 615        struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
 616
 617        if (pattrib->encrypt)
 618                recvframe_pull_tail(precvframe, pattrib->icv_len);
 619        psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen +
 620                 pattrib->iv_len);
 621        psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
 622        /* convert hdr + possible LLC headers into Ethernet header */
 623        if ((!memcmp(psnap, (void *)rfc1042_header, SNAP_SIZE) &&
 624            (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_IPX, 2)) &&
 625            (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_APPLETALK_AARP, 2))) ||
 626             !memcmp(psnap, (void *)bridge_tunnel_header, SNAP_SIZE)) {
 627                /* remove RFC1042 or Bridge-Tunnel encapsulation and
 628                 * replace EtherType */
 629                bsnaphdr = true;
 630        } else {
 631                /* Leave Ethernet header part of hdr and full payload */
 632                bsnaphdr = false;
 633        }
 634        rmv_len = pattrib->hdrlen + pattrib->iv_len +
 635                  (bsnaphdr ? SNAP_SIZE : 0);
 636        len = precvframe->u.hdr.len - rmv_len;
 637        if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) {
 638                ptr += rmv_len;
 639                *ptr = 0x87;
 640                *(ptr+1) = 0x12;
 641                eth_type = 0x8712;
 642                /* append rx status for mp test packets */
 643                ptr = recvframe_pull(precvframe, (rmv_len -
 644                      sizeof(struct ethhdr) + 2) - 24);
 645                memcpy(ptr, get_rxmem(precvframe), 24);
 646                ptr += 24;
 647        } else
 648                ptr = recvframe_pull(precvframe, (rmv_len -
 649                      sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
 650
 651        memcpy(ptr, pattrib->dst, ETH_ALEN);
 652        memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
 653        if (!bsnaphdr) {
 654                len = htons(len);
 655                memcpy(ptr + 12, &len, 2);
 656        }
 657        return ret;
 658}
 659
 660s32 r8712_recv_entry(union recv_frame *precvframe)
 661{
 662        struct _adapter *padapter;
 663        struct recv_priv *precvpriv;
 664        struct  mlme_priv *pmlmepriv;
 665        struct recv_stat *prxstat;
 666        struct dvobj_priv *pdev;
 667        u8 *phead, *pdata, *ptail, *pend;
 668
 669        struct  __queue *pfree_recv_queue, *ppending_recv_queue;
 670        s32 ret = _SUCCESS;
 671        struct intf_hdl *pintfhdl;
 672
 673        padapter = precvframe->u.hdr.adapter;
 674        pintfhdl = &padapter->pio_queue->intf;
 675        pmlmepriv = &padapter->mlmepriv;
 676        precvpriv = &(padapter->recvpriv);
 677        pdev = &padapter->dvobjpriv;
 678        pfree_recv_queue = &(precvpriv->free_recv_queue);
 679        ppending_recv_queue = &(precvpriv->recv_pending_queue);
 680        phead = precvframe->u.hdr.rx_head;
 681        pdata = precvframe->u.hdr.rx_data;
 682        ptail = precvframe->u.hdr.rx_tail;
 683        pend = precvframe->u.hdr.rx_end;
 684        prxstat = (struct recv_stat *)phead;
 685
 686        padapter->ledpriv.LedControlHandler(padapter, LED_CTL_RX);
 687
 688        ret = recv_func(padapter, precvframe);
 689        if (ret == _FAIL)
 690                goto _recv_entry_drop;
 691        precvpriv->rx_pkts++;
 692        precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail -
 693                                precvframe->u.hdr.rx_data);
 694        return ret;
 695_recv_entry_drop:
 696        precvpriv->rx_drop++;
 697        padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
 698        return ret;
 699}
 700