Esempio n. 1
0
/** 
 *  @brief configure tx_pause settings
 *   
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @return         0 --success, otherwise fail
 */
static int
woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_ioctl_req *ioctl_req = NULL;
    mlan_ds_misc_cfg *misc = NULL;
    tx_data_pause_para param;
    int ret = 0;

    ENTER();
    memset(&param, 0, sizeof(param));

    /* Sanity check */
    if (req->ifr_data == NULL) {
        PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
        ret = -EFAULT;
        goto done;
    }
    if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
        PRINTM(MERROR, "Copy from user failed\n");
        ret = -EFAULT;
        goto done;
    }
    DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *) & param, sizeof(param));

    ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
    if (ioctl_req == NULL) {
        LEAVE();
        return -ENOMEM;
    }
    misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
    misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
    ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;

    if (!param.action) {
        /* Get Tx data pause status from MLAN */
        ioctl_req->action = MLAN_ACT_GET;
    } else {
        /* Set Tx data pause in MLAN */
        ioctl_req->action = MLAN_ACT_SET;
        misc->param.tx_datapause.tx_pause = param.txpause;
        misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
    }
    if (MLAN_STATUS_SUCCESS !=
        woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
        ret = -EFAULT;
        goto done;
    }

    param.txpause = misc->param.tx_datapause.tx_pause;
    param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;

    /* Copy to user */
    if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
        PRINTM(MERROR, "Copy to user failed!\n");
        ret = -EFAULT;
        goto done;
    }
  done:
    if (ioctl_req)
        kfree(ioctl_req);
    LEAVE();
    return ret;
}
/**
 *  @brief This function fill the txpd for tx packet
 *
 *  @param priv	   A pointer to mlan_private structure
 *  @param pmbuf   A pointer to the mlan_buffer for process
 *
 *  @return        headptr or MNULL
 */
t_void *
wlan_ops_uap_process_txpd(IN t_void *priv, IN pmlan_buffer pmbuf)
{
    pmlan_private pmpriv = (pmlan_private)priv;
    UapTxPD *plocal_tx_pd;
    t_u8 *head_ptr = MNULL;
    t_u32 pkt_type;
    t_u32 tx_control;
    ENTER();

    if (!pmbuf->data_len) {
        PRINTM(MERROR, "uAP Tx Error: Invalid packet length: %d\n",
               pmbuf->data_len);
        pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
        goto done;
    }
    if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
        memcpy(pmpriv->adapter, &pkt_type,
               pmbuf->pbuf + pmbuf->data_offset, sizeof(pkt_type));
        memcpy(pmpriv->adapter, &tx_control,
               pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
               sizeof(tx_control));
        pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
        pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
    }
    if (pmbuf->data_offset < (sizeof(UapTxPD) + INTF_HEADER_LEN +
                              DMA_ALIGNMENT)) {
        PRINTM(MERROR,
               "not enough space for UapTxPD: headroom=%d pkt_len=%d, required=%d\n",
               pmbuf->data_offset, pmbuf->data_len,
               sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
        DBG_HEXDUMP(MDAT_D, "drop pkt",
                    pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
        pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
        goto done;
    }

    /* head_ptr should be aligned */
    head_ptr =
        pmbuf->pbuf + pmbuf->data_offset - sizeof(UapTxPD) -
        INTF_HEADER_LEN;
    head_ptr = (t_u8 *)((t_ptr)head_ptr & ~((t_ptr)(DMA_ALIGNMENT - 1)));

    plocal_tx_pd = (UapTxPD *)(head_ptr + INTF_HEADER_LEN);
    memset(pmpriv->adapter, plocal_tx_pd, 0, sizeof(UapTxPD));

    /* Set the BSS number to TxPD */
    plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
    plocal_tx_pd->bss_type = pmpriv->bss_type;

    plocal_tx_pd->tx_pkt_length = (t_u16)pmbuf->data_len;

    plocal_tx_pd->priority = (t_u8)pmbuf->priority;
    plocal_tx_pd->pkt_delay_2ms =
        wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);

    if (plocal_tx_pd->priority <
            NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
        /*
         * Set the priority specific tx_control field, setting of 0 will
         *   cause the default value to be used later in this function
         */
        plocal_tx_pd->tx_control
            =
                pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->
                        priority];

    if (pmbuf->flags & MLAN_BUF_FLAG_TX_STATUS) {
        plocal_tx_pd->tx_token_id = (t_u8)pmbuf->tx_seq_num;
        plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS;
    }

    /* Offset of actual data */
    plocal_tx_pd->tx_pkt_offset =
        (t_u16)((t_ptr)pmbuf->pbuf + pmbuf->data_offset -
                (t_ptr)plocal_tx_pd);

    if (!plocal_tx_pd->tx_control) {
        /* TxCtrl set by user or default */
        plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
    }

    if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
        plocal_tx_pd->tx_pkt_type = (t_u16)pkt_type;
        plocal_tx_pd->tx_control = tx_control;
    }
    uap_endian_convert_TxPD(plocal_tx_pd);

    /* Adjust the data offset and length to include TxPD in pmbuf */
    pmbuf->data_len += pmbuf->data_offset;
    pmbuf->data_offset = (t_u32)((t_ptr)head_ptr - (t_ptr)pmbuf->pbuf);
    pmbuf->data_len -= pmbuf->data_offset;

done:
    LEAVE();
    return head_ptr;
}
/**
 *  @brief This function sends sleep confirm command to firmware.
 * 
 *  @param pmadapter  A pointer to mlan_adapter structure
 *
 *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter)
{
    mlan_status ret = MLAN_STATUS_SUCCESS;
    static t_u32 i = 0;
    t_u16 cmd_len = 0;
    HostCmd_DS_802_11_PS_MODE_ENH *pps_mode = MNULL;
    opt_sleep_confirm_buffer *sleep_cfm_buf =
        (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf +
                                      pmadapter->psleep_cfm->data_offset);

    ENTER();

    if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type ==
        MLAN_BSS_TYPE_STA) {
        cmd_len = sizeof(HostCmd_DS_COMMAND);
        pps_mode = &sleep_cfm_buf->ps_cfm_sleep.params.psmode_enh;
        sleep_cfm_buf->ps_cfm_sleep.seq_num =
            wlan_cpu_to_le16(++pmadapter->seq_num);
        pps_mode->params.sleep_cfm.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED);
        DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep, cmd_len);
    }

    /* Send sleep confirm command to firmware */
    pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN;
    ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD,
                                 pmadapter->psleep_cfm, MNULL);
    if (ret == MLAN_STATUS_FAILURE) {
        PRINTM(MERROR, "SLEEP_CFM: failed\n");
        pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
        goto done;
    } else {
        if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type ==
            MLAN_BSS_TYPE_STA) {
            if (!pps_mode->params.sleep_cfm.resp_ctrl) {
                /* Response is not needed for sleep confirm command */
                pmadapter->ps_state = PS_STATE_SLEEP;
            } else {
                pmadapter->ps_state = PS_STATE_SLEEP_CFM;
            }

            if (pps_mode->params.sleep_cfm.resp_ctrl != RESP_NEEDED
                && (pmadapter->is_hs_configured &&
                    !pmadapter->sleep_period.period)) {
                pmadapter->pm_wakeup_card_req = MTRUE;
                wlan_host_sleep_activated_event(wlan_get_priv
                                                (pmadapter, MLAN_BSS_TYPE_STA),
                                                MTRUE);
            }
        }
#define NUM_SC_PER_LINE         16
        if (++i % NUM_SC_PER_LINE == 0)
            PRINTM(MEVENT, "+\n");
        else
            PRINTM(MEVENT, "+");
    }

  done:
    LEAVE();
    return ret;
}
Esempio n. 4
0
/** 
 *  @brief uap addba reject tbl 
 *   
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @return         0 --success, otherwise fail
 */
static int
woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_ioctl_req *ioctl_req = NULL;
    mlan_ds_11n_cfg *cfg_11n = NULL;
    addba_reject_para param;
    int ret = 0;
    int i = 0;

    ENTER();
    memset(&param, 0, sizeof(param));

    /* Sanity check */
    if (req->ifr_data == NULL) {
        PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
        ret = -EFAULT;
        goto done;
    }
    if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
        PRINTM(MERROR, "Copy from user failed\n");
        ret = -EFAULT;
        goto done;
    }
    DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param));

    ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
    if (ioctl_req == NULL) {
        LEAVE();
        return -ENOMEM;
    }
    cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
    cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
    ioctl_req->req_id = MLAN_IOCTL_11N_CFG;

    if (!param.action) {
        /* Get addba_reject tbl from MLAN */
        ioctl_req->action = MLAN_ACT_GET;
    } else {
        /* Set addba_reject tbl in MLAN */
        ioctl_req->action = MLAN_ACT_SET;
        for (i = 0; i < MAX_NUM_TID; i++) {
            cfg_11n->param.addba_reject[i] = param.addba_reject[i];
        }
    }
    if (MLAN_STATUS_SUCCESS !=
        woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
        ret = -EFAULT;
        goto done;
    }
    for (i = 0; i < MAX_NUM_TID; i++) {
        param.addba_reject[i] = cfg_11n->param.addba_reject[i];
    }
    /* Copy to user */
    if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
        PRINTM(MERROR, "Copy to user failed!\n");
        ret = -EFAULT;
        goto done;
    }
  done:
    if (ioctl_req)
        kfree(ioctl_req);
    LEAVE();
    return ret;
}
/** 
 *  @brief Transfer firmware to card
 *  
 *  @param priv      A Pointer to bt_private structure
 *  @return 	     BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no.	
 */
static int
sd_init_fw_dpc(bt_private * priv)
{
    struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
    u8 *firmware = NULL;
    int firmwarelen;
    u8 base0;
    u8 base1;
    int ret = BT_STATUS_SUCCESS;
    int offset;
    void *tmpfwbuf = NULL;
    int tmpfwbufsz;
    u8 *fwbuf;
    u16 len;
    int txlen = 0;
    int tx_blocks = 0;
    int i = 0;
    int tries = 0;
#ifdef FW_DOWNLOAD_SPEED
    u32 tv1, tv2;
#endif
    u8 crc_buffer = 0;

    ENTER();
    firmware = (u8 *) priv->firmware->data;
    firmwarelen = priv->firmware->size;

    PRINTM(INFO, "BT: Downloading FW image (%d bytes)\n", firmwarelen);

#ifdef FW_DOWNLOAD_SPEED
    tv1 = get_utimeofday();
#endif

    tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, DMA_ALIGNMENT);
    tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
    if (!tmpfwbuf) {
        PRINTM(ERROR,
               "BT: Unable to allocate buffer for firmware. Terminating download\n");
        ret = BT_STATUS_FAILURE;
        goto done;
    }
    memset(tmpfwbuf, 0, tmpfwbufsz);
    /* Ensure 8-byte aligned firmware buffer */
    fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);

    if (!(priv->fw_crc_check)) {
        /* CRC check not required, use custom header first */
        firmware = fw_crc_header;
        firmwarelen = FW_CRC_HEADER;
        crc_buffer = 1;
    }

    /* Perform firmware data transfer */
    offset = 0;
    do {
        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
        ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
        if (ret < 0) {
            PRINTM(FATAL,
                   "BT: FW download with helper poll status timeout @ %d\n",
                   offset);
            goto done;
        }

        if (!crc_buffer)
            /* More data? */
            if (offset >= firmwarelen)
                break;

        for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
            base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret);
            if (ret) {
                PRINTM(WARN, "Dev BASE0 register read failed:"
                       " base0=0x%04X(%d). Terminating download\n", base0,
                       base0);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret);
            if (ret) {
                PRINTM(WARN, "Dev BASE1 register read failed:"
                       " base1=0x%04X(%d). Terminating download\n", base1,
                       base1);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            len = (((u16) base1) << 8) | base0;

            if (len != 0)
                break;
            udelay(10);
        }

        if (len == 0)
            break;
        else if (len > BT_UPLD_SIZE) {
            PRINTM(FATAL, "BT: FW download failure @ %d, invalid length %d\n",
                   offset, len);
            ret = BT_STATUS_FAILURE;
            goto done;
        }

        txlen = len;

        if (len & BIT(0)) {
            i++;
            if (i > MAX_WRITE_IOMEM_RETRY) {
                PRINTM(FATAL,
                       "BT: FW download failure @ %d, over max retry count\n",
                       offset);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            PRINTM(ERROR, "BT: FW CRC error indicated by the helper:"
                   " len = 0x%04X, txlen = %d\n", len, txlen);
            len &= ~BIT(0);

            PRINTM(ERROR, "BT: retry: %d, offset %d\n", i, offset);
            DBG_HEXDUMP(ERROR, "BT: FW block:", fwbuf, len);

            /* Setting this to 0 to resend from same offset */
            txlen = 0;
        } else {
            i = 0;

            /* Set blocksize to transfer - checking for last block */
            if (firmwarelen - offset < txlen)
                txlen = firmwarelen - offset;

            PRINTM(INFO, ".");

            tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;

            /* Copy payload to buffer */
            memcpy(fwbuf, &firmware[offset], txlen);
        }

        /* Send data */
        ret =
            sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf,
                         tx_blocks * SD_BLOCK_SIZE_FW_DL);

        if (ret < 0) {
            PRINTM(ERROR, "BT: FW download, write iomem (%d) failed @ %d\n", i,
                   offset);
            sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
            if (ret)
                PRINTM(ERROR, "write ioreg failed (CFG)\n");
        }

        offset += txlen;
        if (crc_buffer) {
            if (offset >= FW_CRC_HEADER) {
                /* Custom header download complete, restore original FW */
                offset = 0;
                firmware = (u8 *) priv->firmware->data;
                firmwarelen = priv->firmware->size;
                crc_buffer = 0;
            }
        }
    } while (TRUE);

    PRINTM(INFO, "\nBT: FW download over, size %d bytes\n", offset);

    ret = BT_STATUS_SUCCESS;
  done:
