summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c')
-rw-r--r--drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
new file mode 100644
index 000000000000..5e5c68e2a108
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c
@@ -0,0 +1,289 @@
+/** @file mlan_sta_rx.c
+ *
+ * @brief This file contains the handling of RX in MLAN
+ * module.
+ *
+ * Copyright (C) 2008-2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+/********************************************************
+Change log:
+ 10/27/2008: initial version
+********************************************************/
+
+#include "mlan.h"
+#include "mlan_join.h"
+#include "mlan_util.h"
+#include "mlan_fw.h"
+#include "mlan_main.h"
+#include "mlan_11n_aggr.h"
+#include "mlan_11n_rxreorder.h"
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/** Ethernet II header */
+typedef struct
+{
+ /** Ethernet II header destination address */
+ t_u8 dest_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header source address */
+ t_u8 src_addr[MLAN_MAC_ADDR_LENGTH];
+ /** Ethernet II header length */
+ t_u16 ethertype;
+
+} EthII_Hdr_t;
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+
+/********************************************************
+ Global functions
+********************************************************/
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param pmadapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to mlan_buffer which includes the received packet
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_process_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ RxPacketHdr_t *prx_pkt;
+ RxPD *prx_pd;
+ int hdr_chop;
+ EthII_Hdr_t *peth_hdr;
+ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ t_u8 snap_oui_802_h[MLAN_MAC_ADDR_LENGTH] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+ t_u8 appletalk_aarp_type[2] = { 0x80, 0xf3 };
+ t_u8 ipx_snap_type[2] = { 0x81, 0x37 };
+
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+/** Small debug type */
+#define DBG_TYPE_SMALL 2
+/** Size of debugging structure */
+#define SIZE_OF_DBG_STRUCT 4
+ if (prx_pd->rx_pkt_type == PKT_TYPE_DEBUG) {
+ t_u8 dbgType;
+ dbgType = *(t_u8 *) & prx_pkt->eth803_hdr;
+ if (dbgType == DBG_TYPE_SMALL) {
+ PRINTM(MFW_D, "\n");
+ DBG_HEXDUMP(MFW_D, "FWDBG",
+ (t_s8 *) ((t_u8 *) & prx_pkt->eth803_hdr +
+ SIZE_OF_DBG_STRUCT), prx_pd->rx_pkt_length);
+ PRINTM(MFW_D, "FWDBG::\n");
+ }
+ goto done;
+ }
+
+ PRINTM(MINFO, "RX Data: data_len - prx_pd->rx_pkt_offset = %d - %d = %d\n",
+ pmbuf->data_len, prx_pd->rx_pkt_offset,
+ pmbuf->data_len - prx_pd->rx_pkt_offset);
+
+ HEXDUMP("RX Data: Dest", prx_pkt->eth803_hdr.dest_addr,
+ sizeof(prx_pkt->eth803_hdr.dest_addr));
+ HEXDUMP("RX Data: Src", prx_pkt->eth803_hdr.src_addr,
+ sizeof(prx_pkt->eth803_hdr.src_addr));
+
+ if ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ snap_oui_802_h, sizeof(snap_oui_802_h)) == 0) ||
+ ((memcmp(pmadapter, &prx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ appletalk_aarp_type, sizeof(appletalk_aarp_type)) &&
+ memcmp(pmadapter, &prx_pkt->rfc1042_hdr.snap_type,
+ ipx_snap_type, sizeof(ipx_snap_type)))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype).
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ peth_hdr = (EthII_Hdr_t *)
+ ((t_u8 *) & prx_pkt->eth803_hdr
+ + sizeof(prx_pkt->eth803_hdr) + sizeof(prx_pkt->rfc1042_hdr)
+ - sizeof(prx_pkt->eth803_hdr.dest_addr)
+ - sizeof(prx_pkt->eth803_hdr.src_addr)
+ - sizeof(prx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(pmadapter, peth_hdr->src_addr, prx_pkt->eth803_hdr.src_addr,
+ sizeof(peth_hdr->src_addr));
+ memcpy(pmadapter, peth_hdr->dest_addr, prx_pkt->eth803_hdr.dest_addr,
+ sizeof(peth_hdr->dest_addr));
+
+ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+ that was removed. */
+ hdr_chop = (t_u32) ((t_ptr) peth_hdr - (t_ptr) prx_pd);
+ } else {
+ HEXDUMP("RX Data: LLC/SNAP",
+ (t_u8 *) & prx_pkt->rfc1042_hdr, sizeof(prx_pkt->rfc1042_hdr));
+
+ /* Chop off the RxPD */
+ hdr_chop = (t_u32) ((t_ptr) & prx_pkt->eth803_hdr - (t_ptr) prx_pd);
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ either the reconstructed EthII frame or the 802.2/llc/snap frame */
+ pmbuf->data_len -= hdr_chop;
+ pmbuf->data_offset += hdr_chop;
+ pmbuf->pparent = MNULL;
+
+ DBG_HEXDUMP(MDAT_D, "RxPD", (t_u8 *) prx_pd,
+ MIN(sizeof(RxPD), MAX_DATA_DUMP_LEN));
+ DBG_HEXDUMP(MDAT_D, "Rx Payload", ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
+ MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));
+
+ priv->rxpd_rate = prx_pd->rx_rate;
+
+ priv->rxpd_htinfo = prx_pd->ht_info;
+ pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
+ &pmbuf->out_ts_sec,
+ &pmbuf->out_ts_usec);
+ PRINTM(MDATA, "%lu.%06lu : Data => kernel seq_num=%d tid=%d\n",
+ pmbuf->out_ts_sec, pmbuf->out_ts_usec, prx_pd->seq_num,
+ prx_pd->priority);
+
+ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
+ if (ret == MLAN_STATUS_FAILURE) {
+ pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
+ PRINTM(MERROR, "STA Rx Error: moal_recv_packet returned error\n");
+ }
+ done:
+ if (ret != MLAN_STATUS_PENDING) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function processes the received buffer
+ *
+ * @param adapter A pointer to mlan_adapter
+ * @param pmbuf A pointer to the received buffer
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+wlan_ops_sta_process_rx_packet(IN t_void * adapter, IN pmlan_buffer pmbuf)
+{
+ pmlan_adapter pmadapter = (pmlan_adapter) adapter;
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ RxPD *prx_pd;
+ RxPacketHdr_t *prx_pkt;
+ pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
+ t_u8 ta[MLAN_MAC_ADDR_LENGTH];
+ t_u16 rx_pkt_type = 0;
+ wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
+ ENTER();
+
+ prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);
+ /* Endian conversion */
+ endian_convert_RxPD(prx_pd);
+ rx_pkt_type = prx_pd->rx_pkt_type;
+ prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+
+ if ((prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length) >
+ (t_u16) pmbuf->data_len) {
+ PRINTM(MERROR,
+ "Wrong rx packet: len=%d,rx_pkt_offset=%d,"
+ " rx_pkt_length=%d\n", pmbuf->data_len, prx_pd->rx_pkt_offset,
+ prx_pd->rx_pkt_length);
+ pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
+ ret = MLAN_STATUS_FAILURE;
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+ pmbuf->data_len = prx_pd->rx_pkt_offset + prx_pd->rx_pkt_length;
+
+ if (pmadapter->priv[pmbuf->bss_index]->mgmt_frame_passthru_mask &&
+ prx_pd->rx_pkt_type == PKT_TYPE_MGMT_FRAME) {
+ /* Check if this is mgmt packet and needs to forwarded to app as an
+ event */
+ pmgmt_pkt_hdr =
+ (wlan_mgmt_pkt *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);
+ pmgmt_pkt_hdr->frm_len = wlan_le16_to_cpu(pmgmt_pkt_hdr->frm_len);
+
+ if ((pmgmt_pkt_hdr->wlan_header.frm_ctl
+ & IEEE80211_FC_MGMT_FRAME_TYPE_MASK) == 0)
+ wlan_process_802dot11_mgmt_pkt(pmadapter->priv[pmbuf->bss_index],
+ (t_u8 *) & pmgmt_pkt_hdr->
+ wlan_header,
+ pmgmt_pkt_hdr->frm_len +
+ sizeof(wlan_mgmt_pkt)
+ - sizeof(pmgmt_pkt_hdr->frm_len));
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ goto done;
+ }
+
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if (!IS_11N_ENABLED(priv) ||
+ memcmp(priv->adapter, priv->curr_addr, prx_pkt->eth803_hdr.dest_addr,
+ MLAN_MAC_ADDR_LENGTH)) {
+ wlan_process_rx_packet(pmadapter, pmbuf);
+ goto done;
+ }
+
+ if (queuing_ra_based(priv)) {
+ memcpy(pmadapter, ta, prx_pkt->eth803_hdr.src_addr,
+ MLAN_MAC_ADDR_LENGTH);
+ } else {
+ if ((rx_pkt_type != PKT_TYPE_BAR) && (prx_pd->priority < MAX_NUM_TID))
+ priv->rx_seq[prx_pd->priority] = prx_pd->seq_num;
+ memcpy(pmadapter, ta,
+ priv->curr_bss_params.bss_descriptor.mac_address,
+ MLAN_MAC_ADDR_LENGTH);
+ }
+
+ /* Reorder and send to OS */
+ if ((ret = mlan_11n_rxreorder_pkt(priv, prx_pd->seq_num,
+ prx_pd->priority, ta,
+ (t_u8) prx_pd->rx_pkt_type,
+ (void *) pmbuf)) ||
+ (rx_pkt_type == PKT_TYPE_BAR)
+ ) {
+ wlan_free_mlan_buffer(pmadapter, pmbuf);
+ }
+
+ done:
+
+ LEAVE();
+ return (ret);
+}