/** * @brief Add TxPD to AMSDU header * * @param priv A pointer to mlan_private structure * @param mbuf Pointer to buffer where the TxPD will be formed * * @return N/A */ static void wlan_11n_form_amsdu_txpd(mlan_private * priv, mlan_buffer * mbuf) { TxPD *ptx_pd; mlan_adapter *pmadapter = priv->adapter; ENTER(); ptx_pd = (TxPD *) mbuf->pbuf; memset(pmadapter, ptx_pd, 0, sizeof(TxPD)); /* * Original priority has been overwritten */ ptx_pd->priority = (t_u8) mbuf->priority; ptx_pd->pkt_delay_2ms = wlan_wmm_compute_driver_packet_delay(priv, mbuf); ptx_pd->bss_num = GET_BSS_NUM(priv); ptx_pd->bss_type = priv->bss_type; /* Always zero as the data is followed by TxPD */ ptx_pd->tx_pkt_offset = sizeof(TxPD); ptx_pd->tx_pkt_type = PKT_TYPE_AMSDU; if (mbuf->flags & MLAN_BUF_FLAG_TDLS) ptx_pd->flags = MRVDRV_TxPD_FLAGS_TDLS_PACKET; if (ptx_pd->tx_control == 0) /* TxCtrl set by user or default */ ptx_pd->tx_control = priv->pkt_tx_ctrl; endian_convert_TxPD(ptx_pd); LEAVE(); }
/** * @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 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_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf) { mlan_private *pmpriv = (mlan_private *) priv; pmlan_adapter pmadapter = pmpriv->adapter; TxPD *plocal_tx_pd; t_u8 *head_ptr = MNULL; ENTER(); if (!pmbuf->data_len) { PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n", pmbuf->data_len); pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID; goto done; } if (pmbuf->data_offset < (sizeof(TxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT)) { PRINTM(MERROR, "not enough space for TxPD: %d\n", 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(TxPD) - INTF_HEADER_LEN; head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1))); plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN); memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD)); /* 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 (pmadapter->pps_uapsd_mode) { if (MTRUE == wlan_check_last_packet_indication(pmpriv)) { pmadapter->tx_lock_flag = MTRUE; plocal_tx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET; } } /* 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; } 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) (head_ptr - pmbuf->pbuf); pmbuf->data_len -= pmbuf->data_offset; done: LEAVE(); return head_ptr; }