#ifdef FW_DOWNLOAD_SPEED
    tv2 = get_utimeofday();
    PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
           (tv1 % 1000000) / 1000, tv1 % 1000);
    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
           (tv2 % 1000000) / 1000, tv2 % 1000);
    tv2 -= tv1;
    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
           (tv2 % 1000000) / 1000, tv2 % 1000);
#endif
    if (tmpfwbuf)
        kfree(tmpfwbuf);
    LEAVE();
    return ret;
}
Esempio n. 6
0
/** 
 *  @brief This function checks the conditions and sends packet to device 
 *  
 *  @param priv	   A pointer to mlan_private structure
 *  @param pmbuf   A pointer to the mlan_buffer for process
 *  @param tx_param A pointer to mlan_tx_param structure
 *
 *  @return 	   mlan_status
 */
mlan_status
wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
                mlan_tx_param * tx_param)
{
    mlan_status ret = MLAN_STATUS_SUCCESS;
    pmlan_adapter pmadapter = priv->adapter;
    t_u8 *head_ptr = MNULL;
    t_u32 sec, usec;
#ifdef STA_SUPPORT
    TxPD *plocal_tx_pd = MNULL;
#endif

    ENTER();

    head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf);
    if (!head_ptr) {
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }
#ifdef STA_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
        plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN);
#endif
    ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param);
  done:
    switch (ret) {
    case MLAN_STATUS_RESOURCE:
#ifdef STA_SUPPORT
        if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
            pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
            pmadapter->tx_lock_flag = MFALSE;
            plocal_tx_pd->flags = 0;
        }
#endif
        PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
        break;
    case MLAN_STATUS_FAILURE:
        pmadapter->data_sent = MFALSE;
        PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
        pmadapter->dbg.num_tx_host_to_card_failure++;
        wlan_write_data_complete(pmadapter, pmbuf, ret);
        break;
    case MLAN_STATUS_PENDING:
        pmadapter->data_sent = MFALSE;
        break;
    case MLAN_STATUS_SUCCESS:
        wlan_write_data_complete(pmadapter, pmbuf, ret);
        break;
    default:
        break;
    }

    if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
        pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
                                                  &usec);
        PRINTM(MDATA, "%lu.%lu : Data => FW\n", sec, usec);

        DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN,
                    MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
    }
    LEAVE();
    return ret;
}
/**
 *  @brief This function handles events generated by firmware
 *
 *  @param priv A pointer to mlan_private structure
 *
 *  @return     MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_ops_sta_process_event(IN t_void * priv)
{
	pmlan_private pmpriv = (pmlan_private) priv;
	pmlan_adapter pmadapter = pmpriv->adapter;
	mlan_status ret = MLAN_STATUS_SUCCESS;
	t_u32 eventcause = pmadapter->event_cause;
	t_u8 event_buf[100];
	t_u8 *evt_buf = MNULL;
	pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
	t_u16 reason_code;
	pmlan_callbacks pcb = &pmadapter->callbacks;
	mlan_event *pevent = (mlan_event *) event_buf;

	ENTER();

	/* Event length check */
	if ((pmbuf->data_len - sizeof(eventcause)) > MAX_EVENT_SIZE) {
		pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
		LEAVE();
		return MLAN_STATUS_FAILURE;
	}

	if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE &&
	    pmbuf->data_len > sizeof(eventcause))
		DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
			    pmbuf->data_len);

	switch (eventcause) {
	case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
		PRINTM(MERROR,
		       "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
		break;
	case EVENT_LINK_SENSED:
		PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
		pmpriv->adhoc_is_link_sensed = MTRUE;
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED,
				MNULL);
		break;

	case EVENT_DEAUTHENTICATED:
		if (pmpriv->wps.session_enable) {
			PRINTM(MMSG,
			       "wlan: Recevie deauth event in wps session\n");
			break;
		}
		reason_code =
			*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset +
				    sizeof(eventcause));
		PRINTM(MMSG, "wlan: EVENT: Deauthenticated (reason 0x%x)\n",
		       reason_code);
		pmadapter->dbg.num_event_deauth++;
		wlan_handle_disconnect_event(pmpriv);

		break;

	case EVENT_DISASSOCIATED:
		if (pmpriv->wps.session_enable) {
			PRINTM(MMSG,
			       "wlan: Recevie disassociate event in wps session\n");
			break;
		}
		reason_code =
			*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset +
				    sizeof(eventcause));
		PRINTM(MMSG, "wlan: EVENT: Disassociated (reason 0x%x)\n",
		       reason_code);
		pmadapter->dbg.num_event_disassoc++;
		wlan_handle_disconnect_event(pmpriv);
		break;

	case EVENT_LINK_LOST:
		reason_code =
			*(t_u16 *) (pmbuf->pbuf + pmbuf->data_offset +
				    sizeof(eventcause));
		PRINTM(MMSG, "wlan: EVENT: Link lost (reason 0x%x)\n",
		       reason_code);
		pmadapter->dbg.num_event_link_lost++;
		wlan_handle_disconnect_event(pmpriv);
		break;

	case EVENT_PS_SLEEP:
		PRINTM(MINFO, "EVENT: SLEEP\n");
		PRINTM(MEVENT, "_");

		/* Handle unexpected PS SLEEP event */
		if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
			break;
		pmadapter->ps_state = PS_STATE_PRE_SLEEP;

		wlan_check_ps_cond(pmadapter);
		break;

	case EVENT_PS_AWAKE:
		PRINTM(MINFO, "EVENT: AWAKE\n");
		PRINTM(MEVENT, "|");
		if (!pmadapter->pps_uapsd_mode &&
		    pmpriv->media_connected &&
		    (pmpriv->port_open || !pmpriv->port_ctrl_mode) &&
		    pmadapter->sleep_period.period) {
			pmadapter->pps_uapsd_mode = MTRUE;
			PRINTM(MEVENT, "PPS/UAPSD mode activated\n");
		}
		/* Handle unexpected PS AWAKE event */
		if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
			break;
		pmadapter->tx_lock_flag = MFALSE;
		if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) {
			if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
				if (!pmadapter->data_sent) {
					if (wlan_send_null_packet(pmpriv,
								  MRVDRV_TxPD_POWER_MGMT_NULL_PACKET
								  |
								  MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
					    == MLAN_STATUS_SUCCESS) {
						LEAVE();
						return MLAN_STATUS_SUCCESS;
					}
				}
			}
		}
		pmadapter->ps_state = PS_STATE_AWAKE;
		pmadapter->pm_wakeup_card_req = MFALSE;
		pmadapter->pm_wakeup_fw_try = MFALSE;
		break;

	case EVENT_HS_ACT_REQ:
		PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
		ret = wlan_prepare_cmd(priv,
				       HostCmd_CMD_802_11_HS_CFG_ENH,
				       0, 0, MNULL, MNULL);
		break;

	case EVENT_MIC_ERR_UNICAST:
		PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
		break;

	case EVENT_MIC_ERR_MULTICAST:
		PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
		break;
	case EVENT_MIB_CHANGED:
	case EVENT_INIT_DONE:
		break;

	case EVENT_ADHOC_BCN_LOST:
		PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
		pmpriv->adhoc_is_link_sensed = MFALSE;
		wlan_clean_txrx(pmpriv);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST,
				MNULL);
		break;

	case EVENT_FW_DEBUG_INFO:
		/* Allocate memory for event buffer */
		ret = pcb->moal_malloc(pmadapter->pmoal_handle,
				       MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf);
		if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
			pevent = (pmlan_event) evt_buf;
			pevent->bss_index = pmpriv->bss_index;
			PRINTM(MEVENT, "EVENT: FW Debug Info\n");
			pevent->event_id = MLAN_EVENT_ID_FW_DEBUG_INFO;
			pevent->event_len =
				pmbuf->data_len - sizeof(eventcause);
			memcpy(pmadapter, (t_u8 *) pevent->event_buf,
			       pmbuf->pbuf + pmbuf->data_offset +
			       sizeof(eventcause), pevent->event_len);
			wlan_recv_event(pmpriv, pevent->event_id, pevent);
			pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
		}
		break;

	case EVENT_BG_SCAN_REPORT:
		PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
		pmadapter->bgscan_reported = MTRUE;
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN, MNULL);
		break;
	case EVENT_BG_SCAN_STOPPED:
		PRINTM(MEVENT, "EVENT: BGS_STOPPED\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BG_SCAN_STOPPED,
				MNULL);
		break;

	case EVENT_PORT_RELEASE:
		PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
		/* Open the port for e-supp mode */
		if (pmpriv->port_ctrl_mode == MTRUE) {
			PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
			pmpriv->port_open = MTRUE;
		}
		pmadapter->scan_block = MFALSE;
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
		break;

	case EVENT_STOP_TX:
		PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
		wlan_11h_tx_disable(pmpriv);	/* this fn will send event up
						   to MOAL */
		break;
	case EVENT_START_TX:
		PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
		wlan_11h_tx_enable(pmpriv);	/* this fn will send event up
						   to MOAL */
		break;
	case EVENT_CHANNEL_SWITCH:
		PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
		/* To be handled for 'chanswann' private command */
		break;
	case EVENT_CHANNEL_SWITCH_ANN:
		PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n");
		/* Here, pass up event first, as handling will send deauth */
		wlan_recv_event(pmpriv,
				MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, MNULL);
		wlan_11h_handle_event_chanswann(pmpriv);
		break;
	case EVENT_RADAR_DETECTED:
		PRINTM(MEVENT, "EVENT: Radar Detected\n");

		/* Send as passthru first, this event can cause other events */
		memset(pmadapter, pevent, 0x00, sizeof(event_buf));
		pevent->bss_index = pmpriv->bss_index;
		pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
		pevent->event_len = pmbuf->data_len;
		memcpy(pmadapter, (t_u8 *) pevent->event_buf,
		       pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
		wlan_recv_event(pmpriv, pevent->event_id, pevent);

		if (pmadapter->state_rdh.stage == RDH_OFF) {
			pmadapter->state_rdh.stage = RDH_CHK_INTFS;
			wlan_11h_radar_detected_handling(pmadapter);
		} else {
			PRINTM(MEVENT, "Ignore Event Radar Detected - handling"
			       " already in progress.\n");
		}

		break;

	case EVENT_CHANNEL_REPORT_RDY:
		PRINTM(MEVENT, "EVENT: Channel Report Ready\n");
		/* Allocate memory for event buffer */
		ret = pcb->moal_malloc(pmadapter->pmoal_handle,
				       MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf);
		if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
			memset(pmadapter, evt_buf, 0x00, MAX_EVENT_SIZE);
			/* Setup event buffer */
			pevent = (pmlan_event) evt_buf;
			pevent->bss_index = pmpriv->bss_index;
			pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY;
			pevent->event_len =
				pmbuf->data_len - sizeof(eventcause);
			/* Copy event data */
			memcpy(pmadapter, (t_u8 *) pevent->event_buf,
			       pmbuf->pbuf + pmbuf->data_offset +
			       sizeof(eventcause), pevent->event_len);
			/* Handle / pass event data */
			ret = wlan_11h_handle_event_chanrpt_ready(pmpriv,
								  pevent);

			/* Also send this event as passthru */
			pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
			pevent->event_len = pmbuf->data_len;
			memcpy(pmadapter, (t_u8 *) pevent->event_buf,
			       pmbuf->pbuf + pmbuf->data_offset,
			       pevent->event_len);
			wlan_recv_event(pmpriv, pevent->event_id, pevent);
			/* Now done with buffer */
			pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
		}
		/* Send up this Event to unblock MOAL waitqueue */
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL);
		break;
	case EVENT_EXT_SCAN_REPORT:
		PRINTM(MEVENT, "EVENT: EXT_SCAN Report (%d)\n",
		       pmbuf->data_len);
		if (pmadapter->pscan_ioctl_req && pmadapter->ext_scan)
			ret = wlan_handle_event_ext_scan_report(priv, pmbuf);
		break;
	case EVENT_MEAS_REPORT_RDY:
		PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n",
		       eventcause);
		ret = wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
				       HostCmd_ACT_GEN_SET, 0, 0, MNULL);
		break;
	case EVENT_WMM_STATUS_CHANGE:
		if (pmbuf && pmbuf->data_len
		    > sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) {
			PRINTM(MEVENT, "EVENT: WMM status changed: %d\n",
			       pmbuf->data_len);

			evt_buf = (pmbuf->pbuf
				   + pmbuf->data_offset + sizeof(eventcause));

			wlan_ret_wmm_get_status(pmpriv,
						evt_buf,
						pmbuf->data_len -
						sizeof(eventcause));
		} else {
			PRINTM(MEVENT, "EVENT: WMM status changed\n");
			ret = wlan_cmd_wmm_status_change(pmpriv);
		}
		break;

	case EVENT_RSSI_LOW:
		PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL);
		break;
	case EVENT_SNR_LOW:
		PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
		break;
	case EVENT_MAX_FAIL:
		PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
		break;
	case EVENT_RSSI_HIGH:
		PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL);
		break;
	case EVENT_SNR_HIGH:
		PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
		break;
	case EVENT_DATA_RSSI_LOW:
		PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
		break;
	case EVENT_DATA_SNR_LOW:
		PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
		break;
	case EVENT_DATA_RSSI_HIGH:
		PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
		break;
	case EVENT_DATA_SNR_HIGH:
		PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
		break;
	case EVENT_LINK_QUALITY:
		PRINTM(MEVENT, "EVENT: Link Quality\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
		break;
	case EVENT_PRE_BEACON_LOST:
		PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
		break;
	case EVENT_IBSS_COALESCED:
		PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
		ret = wlan_prepare_cmd(pmpriv,
				       HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
				       HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
		break;
	case EVENT_ADDBA:
		PRINTM(MEVENT, "EVENT: ADDBA Request\n");
		if (pmpriv->media_connected == MTRUE)
			ret = wlan_prepare_cmd(pmpriv,
					       HostCmd_CMD_11N_ADDBA_RSP,
					       HostCmd_ACT_GEN_SET, 0, MNULL,
					       pmadapter->event_body);
		else
			PRINTM(MERROR,
			       "Ignore ADDBA Request event in disconnected state\n");
		break;
	case EVENT_DELBA:
		PRINTM(MEVENT, "EVENT: DELBA Request\n");
		if (pmpriv->media_connected == MTRUE)
			wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
		else
			PRINTM(MERROR,
			       "Ignore DELBA Request event in disconnected state\n");
		break;
	case EVENT_BA_STREAM_TIMEOUT:
		PRINTM(MEVENT, "EVENT:  BA Stream timeout\n");
		if (pmpriv->media_connected == MTRUE)
			wlan_11n_ba_stream_timeout(pmpriv,
						   (HostCmd_DS_11N_BATIMEOUT *)
						   pmadapter->event_body);
		else
			PRINTM(MERROR,
			       "Ignore BA Stream timeout event in disconnected state\n");
		break;
	case EVENT_RXBA_SYNC:
		PRINTM(MEVENT, "EVENT:  RXBA_SYNC\n");
		wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
					 pmbuf->data_len - sizeof(eventcause));
		break;
	case EVENT_AMSDU_AGGR_CTRL:
		PRINTM(MEVENT, "EVENT:  AMSDU_AGGR_CTRL %d\n",
		       *(t_u16 *) pmadapter->event_body);
		pmadapter->tx_buf_size =
			MIN(pmadapter->curr_tx_buf_size,
			    wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
		PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
		break;

	case EVENT_WEP_ICV_ERR:
		PRINTM(MEVENT, "EVENT: WEP ICV error\n");
		pevent->bss_index = pmpriv->bss_index;
		pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
		pevent->event_len = sizeof(Event_WEP_ICV_ERR);
		memcpy(pmadapter, (t_u8 *) pevent->event_buf,
		       pmadapter->event_body, pevent->event_len);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
		break;

	case EVENT_BW_CHANGE:
		PRINTM(MEVENT, "EVENT: BW Change\n");
		pevent->bss_index = pmpriv->bss_index;
		pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
		pevent->event_len = sizeof(t_u8);
		/* Copy event body from the event buffer */
		memcpy(pmadapter, (t_u8 *) pevent->event_buf,
		       pmadapter->event_body, pevent->event_len);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
		break;

#ifdef WIFI_DIRECT_SUPPORT
	case EVENT_WIFIDIRECT_GENERIC_EVENT:
		PRINTM(MEVENT, "EVENT: WIFIDIRECT event %d\n", eventcause);
		/* Allocate memory for event buffer */
		ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
				       MLAN_MEM_DEF, &evt_buf);
		if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
			pevent = (pmlan_event) evt_buf;
			pevent->bss_index = pmpriv->bss_index;
			pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
			pevent->event_len = pmbuf->data_len;
			memcpy(pmadapter, (t_u8 *) pevent->event_buf,
			       pmbuf->pbuf + pmbuf->data_offset,
			       pevent->event_len);
			wlan_recv_event(pmpriv, pevent->event_id, pevent);
			pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
		}
		break;
	case EVENT_WIFIDIRECT_SERVICE_DISCOVERY:
		PRINTM(MEVENT, "EVENT: WIFIDIRECT service discovery event %d\n",
		       eventcause);
		/* Allocate large memory for service discovery */
		if (pmbuf->data_len < MAX_EVENT_SIZE)
			ret = pcb->moal_malloc(pmadapter->pmoal_handle,
					       MAX_EVENT_SIZE, MLAN_MEM_DEF,
					       &evt_buf);
		else
			ret = pcb->moal_malloc(pmadapter->pmoal_handle,
					       MAX_EVENT_SIZE * 2, MLAN_MEM_DEF,
					       &evt_buf);
		if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
			pevent = (pmlan_event) evt_buf;
			pevent->bss_index = pmpriv->bss_index;
			pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
			pevent->event_len = pmbuf->data_len;
			memcpy(pmadapter, (t_u8 *) pevent->event_buf,
			       pmbuf->pbuf + pmbuf->data_offset,
			       pevent->event_len);
			wlan_recv_event(pmpriv, pevent->event_id, pevent);
			pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
		}
		break;
	case EVENT_REMAIN_ON_CHANNEL_EXPIRED:
		PRINTM(MEVENT, "EVENT: REMAIN_ON_CHANNEL_EXPIRED reason=%d\n",
		       *(t_u16 *) pmadapter->event_body);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED,
				MNULL);
		break;
