/** * @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(¶m, 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(¶m, 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, ¶m, 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; }
/** * @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(¶m, 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(¶m, 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, ¶m, 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; }
/** * @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; }
/** * @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(¶m, 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(¶m, 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, ¶m, 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; }
/** * @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; }
/** * @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; }
/** * @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; }
/** * @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; }
/** * @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; }
/** * @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; }