/** * @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 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"); pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); if (pmbuf_src) { pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pmadapter->tx_buf_size, 0, MOAL_MALLOC_BUFFER); if (!pmbuf_aggr) { 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; pmbuf_aggr->in_ts_sec = pmbuf_src->in_ts_sec; pmbuf_aggr->in_ts_usec = pmbuf_src->in_ts_usec; if (pmbuf_src->flags & MLAN_BUF_FLAG_TDLS) pmbuf_aggr->flags |= MLAN_BUF_FLAG_TDLS; /* 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); if (pmbuf_src->flags & MLAN_BUF_FLAG_TCP_ACK) pmadapter->callbacks.moal_tcp_ack_tx_ind(pmadapter-> pmoal_handle, pmbuf_src); 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", 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: 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 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 decodes the rx packet & * calls corresponding handlers according to the packet type * * @param pmadapter A pointer to mlan_adapter structure * @param pmbuf A pointer to the SDIO data/cmd buffer * @param upld_typ Type of rx packet * @return MLAN_STATUS_SUCCESS */ static mlan_status wlan_decode_rx_packet(mlan_adapter * pmadapter, mlan_buffer * pmbuf, t_u32 upld_typ) { t_u8 *cmdBuf; t_u32 event; ENTER(); switch (upld_typ) { case MLAN_TYPE_DATA: PRINTM(MINFO, "--- Rx: Data packet ---\n"); pmbuf->data_len = (pmadapter->upld_len - INTF_HEADER_LEN); pmbuf->data_offset += INTF_HEADER_LEN; util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->rx_data_queue, (pmlan_linked_list) pmbuf, pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock); util_scalar_increment(pmadapter->pmoal_handle, &pmadapter->rx_pkts_queued, pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock); pmadapter->data_received = MTRUE; break; case MLAN_TYPE_CMD: PRINTM(MINFO, "--- Rx: Cmd Response ---\n"); /* take care of curr_cmd = NULL case */ if (!pmadapter->curr_cmd) { cmdBuf = pmadapter->upld_buf; if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) { wlan_process_sleep_confirm_resp(pmadapter, pmbuf->pbuf + pmbuf-> data_offset + INTF_HEADER_LEN, pmadapter-> upld_len - INTF_HEADER_LEN); } pmadapter->upld_len -= INTF_HEADER_LEN; memcpy(pmadapter, cmdBuf, pmbuf->pbuf + pmbuf->data_offset + INTF_HEADER_LEN, MIN(MRVDRV_SIZE_OF_CMD_BUFFER, pmadapter->upld_len - INTF_HEADER_LEN)); wlan_free_mlan_buffer(pmadapter, pmbuf); } else { pmadapter->cmd_resp_received = MTRUE; pmadapter->upld_len -= INTF_HEADER_LEN; pmbuf->data_len = pmadapter->upld_len; pmbuf->data_offset += INTF_HEADER_LEN; pmadapter->curr_cmd->respbuf = pmbuf; } break; case MLAN_TYPE_EVENT: PRINTM(MINFO, "--- Rx: Event ---\n"); event = *(t_u32 *) & pmbuf->pbuf[pmbuf->data_offset + INTF_HEADER_LEN]; pmadapter->event_cause = wlan_le32_to_cpu(event); if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) && ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) < MAX_EVENT_SIZE)) { memcpy(pmadapter, pmadapter->event_body, pmbuf->pbuf + pmbuf->data_offset + MLAN_EVENT_HEADER_LEN, pmadapter->upld_len - MLAN_EVENT_HEADER_LEN); } /* event cause has been saved to adapter->event_cause */ pmadapter->event_received = MTRUE; pmbuf->data_len = pmadapter->upld_len; pmadapter->pmlan_buffer_event = pmbuf; /* remove SDIO header */ pmbuf->data_offset += INTF_HEADER_LEN; pmbuf->data_len -= INTF_HEADER_LEN; break; default: PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ); wlan_free_mlan_buffer(pmadapter, pmbuf); break; } LEAVE(); return MLAN_STATUS_SUCCESS; }