#endif /* WIFI_DIRECT_SUPPORT */

	case EVENT_SAD_REPORT:
		{
			t_u8 *pevt_dat =
				pmbuf->pbuf + pmbuf->data_offset +
				sizeof(t_u32);
			PRINTM(MEVENT,
			       "EVENT: Antenna Diversity %d  (%d, %d, %d, %d)\n",
			       eventcause, pevt_dat[0] + 1, pevt_dat[1] + 1,
			       pevt_dat[2], pevt_dat[3]);
		}
		break;

	default:
		PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
		wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
		break;
	}

	LEAVE();
	return ret;
}
/**
 *  @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;
    t_u32 bss_num = 0;
    pmlan_private priv = pmadapter->priv[0];
    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 };

    ENTER();
    prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset);

    pmbuf->bss_num = bss_num;

    prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);

    DBG_HEXDUMP(DAT_D, "Rx", pmbuf->pbuf + pmbuf->data_offset,
                MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));

/** Rx packet type debugging */
#define RX_PKT_TYPE_DEBUG  0xEF
/** Small debug type */
#define DBG_TYPE_SMALL  2
/** Size of debugging structure */
#define SIZE_OF_DBG_STRUCT 4
    if (prx_pd->rx_pkt_type == RX_PKT_TYPE_DEBUG) {
        t_u8 dbgType;
        dbgType = *(t_u8 *) & prx_pkt->eth803_hdr;
        if (dbgType == DBG_TYPE_SMALL) {
            PRINTM(FW_D, "\n");
            DBG_HEXDUMP(FW_D, "FWDBG",
                        (t_s8 *) ((t_u8 *) & prx_pkt->eth803_hdr +
                                  SIZE_OF_DBG_STRUCT), prx_pd->rx_pkt_length);
            PRINTM(FW_D, "FWDBG::\n");
        }
        goto done;
    }

    PRINTM(INFO, "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(&prx_pkt->rfc1042_hdr,
                rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
        /* 
         *  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(peth_hdr->src_addr, prx_pkt->eth803_hdr.src_addr,
               sizeof(peth_hdr->src_addr));
        memcpy(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_u8 *) peth_hdr - (t_u8 *) 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_u8 *) & prx_pkt->eth803_hdr - (t_u8 *) 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;

    priv->rxpd_rate = prx_pd->rx_rate;
    priv->rxpd_htinfo = prx_pd->ht_info;

    ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
    if (ret == MLAN_STATUS_FAILURE) {
        PRINTM(ERROR, "RX Error: moal_recv_packet" " returns failure\n");
    }

    pmadapter->callbacks.moal_get_system_time(&pmbuf->out_ts_sec,
                                              &pmbuf->out_ts_usec);
    PRINTM(DATA, "%lu.%lu : Data => kernel\n", pmbuf->out_ts_sec,
           pmbuf->out_ts_usec);

    if (ret != MLAN_STATUS_PENDING) {
        pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
                                                MLAN_USB_EP_DATA, ret);
    }

  done:
    LEAVE();

    return ret;
}
Esempio n. 9
0
/** 
 *  @brief configure deep sleep 
 *   
 *  @param dev      A pointer to net_device structure
 *  @param req      A pointer to ifreq structure
 *  @return         0 --success, otherwise fail
 */
static int
woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    mlan_ioctl_req *ioctl_req = NULL;
    mlan_ds_pm_cfg *pm = NULL;
    deep_sleep_para param;
    int ret = 0;

    ENTER();
    memset(&param, 0, sizeof(param));

    /* Sanity check */
    if (req->ifr_data == NULL) {
        PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
        ret = -EFAULT;
        goto done;
    }
    if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
        PRINTM(MERROR, "Copy from user failed\n");
        ret = -EFAULT;
        goto done;
    }
    DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param));

    ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
    if (ioctl_req == NULL) {
        LEAVE();
        return -ENOMEM;
    }
    pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
    pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
    ioctl_req->req_id = MLAN_IOCTL_PM_CFG;

    if (!param.action) {
        /* Get deep_sleep status from MLAN */
        ioctl_req->action = MLAN_ACT_GET;
    } else {
        /* Set deep_sleep in MLAN */
        ioctl_req->action = MLAN_ACT_SET;
        if (param.deep_sleep == MTRUE) {
            pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
            pm->param.auto_deep_sleep.idletime = param.idle_time;
        } else {
            pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
        }
    }
    if (MLAN_STATUS_SUCCESS !=
        woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
        ret = -EFAULT;
        goto done;
    }
    if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
        param.deep_sleep = MTRUE;
    else
        param.deep_sleep = MFALSE;
    param.idle_time = pm->param.auto_deep_sleep.idletime;
    /* Copy to user */
    if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
        PRINTM(MERROR, "Copy to user failed!\n");
        ret = -EFAULT;
        goto done;
    }
  done:
    if (ioctl_req)
        kfree(ioctl_req);
    LEAVE();
    return ret;
}
/**
 *  @brief This function process tdls action frame
 *
 *  @param priv        A pointer to mlan_private structure
 *  @param pbuf        A pointer to tdls action frame buffer
 *  @param len         len of tdls action frame buffer
 *  @return            N/A
 */
