diff options
Diffstat (limited to 'drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c')
-rw-r--r-- | drivers/net/wireless/sd8797/mlan/mlan_sta_rx.c | 289 |
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); +} |