void
wlan_process_tdls_action_frame(pmlan_private priv, t_u8 *pbuf, t_u32 len)
{
	sta_node *sta_ptr = MNULL;
	t_u8 *peer;
	t_u8 *pos, *end;
	t_u8 action;
	int ie_len = 0;
	t_u8 i;

#define TDLS_PAYLOAD_TYPE     2
#define TDLS_CATEGORY         0x0c
#define TDLS_REQ_FIX_LEN      6
#define TDLS_RESP_FIX_LEN     8
#define TDLS_CONFIRM_FIX_LEN  6
	if (len < (sizeof(EthII_Hdr_t) + 3))
		return;
	if (*(t_u8 *)(pbuf + sizeof(EthII_Hdr_t)) != TDLS_PAYLOAD_TYPE)
		/* TDLS payload type = 2 */
		return;
	if (*(t_u8 *)(pbuf + sizeof(EthII_Hdr_t) + 1) != TDLS_CATEGORY)
		/* TDLS category = 0xc */
		return;
	peer = pbuf + MLAN_MAC_ADDR_LENGTH;

	action = *(t_u8 *)(pbuf + sizeof(EthII_Hdr_t) + 2);
	/* 2= payload type + category */

	if (action > TDLS_SETUP_CONFIRM) {
		/* just handle TDLS setup request/response/confirm */
		PRINTM(MMSG, "Recv TDLS Action: peer=" MACSTR ", action=%d\n",
		       MAC2STR(peer), action);
		return;
	}

	sta_ptr = wlan_add_station_entry(priv, peer);
	if (!sta_ptr)
		return;
	if (action == TDLS_SETUP_REQUEST) {	/* setup request */
		sta_ptr->status = TDLS_NOT_SETUP;
		PRINTM(MMSG, "Recv TDLS SETUP Request: peer=" MACSTR "\n",
		       MAC2STR(peer));
		wlan_hold_tdls_packets(priv, peer);
		if (len < (sizeof(EthII_Hdr_t) + TDLS_REQ_FIX_LEN))
			return;
		pos = pbuf + sizeof(EthII_Hdr_t) + 4;
		/* payload 1+ category 1 + action 1 +dialog 1 */
		sta_ptr->capability = mlan_ntohs(*(t_u16 *)pos);
		ie_len = len - sizeof(EthII_Hdr_t) - TDLS_REQ_FIX_LEN;
		pos += 2;
	} else if (action == 1) {	/* setup respons */
		PRINTM(MMSG, "Recv TDLS SETUP Response: peer=" MACSTR "\n",
		       MAC2STR(peer));
		if (len < (sizeof(EthII_Hdr_t) + TDLS_RESP_FIX_LEN))
			return;
		pos = pbuf + sizeof(EthII_Hdr_t) + 6;
		/* payload 1+ category 1 + action 1 +dialog 1 +status 2 */
		sta_ptr->capability = mlan_ntohs(*(t_u16 *)pos);
		ie_len = len - sizeof(EthII_Hdr_t) - TDLS_RESP_FIX_LEN;
		pos += 2;
	} else {		/* setup confirm */
		PRINTM(MMSG, "Recv TDLS SETUP Confirm: peer=" MACSTR "\n",
		       MAC2STR(peer));
		if (len < (sizeof(EthII_Hdr_t) + TDLS_CONFIRM_FIX_LEN))
			return;
		pos = pbuf + sizeof(EthII_Hdr_t) + TDLS_CONFIRM_FIX_LEN;
		/* payload 1+ category 1 + action 1 +dialog 1 + status 2 */
		ie_len = len - sizeof(EthII_Hdr_t) - TDLS_CONFIRM_FIX_LEN;
	}
	for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
		if (pos + 2 + pos[1] > end)
			break;
		switch (*pos) {
		case SUPPORTED_RATES:
			sta_ptr->rate_len = pos[1];
			for (i = 0; i < pos[1]; i++)
				sta_ptr->support_rate[i] = pos[2 + i];
			break;
		case EXTENDED_SUPPORTED_RATES:
			for (i = 0; i < pos[1]; i++)
				sta_ptr->support_rate[sta_ptr->rate_len + i] =
					pos[2 + i];
			sta_ptr->rate_len += pos[1];
			break;
		case HT_CAPABILITY:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->HTcap, pos,
			       sizeof(IEEEtypes_HTCap_t));
			sta_ptr->is_11n_enabled = 1;
			DBG_HEXDUMP(MDAT_D, "TDLS HT capability",
				    (t_u8 *)(&sta_ptr->HTcap),
				    MIN(sizeof(IEEEtypes_HTCap_t),
					MAX_DATA_DUMP_LEN));
			break;
		case HT_OPERATION:
			memcpy(priv->adapter, &sta_ptr->HTInfo, pos,
			       sizeof(IEEEtypes_HTInfo_t));
			DBG_HEXDUMP(MDAT_D, "TDLS HT info",
				    (t_u8 *)(&sta_ptr->HTInfo),
				    MIN(sizeof(IEEEtypes_HTInfo_t),
					MAX_DATA_DUMP_LEN));
			break;
		case BSSCO_2040:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->BSSCO_20_40,
			       pos, sizeof(IEEEtypes_2040BSSCo_t));
			break;
		case EXT_CAPABILITY:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->ExtCap, pos,
			       pos[1] + sizeof(IEEEtypes_Header_t));
			DBG_HEXDUMP(MDAT_D, "TDLS Extended capability",
				    (t_u8 *)(&sta_ptr->ExtCap),
				    sta_ptr->ExtCap.ieee_hdr.len + 2);
			break;
		case RSN_IE:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->rsn_ie, pos,
			       pos[1] + sizeof(IEEEtypes_Header_t));
			DBG_HEXDUMP(MDAT_D, "TDLS Rsn ie ",
				    (t_u8 *)(&sta_ptr->rsn_ie),
				    pos[1] + sizeof(IEEEtypes_Header_t));
			break;
		case QOS_INFO:
			sta_ptr->qos_info = pos[2];
			PRINTM(MDAT_D, "TDLS qos info %x\n", sta_ptr->qos_info);
			break;
		case LINK_ID:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->link_ie, pos,
			       sizeof(IEEEtypes_LinkIDElement_t));
			break;

		case VHT_CAPABILITY:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->vht_cap, pos,
			       sizeof(IEEEtypes_VHTCap_t));
			sta_ptr->is_11ac_enabled = 1;
			DBG_HEXDUMP(MDAT_D, "TDLS VHT capability",
				    (t_u8 *)(&sta_ptr->vht_cap),
				    MIN(sizeof(IEEEtypes_VHTCap_t),
					MAX_DATA_DUMP_LEN));
			break;
		case VHT_OPERATION:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->vht_oprat, pos,
			       sizeof(IEEEtypes_VHTOprat_t));
			DBG_HEXDUMP(MDAT_D, "TDLS VHT Operation",
				    (t_u8 *)(&sta_ptr->vht_oprat),
				    MIN(sizeof(IEEEtypes_VHTOprat_t),
					MAX_DATA_DUMP_LEN));
			break;
		case AID_INFO:
			memcpy(priv->adapter, (t_u8 *)&sta_ptr->aid_info, pos,
			       sizeof(IEEEtypes_AID_t));
			DBG_HEXDUMP(MDAT_D, "TDLS AID Info",
				    (t_u8 *)(&sta_ptr->aid_info),
				    MIN(sizeof(IEEEtypes_AID_t),
					MAX_DATA_DUMP_LEN));
			break;
		default:
			break;
		}
	}
	return;
}
Esempio n. 11
0
/**
 *	@brief read handler for BT char dev
 *
 *	@param filp	pointer to structure file
 *	@param buf		pointer to char buffer
 *	@param count	size of receive buffer
 *	@param f_pos	pointer to loff_t type data
 *	@return			number of bytes read
 */
ssize_t
chardev_read(struct file * filp, char *buf, size_t count, loff_t * f_pos)
{
	struct char_dev *dev = (struct char_dev *)filp->private_data;
	struct m_dev *m_dev = dev->m_dev;
	DECLARE_WAITQUEUE(wait, current);
	ssize_t ret = 0;
	struct sk_buff *skb = NULL;

	ENTER();
	if (!dev || !dev->m_dev) {
		LEAVE();
		return -ENXIO;
	}
	/* Wait for rx data */
	add_wait_queue(&m_dev->req_wait_q, &wait);
	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
		skb = skb_dequeue(&m_dev->rx_q);
		if (skb)
			break;
		if (!test_bit(HCI_UP, &m_dev->flags)) {
			ret = -EBUSY;
			break;
		}

		if (filp->f_flags & O_NONBLOCK) {
			ret = -EAGAIN;
			break;
		}
		if (signal_pending(current)) {
			ret = -EINTR;
			break;
		}
		schedule();
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&m_dev->req_wait_q, &wait);

	if (!skb)
		goto out;

	if (m_dev->read_continue_flag == 0) {
		/* Put type byte before the data */
		memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
		PRINTM(DATA, "Read: pkt_type: 0x%x, len=%d @%lu\n",
		       bt_cb(skb)->pkt_type, skb->len, jiffies);
	}
	DBG_HEXDUMP(DAT_D, "chardev_read", skb->data, skb->len);
	if (skb->len > count) {
		/* user data length is smaller than the skb length */
		if (copy_to_user(buf, skb->data, count)) {
			ret = -EFAULT;
			goto outf;
		}
		skb_pull(skb, count);
		skb_queue_head(&m_dev->rx_q, skb);
		m_dev->read_continue_flag = 1;
		wake_up_interruptible(&m_dev->req_wait_q);
		ret = count;
		goto out;
	} else {
		if (copy_to_user(buf, skb->data, skb->len)) {
			ret = -EFAULT;
			goto outf;
		}
		m_dev->read_continue_flag = 0;
		ret = skb->len;
	}
outf:
	kfree_skb(skb);
out:
	LEAVE();
	return ret;
}
/** 
 *  @brief This function handles events generated by firmware
 *  
 *  @param priv	A pointer to mlan_private structure
 *
 *  @return		MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_ops_sta_process_event(IN t_void * priv)
{
    pmlan_private pmpriv = (pmlan_private) priv;
    pmlan_adapter pmadapter = pmpriv->adapter;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    t_u32 eventcause = pmadapter->event_cause;
    t_u8 event_buf[100];
    t_u8 *evt_buf = MNULL;
    pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event;
#if defined(WFD_SUPPORT)
    pmlan_callbacks pcb = &pmadapter->callbacks;
#endif
    mlan_event *pevent = (mlan_event *) event_buf;

    ENTER();

    if (eventcause != EVENT_PS_AWAKE && eventcause != EVENT_PS_SLEEP &&
        pmbuf->data_len > sizeof(eventcause))
        DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset,
                    pmbuf->data_len);

    switch (eventcause) {
    case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
        PRINTM(MERROR,
               "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n");
        break;
    case EVENT_LINK_SENSED:
        PRINTM(MEVENT, "EVENT: LINK_SENSED\n");
        pmpriv->adhoc_is_link_sensed = MTRUE;
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL);
        break;

    case EVENT_DEAUTHENTICATED:
        PRINTM(MEVENT, "EVENT: Deauthenticated\n");
        pmadapter->dbg.num_event_deauth++;
        wlan_handle_disconnect_event(pmpriv);

        break;

    case EVENT_DISASSOCIATED:
        PRINTM(MEVENT, "EVENT: Disassociated\n");
        pmadapter->dbg.num_event_disassoc++;
        wlan_handle_disconnect_event(pmpriv);
        break;

    case EVENT_LINK_LOST:
        PRINTM(MEVENT, "EVENT: Link lost\n");
        pmadapter->dbg.num_event_link_lost++;
        wlan_handle_disconnect_event(pmpriv);
        break;

    case EVENT_PS_SLEEP:
        PRINTM(MINFO, "EVENT: SLEEP\n");
        PRINTM(MEVENT, "_");

        /* Handle unexpected PS SLEEP event */
        if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
            break;
        pmadapter->ps_state = PS_STATE_PRE_SLEEP;

        wlan_check_ps_cond(pmadapter);
        break;

    case EVENT_PS_AWAKE:
        PRINTM(MINFO, "EVENT: AWAKE \n");
        PRINTM(MEVENT, "|");
        if (!pmadapter->pps_uapsd_mode &&
            pmpriv->media_connected &&
            (pmpriv->port_open || !pmpriv->port_ctrl_mode) &&
            pmadapter->sleep_period.period) {
            pmadapter->pps_uapsd_mode = MTRUE;
            PRINTM(MEVENT, "PPS/UAPSD mode activated\n");
        }
        /* Handle unexpected PS AWAKE event */
        if (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
            break;
        pmadapter->tx_lock_flag = MFALSE;
        if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) {
            if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
                if (!pmadapter->data_sent) {
                    if (wlan_send_null_packet(pmpriv,
                                              MRVDRV_TxPD_POWER_MGMT_NULL_PACKET
                                              |
                                              MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
                        == MLAN_STATUS_SUCCESS) {
                        LEAVE();
                        return MLAN_STATUS_SUCCESS;
                    }
                }
            }
        }
        pmadapter->ps_state = PS_STATE_AWAKE;
        pmadapter->pm_wakeup_card_req = MFALSE;
        pmadapter->pm_wakeup_fw_try = MFALSE;
        break;

    case EVENT_HS_ACT_REQ:
        PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n");
        ret = wlan_prepare_cmd(priv,
                               HostCmd_CMD_802_11_HS_CFG_ENH,
                               0, 0, MNULL, MNULL);
        break;

    case EVENT_MIC_ERR_UNICAST:
        PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL);
        break;

    case EVENT_MIC_ERR_MULTICAST:
        PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL);
        break;
    case EVENT_MIB_CHANGED:
    case EVENT_INIT_DONE:
        break;

    case EVENT_ADHOC_BCN_LOST:
        PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n");
        pmpriv->adhoc_is_link_sensed = MFALSE;
        wlan_clean_txrx(pmpriv);
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL);
        break;

    case EVENT_BG_SCAN_REPORT:
        PRINTM(MEVENT, "EVENT: BGS_REPORT\n");
        /* Clear the previous scan result */
        memset(pmadapter, pmadapter->pscan_table, 0x00,
               sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
        pmadapter->num_in_scan_table = 0;
        pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
        ret = wlan_prepare_cmd(pmpriv,
                               HostCmd_CMD_802_11_BG_SCAN_QUERY,
                               HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
        break;

    case EVENT_PORT_RELEASE:
        PRINTM(MEVENT, "EVENT: PORT RELEASE\n");
        /* Open the port for e-supp mode */
        if (pmpriv->port_ctrl_mode == MTRUE) {
            PRINTM(MINFO, "PORT_REL: port_status = OPEN\n");
            pmpriv->port_open = MTRUE;
        }
        pmpriv->scan_block = MFALSE;
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL);
        break;

    case EVENT_STOP_TX:
        PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause);
        wlan_11h_tx_disable(pmpriv);    // this fn will send event up to MOAL
        break;
    case EVENT_START_TX:
        PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause);
        wlan_11h_tx_enable(pmpriv);     // this fn will send event up to MOAL
        break;
    case EVENT_CHANNEL_SWITCH:
        PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause);
        /* To be handled for 'chanswann' private command */
        break;
    case EVENT_CHANNEL_SWITCH_ANN:
        PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n");
        /* Here, pass up event first, as handling will send deauth */
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, MNULL);
        wlan_11h_handle_event_chanswann(pmpriv);
        break;

    case EVENT_MEAS_REPORT_RDY:
        PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n", eventcause);
        wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
                         HostCmd_ACT_GEN_SET, 0, 0, MNULL);
        break;
    case EVENT_WMM_STATUS_CHANGE:
        if (pmbuf && pmbuf->data_len
            > sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) {
            PRINTM(MEVENT, "EVENT: WMM status changed: %d\n", pmbuf->data_len);

            evt_buf = (pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause));

            wlan_ret_wmm_get_status(pmpriv,
                                    evt_buf,
                                    pmbuf->data_len - sizeof(eventcause));
        } else {
            PRINTM(MEVENT, "EVENT: WMM status changed\n");
            ret = wlan_cmd_wmm_status_change(pmpriv);
        }
        break;

    case EVENT_RSSI_LOW:
        PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL);
        break;
    case EVENT_SNR_LOW:
        PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL);
        break;
    case EVENT_MAX_FAIL:
        PRINTM(MEVENT, "EVENT: MAX_FAIL\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL);
        break;
    case EVENT_RSSI_HIGH:
        PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL);
        break;
    case EVENT_SNR_HIGH:
        PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL);
        break;
    case EVENT_DATA_RSSI_LOW:
        PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL);
        break;
    case EVENT_DATA_SNR_LOW:
        PRINTM(MEVENT, "EVENT: Data SNR_LOW\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL);
        break;
    case EVENT_DATA_RSSI_HIGH:
        PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL);
        break;
    case EVENT_DATA_SNR_HIGH:
        PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL);
        break;
    case EVENT_LINK_QUALITY:
        PRINTM(MEVENT, "EVENT: Link Quality\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL);
        break;
    case EVENT_PRE_BEACON_LOST:
        PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n");
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL);
        break;
    case EVENT_IBSS_COALESCED:
        PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n");
        ret = wlan_prepare_cmd(pmpriv,
                               HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
                               HostCmd_ACT_GEN_GET, 0, MNULL, MNULL);
        break;
    case EVENT_ADDBA:
        PRINTM(MEVENT, "EVENT: ADDBA Request\n");
        wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP,
                         HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body);
        break;
    case EVENT_DELBA:
        PRINTM(MEVENT, "EVENT: DELBA Request\n");
        wlan_11n_delete_bastream(pmpriv, pmadapter->event_body);
        break;
    case EVENT_BA_STREAM_TIMEOUT:
        PRINTM(MEVENT, "EVENT:  BA Stream timeout\n");
        wlan_11n_ba_stream_timeout(pmpriv,
                                   (HostCmd_DS_11N_BATIMEOUT *) pmadapter->
                                   event_body);
        break;
    case EVENT_RXBA_SYNC:
        PRINTM(MEVENT, "EVENT:  RXBA_SYNC\n");
        wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body,
                                 pmbuf->data_len - sizeof(eventcause));
        break;
    case EVENT_AMSDU_AGGR_CTRL:
        PRINTM(MEVENT, "EVENT:  AMSDU_AGGR_CTRL %d\n",
               *(t_u16 *) pmadapter->event_body);
        pmadapter->tx_buf_size =
            MIN(pmadapter->curr_tx_buf_size,
                wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body));
        PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size);
        break;

    case EVENT_WEP_ICV_ERR:
        PRINTM(MEVENT, "EVENT: WEP ICV error\n");
        pevent->bss_index = pmpriv->bss_index;
        pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR;
        pevent->event_len = sizeof(Event_WEP_ICV_ERR);
        memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
               pevent->event_len);
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent);
        break;

    case EVENT_BW_CHANGE:
        PRINTM(MEVENT, "EVENT: BW Change\n");
        pevent->bss_index = pmpriv->bss_index;
        pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED;
        pevent->event_len = sizeof(t_u8);
        /* Copy event body from the event buffer */
        memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
               pevent->event_len);
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent);
        break;

#ifdef WFD_SUPPORT
    case EVENT_WIFIDIRECT_GENERIC_EVENT:
    case EVENT_WIFIDIRECT_SERVICE_DISCOVERY:
        PRINTM(MEVENT, "EVENT: WIFIDIRECT event %d\n", eventcause);
        /* Allocate memory for event buffer */
        ret =
            pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE,
                             MLAN_MEM_DEF, &evt_buf);
        if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) {
            pevent = (pmlan_event) evt_buf;
            pevent->bss_index = pmpriv->bss_index;
            pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU;
            pevent->event_len = pmbuf->data_len;
            memcpy(pmadapter, (t_u8 *) pevent->event_buf,
                   pmbuf->pbuf + pmbuf->data_offset, pevent->event_len);
            wlan_recv_event(pmpriv, pevent->event_id, pevent);
            pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf);
        }
        break;
#endif /* WFD_SUPPORT */

    case EVENT_HOSTWAKE_STAIE:
        PRINTM(MEVENT, "EVENT: HOSTWAKE_STAIE %d\n", eventcause);
        pevent->bss_index = pmpriv->bss_index;
        pevent->event_id = MLAN_EVENT_ID_FW_HOSTWAKE_STAIE;
        pevent->event_len = sizeof(t_u32);
        memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body,
               pevent->event_len);

        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_HOSTWAKE_STAIE, pevent);
        break;
    default:
        PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause);
        wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL);
        break;
    }

    LEAVE();
    return ret;
}
/** 
 *  @brief This function handles the command response
 *  
 *  @param pmadapter    A pointer to mlan_adapter structure
 *
 *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_process_cmdresp(mlan_adapter * pmadapter)
{
    HostCmd_DS_COMMAND *resp = MNULL;
    mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
    mlan_status ret = MLAN_STATUS_SUCCESS;
    t_u16 orig_cmdresp_no;
    t_u16 cmdresp_no;
    t_u16 cmdresp_result;
    mlan_ioctl_req *pioctl_buf = MNULL;
    mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
    t_u32 sec, usec;

    ENTER();

    /* Now we got response from FW, cancel the command timer */
    if (pmadapter->cmd_timer_is_set) {
        /* Cancel command timeout timer */
        pcb->moal_stop_timer(pmadapter->pmlan_cmd_timer);
        /* Cancel command timeout timer */
        pmadapter->cmd_timer_is_set = MFALSE;
    }

    if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) {
        resp = (HostCmd_DS_COMMAND *) pmadapter->upld_buf;
        resp->command = wlan_le16_to_cpu(resp->command);
        PRINTM(MERROR, "CMD_RESP: MNULL curr_cmd, 0x%x\n", resp->command);
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }

    if (pmadapter->curr_cmd->pioctl_buf != MNULL) {
        pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf;
    }

    pmadapter->num_cmd_timeout = 0;

    DBG_HEXDUMP(MCMD_D, "CMD_RESP",
                pmadapter->curr_cmd->respbuf->pbuf +
                pmadapter->curr_cmd->respbuf->data_offset, pmadapter->upld_len);

    resp =
        (HostCmd_DS_COMMAND *) (pmadapter->curr_cmd->respbuf->pbuf +
                                pmadapter->curr_cmd->respbuf->data_offset);
    if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
        /* Copy original response back to response buffer */
        wlan_ret_host_cmd(pmpriv, resp, pioctl_buf);
    }
    resp->command = wlan_le16_to_cpu(resp->command);
    resp->size = wlan_le16_to_cpu(resp->size);
    resp->seq_num = wlan_le16_to_cpu(resp->seq_num);
    resp->result = wlan_le16_to_cpu(resp->result);

    orig_cmdresp_no = resp->command;
    cmdresp_result = resp->result;

    /* Save the last command response to debug log */
    pmadapter->dbg.last_cmd_resp_index =
        (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
    pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] =
        orig_cmdresp_no;

    pmadapter->callbacks.moal_get_system_time(&sec, &usec);
    PRINTM(MCMND, "CMD_RESP (%lu.%lu): 0x%x, result %d, len %d, seqno %d\n",
           sec, usec, orig_cmdresp_no, cmdresp_result, resp->size,
           resp->seq_num);

    if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
        PRINTM(MERROR, "CMD_RESP: Invalid response to command!");
        if (pioctl_buf) {
            pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP;
        }
        wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);
        wlan_request_cmd_lock(pmadapter);
        pmadapter->curr_cmd = MNULL;
        wlan_release_cmd_lock(pmadapter);
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }

    /* Get BSS number and corresponding priv */
    pmpriv = pmadapter->priv[HostCmd_GET_BSS_NO(resp->command)];
    if (!pmpriv)
        pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY);
    /* Clear RET_BIT & BSS_NO_BITS from HostCmd */
    resp->command &= HostCmd_CMD_ID_MASK;
    cmdresp_no = resp->command;

    if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
        pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
        if ((cmdresp_result == HostCmd_RESULT_OK)
            && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
            ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf);
    } else {
        /* handle response */
        ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf);
    }

    if ((pmadapter->hw_status == WlanHardwareStatusInitializing) &&
        (pmadapter->last_init_cmd == cmdresp_no)) {
        if (cmdresp_result == HostCmd_RESULT_OK)
            pmadapter->hw_status = WlanHardwareStatusInitdone;
        else
            wlan_init_fw_complete(pmadapter);
    }

    if (pmadapter->curr_cmd) {
        if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS))
            pioctl_buf->status_code = MLAN_ERROR_NO_ERROR;

        /* Clean up and put current command back to cmd_free_q */
        wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);

        wlan_request_cmd_lock(pmadapter);
        pmadapter->curr_cmd = MNULL;
        wlan_release_cmd_lock(pmadapter);
    }

  done:
    LEAVE();
    return ret;
}
/**
 *  @brief This function processes received packet and forwards it
 *          to kernel/upper layer or send back to firmware
 *
 *  @param priv      A pointer to mlan_private
 *  @param pmbuf     A pointer to mlan_buffer which includes the received packet
 *
 *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_uap_recv_packet(IN mlan_private *priv, IN pmlan_buffer pmbuf)
{
    pmlan_adapter pmadapter = priv->adapter;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    RxPacketHdr_t *prx_pkt;
    pmlan_buffer newbuf = MNULL;

    ENTER();

    prx_pkt = (RxPacketHdr_t *)((t_u8 *)pmbuf->pbuf + pmbuf->data_offset);

    DBG_HEXDUMP(MDAT_D, "uap_recv_packet", pmbuf->pbuf + pmbuf->data_offset,
                MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));

    PRINTM(MDATA, "AMSDU dest " MACSTR "\n",
           MAC2STR(prx_pkt->eth803_hdr.dest_addr));

    /* don't do packet forwarding in disconnected state */
    if ((priv->media_connected == MFALSE) ||
            (pmbuf->data_len > MV_ETH_FRAME_LEN))
        goto upload;

    if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
        if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
            /* Multicast pkt */
            newbuf = wlan_alloc_mlan_buffer(pmadapter,
                                            MLAN_TX_DATA_BUF_SIZE_2K,
                                            0, MOAL_MALLOC_BUFFER);
            if (newbuf) {
                newbuf->bss_index = pmbuf->bss_index;
                newbuf->buf_type = pmbuf->buf_type;
                newbuf->priority = pmbuf->priority;
                newbuf->in_ts_sec = pmbuf->in_ts_sec;
                newbuf->in_ts_usec = pmbuf->in_ts_usec;
                newbuf->data_offset =
                    (sizeof(UapTxPD) + INTF_HEADER_LEN +
                     DMA_ALIGNMENT);
                util_scalar_increment(pmadapter->pmoal_handle,
                                      &pmadapter->
                                      pending_bridge_pkts,
                                      pmadapter->callbacks.
                                      moal_spin_lock,
                                      pmadapter->callbacks.
                                      moal_spin_unlock);

                newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

                /* copy the data */
                memcpy(pmadapter,
                       (t_u8 *)newbuf->pbuf +
                       newbuf->data_offset,
                       pmbuf->pbuf + pmbuf->data_offset,
                       pmbuf->data_len);
                newbuf->data_len = pmbuf->data_len;
                wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
                if (util_scalar_read(pmadapter->pmoal_handle,
                                     &pmadapter->
                                     pending_bridge_pkts,
                                     pmadapter->callbacks.
                                     moal_spin_lock,
                                     pmadapter->callbacks.
                                     moal_spin_unlock) >
                        RX_HIGH_THRESHOLD)
                    wlan_drop_tx_pkts(priv);
                wlan_recv_event(priv,
                                MLAN_EVENT_ID_DRV_DEFER_HANDLING,
                                MNULL);
            }
        }
    } else {
        if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
                (wlan_get_station_entry
                 (priv, prx_pkt->eth803_hdr.dest_addr))) {
            /* Intra BSS packet */
            newbuf = wlan_alloc_mlan_buffer(pmadapter,
                                            MLAN_TX_DATA_BUF_SIZE_2K,
                                            0, MOAL_MALLOC_BUFFER);
            if (newbuf) {
                newbuf->bss_index = pmbuf->bss_index;
                newbuf->buf_type = pmbuf->buf_type;
                newbuf->priority = pmbuf->priority;
                newbuf->in_ts_sec = pmbuf->in_ts_sec;
                newbuf->in_ts_usec = pmbuf->in_ts_usec;
                newbuf->data_offset =
                    (sizeof(UapTxPD) + INTF_HEADER_LEN +
                     DMA_ALIGNMENT);
                util_scalar_increment(pmadapter->pmoal_handle,
                                      &pmadapter->
                                      pending_bridge_pkts,
                                      pmadapter->callbacks.
                                      moal_spin_lock,
                                      pmadapter->callbacks.
                                      moal_spin_unlock);
                newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

                /* copy the data */
                memcpy(pmadapter,
                       (t_u8 *)newbuf->pbuf +
                       newbuf->data_offset,
                       pmbuf->pbuf + pmbuf->data_offset,
                       pmbuf->data_len);
                newbuf->data_len = pmbuf->data_len;
                wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
                if (util_scalar_read(pmadapter->pmoal_handle,
                                     &pmadapter->
                                     pending_bridge_pkts,
                                     pmadapter->callbacks.
                                     moal_spin_lock,
                                     pmadapter->callbacks.
                                     moal_spin_unlock) >
                        RX_HIGH_THRESHOLD)
                    wlan_drop_tx_pkts(priv);
                wlan_recv_event(priv,
                                MLAN_EVENT_ID_DRV_DEFER_HANDLING,
                                MNULL);
            }
            goto done;
        } else if (MLAN_STATUS_FAILURE ==
                   wlan_check_unicast_packet(priv,
                                             prx_pkt->eth803_hdr.
                                             dest_addr)) {
            /* drop packet */
            PRINTM(MDATA, "Drop AMSDU dest " MACSTR "\n",
                   MAC2STR(prx_pkt->eth803_hdr.dest_addr));
            goto done;
        }
    }
upload:
    /** send packet to moal */
    ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle,
            pmbuf);
done:
    LEAVE();
    return ret;
}
Esempio n. 15
0
/**
 *  @brief This function processes received packet and forwards it
 *  		to kernel/upper layer or send back to firmware 
 *  
 *  @param priv      A pointer to mlan_private
 *  @param pmbuf     A pointer to mlan_buffer which includes the received packet
 *
 *  @return 	   MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_uap_recv_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
{
    pmlan_adapter pmadapter = priv->adapter;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    RxPacketHdr_t *prx_pkt;
    pmlan_buffer newbuf = MNULL;

    ENTER();

    prx_pkt = (RxPacketHdr_t *) ((t_u8 *) pmbuf->pbuf + pmbuf->data_offset);

    DBG_HEXDUMP(MDAT_D, "uap_recv_packet", pmbuf->pbuf + pmbuf->data_offset,
                MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));

    PRINTM(MDATA, "AMSDU dest %02x:%02x:%02x:%02x:%02x:%02x\n",
           prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
           prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
           prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);

    /* don't do packet forwarding in disconnected state */
    if ((priv->media_connected == MFALSE) ||
        (pmbuf->data_len > MV_ETH_FRAME_LEN))
        goto upload;

    if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
        /* Multicast pkt */
        if ((newbuf =
             wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
                                    MTRUE))) {
            newbuf->bss_index = pmbuf->bss_index;
            newbuf->buf_type = pmbuf->buf_type;
            newbuf->priority = pmbuf->priority;
            newbuf->in_ts_sec = pmbuf->in_ts_sec;
            newbuf->in_ts_usec = pmbuf->in_ts_usec;
            newbuf->data_offset =
                (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
            pmadapter->pending_bridge_pkts++;
            newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

            /* copy the data */
            memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
                   pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
            newbuf->data_len = pmbuf->data_len;
            wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
            if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
                wlan_drop_tx_pkts(priv);
        }
    } else {
        if (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr)) {
            /* Intra BSS packet */
            if ((newbuf =
                 wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
                                        MTRUE))) {
                newbuf->bss_index = pmbuf->bss_index;
                newbuf->buf_type = pmbuf->buf_type;
                newbuf->priority = pmbuf->priority;
                newbuf->in_ts_sec = pmbuf->in_ts_sec;
                newbuf->in_ts_usec = pmbuf->in_ts_usec;
                newbuf->data_offset =
                    (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
                pmadapter->pending_bridge_pkts++;
                newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

                /* copy the data */
                memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
                       pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len);
                newbuf->data_len = pmbuf->data_len;
                wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
                if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
                    wlan_drop_tx_pkts(priv);
            }
            goto done;
        }
    }
  upload:
    /** send packet to moal */
    ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, pmbuf);
  done:
    LEAVE();
    return ret;
}
/**
 *  @brief This function processes received packet and forwards it
 *          to kernel/upper layer or send back to firmware
 *
 *  @param priv      A pointer to mlan_private
 *  @param pmbuf     A pointer to mlan_buffer which includes the received packet
 *
 *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_process_uap_rx_packet(IN mlan_private *priv, IN pmlan_buffer pmbuf)
{
    pmlan_adapter pmadapter = priv->adapter;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    UapRxPD *prx_pd;
    RxPacketHdr_t *prx_pkt;
    pmlan_buffer newbuf = MNULL;

    ENTER();

    prx_pd = (UapRxPD *)(pmbuf->pbuf + pmbuf->data_offset);
    prx_pkt = (RxPacketHdr_t *)((t_u8 *)prx_pd + prx_pd->rx_pkt_offset);

    DBG_HEXDUMP(MDAT_D, "uAP RxPD", prx_pd,
                MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
    DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
                ((t_u8 *)prx_pd + prx_pd->rx_pkt_offset),
                MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));

    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);
    PRINTM(MDATA, "Rx dest " MACSTR "\n",
           MAC2STR(prx_pkt->eth803_hdr.dest_addr));

    /* don't do packet forwarding in disconnected state */
    /* don't do packet forwarding when packet > 1514 */
    if ((priv->media_connected == MFALSE) ||
            ((pmbuf->data_len - prx_pd->rx_pkt_offset) > MV_ETH_FRAME_LEN))
        goto upload;

    if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
        if (!(priv->pkt_fwd & PKT_FWD_INTRA_BCAST)) {
            /* Multicast pkt */
            newbuf = wlan_alloc_mlan_buffer(pmadapter,
                                            MLAN_TX_DATA_BUF_SIZE_2K,
                                            0, MOAL_MALLOC_BUFFER);
            if (newbuf) {
                newbuf->bss_index = pmbuf->bss_index;
                newbuf->buf_type = pmbuf->buf_type;
                newbuf->priority = pmbuf->priority;
                newbuf->in_ts_sec = pmbuf->in_ts_sec;
                newbuf->in_ts_usec = pmbuf->in_ts_usec;
                newbuf->data_offset =
                    (sizeof(UapTxPD) + INTF_HEADER_LEN +
                     DMA_ALIGNMENT);
                util_scalar_increment(pmadapter->pmoal_handle,
                                      &pmadapter->
                                      pending_bridge_pkts,
                                      pmadapter->callbacks.
                                      moal_spin_lock,
                                      pmadapter->callbacks.
                                      moal_spin_unlock);
                newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

                /* copy the data, skip rxpd */
                memcpy(pmadapter,
                       (t_u8 *)newbuf->pbuf +
                       newbuf->data_offset,
                       pmbuf->pbuf + pmbuf->data_offset +
                       prx_pd->rx_pkt_offset,
                       pmbuf->data_len - prx_pd->rx_pkt_offset);
                newbuf->data_len =
                    pmbuf->data_len - prx_pd->rx_pkt_offset;
                wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
                if (util_scalar_read(pmadapter->pmoal_handle,
                                     &pmadapter->
                                     pending_bridge_pkts,
                                     pmadapter->callbacks.
                                     moal_spin_lock,
                                     pmadapter->callbacks.
                                     moal_spin_unlock) >
                        RX_HIGH_THRESHOLD)
                    wlan_drop_tx_pkts(priv);
                wlan_recv_event(priv,
                                MLAN_EVENT_ID_DRV_DEFER_HANDLING,
                                MNULL);
            }
        }
    } else {
        if ((!(priv->pkt_fwd & PKT_FWD_INTRA_UCAST)) &&
                (wlan_get_station_entry
                 (priv, prx_pkt->eth803_hdr.dest_addr))) {
            /* Forwarding Intra-BSS packet */
            pmbuf->data_len -= prx_pd->rx_pkt_offset;
            pmbuf->data_offset += prx_pd->rx_pkt_offset;
            pmbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
            util_scalar_increment(pmadapter->pmoal_handle,
                                  &pmadapter->pending_bridge_pkts,
                                  pmadapter->callbacks.
                                  moal_spin_lock,
                                  pmadapter->callbacks.
                                  moal_spin_unlock);
            wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
            if (util_scalar_read(pmadapter->pmoal_handle,
                                 &pmadapter->pending_bridge_pkts,
                                 pmadapter->callbacks.
                                 moal_spin_lock,
                                 pmadapter->callbacks.
                                 moal_spin_unlock) >
                    RX_HIGH_THRESHOLD)
                wlan_drop_tx_pkts(priv);
            wlan_recv_event(priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING,
                            MNULL);
            goto done;
        } else if (MLAN_STATUS_FAILURE ==
                   wlan_check_unicast_packet(priv,
                                             prx_pkt->eth803_hdr.
                                             dest_addr)) {
            PRINTM(MDATA, "Drop Pkts: Rx dest " MACSTR "\n",
                   MAC2STR(prx_pkt->eth803_hdr.dest_addr));
            pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
            wlan_free_mlan_buffer(pmadapter, pmbuf);
            goto done;
        }
    }

upload:
    /* Chop off RxPD */
    pmbuf->data_len -= prx_pd->rx_pkt_offset;
    pmbuf->data_offset += prx_pd->rx_pkt_offset;
    pmbuf->pparent = MNULL;

    pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
            &pmbuf->out_ts_sec,
            &pmbuf->out_ts_usec);
    PRINTM_NETINTF(MDATA, priv);
    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) {
        PRINTM(MERROR,
               "uAP Rx Error: moal_recv_packet returned error\n");
        pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
    }

    if (ret != MLAN_STATUS_PENDING)
        wlan_free_mlan_buffer(pmadapter, pmbuf);
done:
    LEAVE();
    return ret;
}
Esempio n. 17
0
/**
 *  @brief This function processes received packet and forwards it
 *  		to kernel/upper layer or send back to firmware 
 *  
 *  @param priv      A pointer to mlan_private
 *  @param pmbuf     A pointer to mlan_buffer which includes the received packet
 *
 *  @return 	   MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_process_uap_rx_packet(IN mlan_private * priv, IN pmlan_buffer pmbuf)
{
    pmlan_adapter pmadapter = priv->adapter;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    UapRxPD *prx_pd;
    RxPacketHdr_t *prx_pkt;
    pmlan_buffer newbuf = MNULL;

    ENTER();

    prx_pd = (UapRxPD *) (pmbuf->pbuf + pmbuf->data_offset);
    prx_pkt = (RxPacketHdr_t *) ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset);

    DBG_HEXDUMP(MDAT_D, "uAP RxPD", prx_pd,
                MIN(sizeof(UapRxPD), MAX_DATA_DUMP_LEN));
    DBG_HEXDUMP(MDAT_D, "uAP Rx Payload",
                ((t_u8 *) prx_pd + prx_pd->rx_pkt_offset),
                MIN(prx_pd->rx_pkt_length, MAX_DATA_DUMP_LEN));

    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);
    PRINTM(MDATA, "Rx dest %02x:%02x:%02x:%02x:%02x:%02x\n",
           prx_pkt->eth803_hdr.dest_addr[0], prx_pkt->eth803_hdr.dest_addr[1],
           prx_pkt->eth803_hdr.dest_addr[2], prx_pkt->eth803_hdr.dest_addr[3],
           prx_pkt->eth803_hdr.dest_addr[4], prx_pkt->eth803_hdr.dest_addr[5]);

    /* don't do packet forwarding in disconnected state */
    /* don't do packet forwarding when packet > 1514 */
    if ((priv->media_connected == MFALSE) ||
        ((pmbuf->data_len - prx_pd->rx_pkt_offset) > MV_ETH_FRAME_LEN))
        goto upload;

    if (prx_pkt->eth803_hdr.dest_addr[0] & 0x01) {
        /* Multicast pkt */
        if ((newbuf =
             wlan_alloc_mlan_buffer(pmadapter, MLAN_TX_DATA_BUF_SIZE_2K, 0,
                                    MTRUE))) {
            newbuf->bss_index = pmbuf->bss_index;
            newbuf->buf_type = pmbuf->buf_type;
            newbuf->priority = pmbuf->priority;
            newbuf->in_ts_sec = pmbuf->in_ts_sec;
            newbuf->in_ts_usec = pmbuf->in_ts_usec;
            newbuf->data_offset =
                (sizeof(UapTxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT);
            pmadapter->pending_bridge_pkts++;
            newbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;

            /* copy the data, skip rxpd */
            memcpy(pmadapter, (t_u8 *) newbuf->pbuf + newbuf->data_offset,
                   pmbuf->pbuf + pmbuf->data_offset + prx_pd->rx_pkt_offset,
                   pmbuf->data_len - prx_pd->rx_pkt_offset);
            newbuf->data_len = pmbuf->data_len - prx_pd->rx_pkt_offset;
            wlan_wmm_add_buf_txqueue(pmadapter, newbuf);
            if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
                wlan_drop_tx_pkts(priv);
        }
    } else {
        if (wlan_get_station_entry(priv, prx_pkt->eth803_hdr.dest_addr)) {
            /* Forwarding Intra-BSS packet */
            pmbuf->data_len -= prx_pd->rx_pkt_offset;
            pmbuf->data_offset += prx_pd->rx_pkt_offset;
            pmbuf->flags |= MLAN_BUF_FLAG_BRIDGE_BUF;
            pmadapter->pending_bridge_pkts++;
            wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
            if (pmadapter->pending_bridge_pkts > RX_HIGH_THRESHOLD)
                wlan_drop_tx_pkts(priv);
            pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle,
                                                    MNULL,
                                                    MLAN_USB_EP_DATA, ret);
            goto done;
        }
    }
  upload:
    /* Chop off RxPD */
    pmbuf->data_len -= prx_pd->rx_pkt_offset;
    pmbuf->data_offset += prx_pd->rx_pkt_offset;
    pmbuf->pparent = MNULL;

    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) {
        PRINTM(MERROR, "uAP Rx Error: moal_recv_packet returned error\n");
        pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
    }

    if (ret != MLAN_STATUS_PENDING) {
        pmadapter->callbacks.moal_recv_complete(pmadapter->pmoal_handle, pmbuf,
                                                MLAN_USB_EP_DATA, ret);
    }
  done:
    LEAVE();
    return ret;
}
Esempio n. 18
0
/**  
 *  @brief This function sends data to the card.
 *  
 *  @param priv    A pointer to bt_private structure
 *  @param payload A pointer to the data/cmd buffer
 *  @param nb	   Length of data/cmd
 *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
int
sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb)
{
    struct sdio_mmc_card *card = priv->bt_dev.card;
    int ret = BT_STATUS_SUCCESS;
    int buf_block_len;
    int blksz;
    int i = 0;
    u8 *buf = NULL;
    struct hci_dev *hdev = priv->bt_dev.hcidev;
    void *tmpbuf = NULL;
    int tmpbufsz;

    ENTER();

    if (!card || !card->func) {
        PRINTM(ERROR, "BT: card or function is NULL!\n");
        LEAVE();
        return BT_STATUS_FAILURE;
    }
    buf = payload;

    /* Allocate buffer and copy payload */
    blksz = SD_BLOCK_SIZE;
    buf_block_len = (nb + blksz - 1) / blksz;
    if ((u32) payload & (DMA_ALIGNMENT - 1)) {
        tmpbufsz = buf_block_len * blksz + DMA_ALIGNMENT;
        tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
        memset(tmpbuf, 0, tmpbufsz);
        /* Ensure 8-byte aligned CMD buffer */
        buf = (u8 *) ALIGN_ADDR(tmpbuf, DMA_ALIGNMENT);
        memcpy(buf, payload, nb);
    }
    sdio_claim_host(card->func);
#define MAX_WRITE_IOMEM_RETRY	2
    do {
        /* Transfer data to card */
        ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf,
                           buf_block_len * blksz);
        if (ret < 0) {
            i++;
            PRINTM(ERROR, "BT: host_to_card, write iomem (%d) failed: %d\n", i,
                   ret);
            sdio_writeb(card->func, HOST_WO_CMD53_FINISH_HOST,
                        CONFIGURATION_REG, &ret);
            udelay(20);
            ret = BT_STATUS_FAILURE;
            if (i > MAX_WRITE_IOMEM_RETRY)
                goto exit;
        } else {
            DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Wr", payload, nb);
            PRINTM(DATA, "BT: SDIO Blk Wr %s: len=%d\n", hdev->name, nb);
        }
    } while (ret == BT_STATUS_FAILURE);
    priv->bt_dev.tx_dnld_rdy = FALSE;
  exit:
    sdio_release_host(card->func);
    if (tmpbuf)
        kfree(tmpbuf);
    LEAVE();
    return ret;
}
/**
 *  @brief This function tells firmware to send a NULL data packet.
 *
 *  @param priv     A pointer to mlan_private structure
 *  @param flags    Transmit Pkt Flags
 *
 *  @return 	    MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure
 */
mlan_status
wlan_send_null_packet(pmlan_private priv, t_u8 flags)
{
	pmlan_adapter pmadapter = priv->adapter;
	TxPD *ptx_pd;
/* sizeof(TxPD) + Interface specific header */
#define NULL_PACKET_HDR 256
	t_u32 data_len = NULL_PACKET_HDR;
	pmlan_buffer pmbuf = MNULL;
	t_u8 *ptr;
	mlan_status ret = MLAN_STATUS_SUCCESS;
#ifdef DEBUG_LEVEL1
	t_u32 sec, usec;
#endif

	ENTER();

	if (pmadapter->surprise_removed == MTRUE) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}

	if (priv->media_connected == MFALSE) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}

	if (pmadapter->data_sent == MTRUE) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}

	pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0,
				       MOAL_MALLOC_BUFFER);
	if (!pmbuf) {
		ret = MLAN_STATUS_FAILURE;
		goto done;
	}
	memset(pmadapter, pmbuf->pbuf, 0, data_len);
	pmbuf->bss_index = priv->bss_index;
	pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
	ptr = pmbuf->pbuf + pmbuf->data_offset;
	pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN;
	ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN);
	ptx_pd->tx_control = priv->pkt_tx_ctrl;
	ptx_pd->flags = flags;
	ptx_pd->priority = WMM_HIGHEST_PRIORITY;
	ptx_pd->tx_pkt_offset = sizeof(TxPD);
	/* Set the BSS number to TxPD */
	ptx_pd->bss_num = GET_BSS_NUM(priv);
	ptx_pd->bss_type = priv->bss_type;

	endian_convert_TxPD(ptx_pd);

	ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL);

	switch (ret) {
	case MLAN_STATUS_RESOURCE:
		wlan_free_mlan_buffer(pmadapter, pmbuf);
		PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
		pmadapter->dbg.num_tx_host_to_card_failure++;
		goto done;
	case MLAN_STATUS_FAILURE:
		pmadapter->data_sent = MFALSE;
		wlan_free_mlan_buffer(pmadapter, pmbuf);
		PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
		pmadapter->dbg.num_tx_host_to_card_failure++;
		goto done;
	case MLAN_STATUS_SUCCESS:
		wlan_free_mlan_buffer(pmadapter, pmbuf);
		PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n");
		pmadapter->tx_lock_flag = MTRUE;
		break;
	case MLAN_STATUS_PENDING:
		pmadapter->data_sent = MFALSE;
		pmadapter->tx_lock_flag = MTRUE;
		break;
	default:
		break;
	}

	PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
	PRINTM_NETINTF(MDATA, priv);
	PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
	DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN);
done:
	LEAVE();
	return ret;
}
Esempio n. 20
0
/** 
 *  @brief This function reads data from the card.
 *  
 *  @param priv    	A pointer to bt_private structure
 *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
static int
sd_card_to_host(bt_private * priv)
{
    int ret = BT_STATUS_SUCCESS;
    u16 buf_len = 0;
    int buf_block_len;
    int blksz;
    struct sk_buff *skb = NULL;
    u32 type;
    u8 *payload = NULL;
    struct hci_dev *hdev = priv->bt_dev.hcidev;
    struct sdio_mmc_card *card = priv->bt_dev.card;

    ENTER();

    if (!card || !card->func) {
        PRINTM(ERROR, "BT: card or function is NULL!\n");
        ret = BT_STATUS_FAILURE;
        goto exit;
    }

    /* Read the length of data to be transferred */
    ret = sd_read_rx_len(priv, &buf_len);
    if (ret < 0) {
        PRINTM(ERROR, "BT: card_to_host, read scratch reg failed\n");
        ret = BT_STATUS_FAILURE;
        goto exit;
    }

    /* Allocate buffer */
    blksz = SD_BLOCK_SIZE;
    buf_block_len = (buf_len + blksz - 1) / blksz;
    if (buf_len <= BT_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
        PRINTM(ERROR, "BT: card_to_host, invalid packet length: %d\n", buf_len);
        ret = BT_STATUS_FAILURE;
        goto exit;
    }
    skb = bt_skb_alloc(buf_block_len * blksz + DMA_ALIGNMENT, GFP_ATOMIC);
    if (skb == NULL) {
        PRINTM(WARN, "BT: No free skb\n");
        goto exit;
    }
    if ((u32) skb->data & (DMA_ALIGNMENT - 1)) {
        skb_put(skb, DMA_ALIGNMENT - ((u32) skb->data & (DMA_ALIGNMENT - 1)));
        skb_pull(skb, DMA_ALIGNMENT - ((u32) skb->data & (DMA_ALIGNMENT - 1)));
    }

    payload = skb->tail;
    ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport,
                      buf_block_len * blksz);
    if (ret < 0) {
        PRINTM(ERROR, "BT: card_to_host, read iomem failed: %d\n", ret);
        kfree_skb(skb);
        skb = NULL;
        ret = BT_STATUS_FAILURE;
        goto exit;
    }
    /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
       (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
    buf_len = payload[0];
    buf_len |= (u16) payload[1] << 8;
    type = payload[3];
    PRINTM(DATA, "BT: SDIO Blk Rd %s: len=%d type=%d\n", hdev->name, buf_len,
           type);
    if (buf_len > buf_block_len * blksz) {
        PRINTM(ERROR,
               "BT: Drop invalid rx pkt, len in hdr=%d, cmd53 length=%d\n",
               buf_len, buf_block_len * blksz);
        ret = BT_STATUS_FAILURE;
        kfree_skb(skb);
        skb = NULL;
        goto exit;
    }
    DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Rd", payload, buf_len);
    switch (type) {
    case HCI_ACLDATA_PKT:
    case HCI_SCODATA_PKT:
    case HCI_EVENT_PKT:
        bt_cb(skb)->pkt_type = type;
        skb->dev = (void *) hdev;
        skb_put(skb, buf_len);
        skb_pull(skb, BT_HEADER_LEN);
        if (type == HCI_EVENT_PKT) {
            if (BT_STATUS_SUCCESS == check_evtpkt(priv, skb))
                break;
        }
        hci_recv_frame(skb);
        hdev->stat.byte_rx += buf_len;
        break;
    case MRVL_VENDOR_PKT:
        bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
        skb->dev = (void *) hdev;
        skb_put(skb, buf_len);
        skb_pull(skb, BT_HEADER_LEN);
        if (BT_STATUS_SUCCESS != bt_process_event(priv, skb))
            hci_recv_frame(skb);
        hdev->stat.byte_rx += buf_len;
        break;
    default:
        /* Driver specified event and command resp should be handle here */
        PRINTM(INFO, "BT: Unknown PKT type:%d\n", type);
        kfree_skb(skb);
        skb = NULL;
        break;
    }
  exit:
    if (ret) {
        hdev->stat.err_rx++;
    }

    LEAVE();
    return ret;
}
Esempio n. 21
0
/**
 *  @brief Aggregate multiple packets into one single AMSDU packet
 *
 *  @param priv 	A pointer to mlan_private structure
 *  @param pra_list	Pointer to the RA List table containing the pointers
 *  			    to packets.
 *  @param headroom	Any interface specific headroom that may be need. TxPD 
 *  				will be formed leaving this headroom.
 *  @param ptrindex	Pointer index
 *
 *  @return		Final packet size or MLAN_STATUS_FAILURE
 */
int
wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list,
                       int headroom, int ptrindex)
{
    int pkt_size = 0;
    pmlan_adapter pmadapter = priv->adapter;
    mlan_buffer *pmbuf_aggr, *pmbuf_src;
    t_u8 *data;
    int pad = 0;
    mlan_status ret = MLAN_STATUS_SUCCESS;
#ifdef DEBUG_LEVEL1
    t_u32 sec = 0, usec = 0;
#endif
    mlan_tx_param tx_param;
#ifdef STA_SUPPORT
    TxPD *ptx_pd = MNULL;
#endif
    t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size);
    ENTER();

    PRINTM(MDAT_D, "Handling Aggr packet\n");

    if ((pmbuf_src =
         (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
                                       &pra_list->buf_head, MNULL, MNULL)) != 0) {

        if ((pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter,
                                                  pmadapter->tx_buf_size, 0,
                                                  MOAL_MALLOC_BUFFER)) == 0) {
            PRINTM(MERROR, "Error allocating mlan_buffer\n");
            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                                  priv->wmm.ra_list_spinlock);
            LEAVE();
            return MLAN_STATUS_FAILURE;
        }

        data = pmbuf_aggr->pbuf + headroom;
        pmbuf_aggr->bss_index = pmbuf_src->bss_index;
        pmbuf_aggr->buf_type = pmbuf_src->buf_type;
        pmbuf_aggr->priority = pmbuf_src->priority;
        pmbuf_aggr->pbuf = data;
        pmbuf_aggr->data_offset = 0;

        /* Form AMSDU */
        wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr);
        pkt_size = sizeof(TxPD);
#ifdef STA_SUPPORT
        if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
            ptx_pd = (TxPD *) pmbuf_aggr->pbuf;
#endif
    } else {
        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                              priv->wmm.ra_list_spinlock);
        goto exit;
    }

    while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN)
                          + headroom) <= max_amsdu_size)) {

        pmbuf_src = (pmlan_buffer)
            util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head,
                              MNULL, MNULL);

        pra_list->total_pkts--;

        /* decrement for every PDU taken from the list */
        priv->wmm.pkts_queued[ptrindex]--;
        util_scalar_decrement(pmadapter->pmoal_handle,
                              &priv->wmm.tx_pkts_queued, MNULL, MNULL);

        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                              priv->wmm.ra_list_spinlock);

        pkt_size += wlan_11n_form_amsdu_pkt(pmadapter,
                                            (data + pkt_size),
                                            pmbuf_src->pbuf +
                                            pmbuf_src->data_offset,
                                            pmbuf_src->data_len, &pad);

        DBG_HEXDUMP(MDAT_D, "pmbuf_src", (t_u8*)pmbuf_src, sizeof(mlan_buffer));
        wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS);

        pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
                                            priv->wmm.ra_list_spinlock);

        if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                                  priv->wmm.ra_list_spinlock);
            LEAVE();
            return MLAN_STATUS_FAILURE;
        }

        pmbuf_src =
            (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
                                          &pra_list->buf_head, MNULL, MNULL);
    }

    pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                          priv->wmm.ra_list_spinlock);

    /* Last AMSDU packet does not need padding */
    pkt_size -= pad;
    pmbuf_aggr->data_len = pkt_size;
    wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr);
    pmbuf_aggr->data_len += headroom;
    pmbuf_aggr->pbuf = data - headroom;
    tx_param.next_pkt_len = ((pmbuf_src) ?
                             pmbuf_src->data_len + sizeof(TxPD) : 0);
    ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA,
                                 pmbuf_aggr, &tx_param);
    switch (ret) {
    case MLAN_STATUS_RESOURCE:
        pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
                                            priv->wmm.ra_list_spinlock);

        if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                                  priv->wmm.ra_list_spinlock);
            pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
            wlan_write_data_complete(pmadapter, pmbuf_aggr,
                                     MLAN_STATUS_FAILURE);
            LEAVE();
            return MLAN_STATUS_FAILURE;
        }
#ifdef STA_SUPPORT
        /* reset tx_lock_flag */
        if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
            pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) {
            pmadapter->tx_lock_flag = MFALSE;
            ptx_pd->flags = 0;
        }
#endif
        util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head,
                               (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL);

        pra_list->total_pkts++;

        /* add back only one: aggregated packet is requeued as one */
        priv->wmm.pkts_queued[ptrindex]++;
        util_scalar_increment(pmadapter->pmoal_handle,
                              &priv->wmm.tx_pkts_queued, MNULL, MNULL);
        pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                              priv->wmm.ra_list_spinlock);
        PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
        pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID;
        break;
    case MLAN_STATUS_FAILURE:
        pmadapter->data_sent = MFALSE;
        PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
        pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL;
        pmadapter->dbg.num_tx_host_to_card_failure++;
        wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
        goto exit;
    case MLAN_STATUS_PENDING:
        pmadapter->data_sent = MFALSE;
        break;
    case MLAN_STATUS_SUCCESS:
        wlan_write_data_complete(pmadapter, pmbuf_aggr, ret);
        break;
    default:
        break;
    }
    if (ret != MLAN_STATUS_RESOURCE) {
        pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
                                            priv->wmm.ra_list_spinlock);
        if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) {
            priv->wmm.packets_out[ptrindex]++;
            priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
        }
        pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
            pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
                                              priv->wmm.ra_list_spinlock);
    }
    PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
    PRINTM_NETINTF(MDATA, priv);
    PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);

  exit:
    LEAVE();
    return (pkt_size + headroom);
}
/**
 *  @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 dbg_type;
		dbg_type = *(t_u8 *) & prx_pkt->eth803_hdr;
		if (dbg_type == DBG_TYPE_SMALL) {
			PRINTM(MFW_D, "\n");
			DBG_HEXDUMP(MFW_D, "FWDBG",
				    (char *)((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));
		if ((priv->hotspot_cfg & HOTSPOT_ENABLED) &&
		    discard_gratuitous_ARP_msg(prx_pkt, pmadapter)) {
			ret = MLAN_STATUS_SUCCESS;
			PRINTM(MDATA,
			       "Bypass sending Gratuitous ARP frame to Kernel.\n");
			goto done;
		}
		/* 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_NETINTF(MDATA, priv);
	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 downloads a command to firmware.
 *  
 *  @param pmpriv       A pointer to mlan_private structure
 *  @param pcmd_node    A pointer to cmd_ctrl_node structure
 *
 *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
static mlan_status
wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node)
{

    mlan_adapter *pmadapter = pmpriv->adapter;
    mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;
    mlan_status ret = MLAN_STATUS_SUCCESS;
    HostCmd_DS_COMMAND *pcmd;
    mlan_ioctl_req *pioctl_buf = MNULL;
    t_u16 cmd_code;
    t_u16 cmd_size;
    t_u32 sec, usec;

    ENTER();

    if (!pmadapter || !pcmd_node) {
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }

    pcmd =
        (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf +
                                pcmd_node->cmdbuf->data_offset);
    if (pcmd_node->pioctl_buf != MNULL)
        pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf;

    /* Sanity test */
    if (pcmd == MNULL || pcmd->size == 0) {
        PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, "
               "Not sending\n");
        if (pioctl_buf != MNULL)
            pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
                wlan_insert_cmd_to_free_q(pmadapter, pcmd_node);
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }

    /* Set command sequence number */
    pmadapter->seq_num++;
    pcmd->seq_num = wlan_cpu_to_le16(pmadapter->seq_num);

    wlan_request_cmd_lock(pmadapter);
    pmadapter->curr_cmd = pcmd_node;
    wlan_release_cmd_lock(pmadapter);

    cmd_code = wlan_le16_to_cpu(pcmd->command);
    cmd_size = wlan_le16_to_cpu(pcmd->size);

    /* Set BSS_NO_BITS to HostCmd */
    cmd_code = HostCmd_SET_BSS_NO(cmd_code, pcmd_node->priv->bss_num);
    pcmd->command = wlan_cpu_to_le16(cmd_code);

    pcmd_node->cmdbuf->data_len = cmd_size;

    pmadapter->callbacks.moal_get_system_time(&sec, &usec);
    PRINTM(MCMND, "DNLD_CMD (%lu.%lu): 0x%x, act 0x%x, len %d, seqno %d\n",
           sec, usec, cmd_code,
           wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size,
           wlan_le16_to_cpu(pcmd->seq_num));
    DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size);

    /* Send the command to lower layer */

    pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN;
    pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN;
    /* Extra header for SDIO is added here */
    ret =
        wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf,
                               MNULL);

    if (ret == MLAN_STATUS_FAILURE) {
        PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n");
        if (pioctl_buf != MNULL)
            pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL,
                wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd);

        wlan_request_cmd_lock(pmadapter);
        pmadapter->curr_cmd = MNULL;
        wlan_release_cmd_lock(pmadapter);

        pmadapter->dbg.num_cmd_host_to_card_failure++;
        ret = MLAN_STATUS_FAILURE;
        goto done;
    }

    /* Save the last command id and action to debug log */
    pmadapter->dbg.last_cmd_index =
        (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
    pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code;
    pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] =
        wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN));

    /* Clear BSS_NO_BITS from HostCmd */
    cmd_code &= HostCmd_CMD_ID_MASK;

    /* Setup the timer after transmit command */
    pcb->moal_start_timer(pmadapter->pmlan_cmd_timer, MFALSE, MRVDRV_TIMER_10S);

    pmadapter->cmd_timer_is_set = MTRUE;

    ret = MLAN_STATUS_SUCCESS;

  done:
    LEAVE();
    return ret;
}