Files
kunlun/plc/halmac/data/mac_data.c
2024-09-28 14:24:04 +08:00

594 lines
19 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "beacon_frame.h"
#include "beacon.h"
#include "iot_errno.h"
#include "iot_io.h"
#include "mac_bcm_api.h"
#include "mpdu_frame.h"
#include "mac_tx_hw.h"
#include "mac_data_api.h"
#include "iot_pkt_api.h"
#include "mac_data.h"
#include "os_mem.h"
#include "mac_desc_engine.h"
#include "plc_mac_header.h"
#include "hw_tonemap.h"
#include "iot_crc.h"
#include "iot_utils.h"
#include "mac_msg.h"
#include "mac.h"
#include "mac_crc.h"
#include "iot_bitops.h"
#include "mac_peer.h"
#include "rate_control.h"
#include "hw_desc.h"
#include "mac_stream.h"
#include "sw_sched.h"
#include "iot_module.h"
#include "phy_bb.h"
#include "plc_mac_cfg.h"
#if CPLC_IOT_CERT_SUPPORT
#include "mac_cert_test.h"
#include "plc_cert_test.h"
#endif
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "mac_pm.h"
#include "mac_pdev.h"
#include "mac_status.h"
#include "mac_mm_sniffer.h"
#if SUPPORT_IEEE_1901
static void mac_data_msdu_i1901_to_sg(iot_pkt_t *src_msdu)
{
uint8_t *data, *tmp_addr;
mac_rx_info_t *src_rx_info, tmp_rx_info;
i1901_mac_header_t *i1901_mac_hdr;
frame_control_t *sg_fc;
uint8_t buff[MAC_HDR_LEN_WITH_ADDR] = {0};
mac_header_t *sg_mac_hdr = (mac_header_t *)buff;
uint8_t sg_mac_hdr_len;
data = iot_pkt_data(src_msdu);
src_rx_info = (mac_rx_info_t *)(data - sizeof(*src_rx_info));
os_mem_cpy(&tmp_rx_info, src_rx_info, sizeof(mac_rx_info_t));
i1901_mac_hdr = (i1901_mac_header_t *)data;
uint32_t i1901_hdr_len;
if (i1901_mac_hdr_var_is_valid(i1901_mac_hdr)) {
sg_mac_hdr->org_src_tei = (uint16_t)i1901_mac_hdr->var[0].org_src_tei;
sg_mac_hdr->org_dest_tei = (uint16_t)i1901_mac_hdr->var[0].org_dest_tei;
sg_mac_hdr->total_hop_cnt = (uint8_t)i1901_mac_hdr->var[0].total_hop_cnt;
sg_mac_hdr->rest_hop_cnt = (uint8_t)i1901_mac_hdr->var[0].rest_hop_cnt;
sg_mac_hdr->main_path_flag = (uint16_t)i1901_mac_hdr->var[0].main_path_flag;
sg_mac_hdr->bc_direction = (uint16_t)i1901_mac_hdr->var[0].bc_direction;
sg_mac_hdr->network_sn = (uint8_t)i1901_mac_hdr->var[0].network_sn;
#if PLC_SILA_NHM_ENABLE
sg_mac_hdr->mac_exist_flag = (uint8_t)i1901_mac_hdr->var[0].mac_exist_flag;
#else
sg_mac_hdr->mac_exist_flag = 0;
#endif
if (sg_mac_hdr->mac_exist_flag) {
i1901_hdr_len = MAC_HDR_LEN_WITH_VAR_ADDR_I1901;
sg_mac_hdr_len = MAC_HDR_LEN_WITH_ADDR;
tmp_addr = data + sizeof(i1901_mac_header_t) +
sizeof(i1901_mac_header_var_t);
os_mem_cpy(sg_mac_hdr->mac[0], tmp_addr, IOT_MAC_ADDR_LEN * 2);
} else {
i1901_hdr_len = MAC_HDR_LEN_WITH_VAR_I1901;
sg_mac_hdr_len = MAC_HDR_LEN_NO_ADDR;
}
} else {
i1901_hdr_len = MAC_HDR_LEN_NO_VAR_I1901;
sg_mac_hdr_len = MAC_HDR_LEN_NO_ADDR;
sg_fc = (frame_control_t *)src_rx_info->fc;
sg_mac_hdr->org_src_tei = (uint16_t)sg_fc->vf.sof.src_tei;
sg_mac_hdr->org_dest_tei = (uint16_t)sg_fc->vf.sof.dst_tei;
sg_mac_hdr->total_hop_cnt = 0;
sg_mac_hdr->rest_hop_cnt = 0;
sg_mac_hdr->main_path_flag = 0;
sg_mac_hdr->bc_direction = 0;
sg_mac_hdr->network_sn = 0;
sg_mac_hdr->mac_exist_flag = 0;
}
sg_mac_hdr->version = i1901_mac_hdr->version;
sg_mac_hdr->send_type = i1901_mac_hdr->send_type;
sg_mac_hdr->send_max_cnt = i1901_mac_hdr->send_max_cnt;
sg_mac_hdr->msdu_sn = i1901_mac_hdr->msdu_sn;
sg_mac_hdr->msdu_type = i1901_mac_hdr->msdu_type;
sg_mac_hdr->msdu_len = i1901_mac_hdr->msdu_len;
sg_mac_hdr->reboot_cnt = i1901_mac_hdr->reboot_cnt;
sg_mac_hdr->path_fix_flag = 0; /* ieee1901 not this field */
/* get new mac header addr */
tmp_addr = data + i1901_hdr_len - sg_mac_hdr_len;
/* copy sg mac header into rx buffer */
os_mem_cpy(tmp_addr, sg_mac_hdr, sg_mac_hdr_len);
/* update rx buffer pkt data addr */
iot_pkt_set_data(src_msdu, tmp_addr);
/* get new rx info addr */
tmp_addr -= sizeof(mac_rx_info_t);
/* copy rx info into rx buffer */
os_mem_cpy(tmp_addr, &tmp_rx_info, sizeof(mac_rx_info_t));
}
void mac_data_msdu_sg_to_i1901(iot_pkt_t *src_msdu)
{
uint16_t sg_mac_hdr_len, i1901_mac_hdr_len;
uint8_t i1901_mac_l_hdr[MAC_HDR_LEN_WITH_VAR_ADDR_I1901] = {0};
i1901_mac_header_t *i1901_mac_hdr = (i1901_mac_header_t *)i1901_mac_l_hdr;
mac_header_t *sg_mac_hdr;
uint16_t len;
uint8_t *addr;
sg_mac_hdr = (mac_header_t *)iot_pkt_data(src_msdu);
sg_mac_hdr_len = sg_mac_hdr->mac_exist_flag ? MAC_HDR_LEN_WITH_ADDR
: MAC_HDR_LEN_NO_ADDR;
/* sg mac header to ieee 1901 mac header */
i1901_mac_hdr->version = I1901_MAC_HDR_STD_VER;
i1901_mac_hdr->send_type = (uint8_t)sg_mac_hdr->send_type;
i1901_mac_hdr->send_max_cnt = sg_mac_hdr->send_max_cnt;
i1901_mac_hdr->msdu_sn = sg_mac_hdr->msdu_sn;
i1901_mac_hdr->msdu_type = sg_mac_hdr->msdu_type; //TODO:
i1901_mac_hdr->msdu_len = sg_mac_hdr->msdu_len; //check max length
i1901_mac_hdr->reboot_cnt = sg_mac_hdr->reboot_cnt;
#if PLC_SILA_NHM_ENABLE
i1901_mac_hdr->mac_frame_type = 1;
#else
i1901_mac_hdr->mac_frame_type = 0;
#endif
i1901_mac_hdr->var[0].org_src_tei = sg_mac_hdr->org_src_tei;
i1901_mac_hdr->var[0].org_dest_tei = sg_mac_hdr->org_dest_tei;
i1901_mac_hdr->var[0].total_hop_cnt = sg_mac_hdr->total_hop_cnt;
i1901_mac_hdr->var[0].rest_hop_cnt = sg_mac_hdr->rest_hop_cnt;
i1901_mac_hdr->var[0].main_path_flag = (uint8_t)sg_mac_hdr->main_path_flag;
i1901_mac_hdr->var[0].bc_direction = (uint8_t)sg_mac_hdr->bc_direction;
i1901_mac_hdr->var[0].network_sn = sg_mac_hdr->network_sn;
#if PLC_SILA_NHM_ENABLE
i1901_mac_hdr->var[0].mac_exist_flag = 0; //TODO: enable filling mac addr
if (i1901_mac_hdr->var[0].mac_exist_flag) {
i1901_mac_hdr_len = MAC_HDR_LEN_WITH_VAR_ADDR_I1901;
addr = i1901_mac_l_hdr + sizeof(i1901_mac_header_t) +
sizeof(i1901_mac_header_var_t);
os_mem_cpy(addr, sg_mac_hdr->mac[0], IOT_MAC_ADDR_LEN * 2);
} else {
i1901_mac_hdr_len = MAC_HDR_LEN_WITH_VAR_I1901;
}
#else
i1901_mac_hdr->var[0].mac_exist_flag = 0;
i1901_mac_hdr_len = MAC_HDR_LEN_WITH_VAR_I1901;
#endif
if (i1901_mac_hdr_len > sg_mac_hdr_len) {
len = i1901_mac_hdr_len - sg_mac_hdr_len;
IOT_ASSERT(iot_pkt_block_len(src_msdu, IOT_PKT_BLOCK_HEAD) >=
(sizeof(mac_tx_info) + sizeof(frame_control_t) + len));
addr = iot_pkt_push(src_msdu, len);
} else {
len = sg_mac_hdr_len - i1901_mac_hdr_len;
addr = iot_pkt_pull(src_msdu, len);
}
os_mem_cpy(addr, i1901_mac_hdr, i1901_mac_hdr_len);
}
#else /* SUPPORT_IEEE_1901 */
#define mac_data_msdu_i1901_to_sg(src_msdu)
#define mac_data_msdu_sg_to_i1901(src_msdu)
#endif /* SUPPORT_IEEE_1901 */
uint32_t mac_data_rx_msdu(mac_vdev_t *vdev, iot_pkt_t *msdu_buf)
{
uint8_t *data;
uint8_t *msdu_crc_ptr = NULL;
uint32_t msdu_crc_old;
uint8_t proto = (uint8_t)PHY_PROTO_TYPE_GET();
uint16_t msdu = 0;
uint16_t mac_hdr_len = 0;
IOT_ASSERT(vdev && msdu_buf);
mac_add_rx_msdu_cnt();
/*check crc*/
data = iot_pkt_data(msdu_buf);
mac_msdu_frame_info_get(proto, msdu_buf, &msdu_crc_ptr, \
&msdu, &mac_hdr_len);
if(msdu == 0)
{
mac_add_rx_msdu_len_is_0_cnt();
iot_printf("msdu len is 0 cnt:%d\n", mac_get_rx_msdu_len_is_0_cnt());
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO,
IOT_MAC_RX_MSDU_LEN_INVALID_ID, 1, mac_get_rx_msdu_len_is_0_cnt());
iot_pkt_free(msdu_buf);
return ERR_FAIL;
}
IOT_ASSERT(msdu_crc_ptr && (mac_hdr_len > 0));
data += mac_hdr_len;
#ifndef DISABLE_SW_SOF_PAYLOAD_CRC_CHECK
#if SUPPORT_IEEE_1901
uint32_t msdu_crc_new = iot_getcrc32_update(0, data, msdu);
#else
uint32_t msdu_crc_new = iot_getcrc32(data, msdu);
#endif
os_mem_cpy(&msdu_crc_old, msdu_crc_ptr, sizeof(msdu_crc_old));
if (msdu_crc_old != msdu_crc_new)
{
mac_add_rx_msdu_crc_err_cnt();
iot_printf("msdu crc err cnt:%d\n", mac_get_rx_msdu_crc_err_cnt());
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_INFO,
IOT_MAC_RX_MSDU_CRC_CNT_ID, 1, mac_get_rx_msdu_crc_err_cnt());
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
/* should not happen as the pb's crc is passed */
IOT_ASSERT(0);
#endif
iot_pkt_free(msdu_buf);
return ERR_FAIL;
}
#endif
/* trim this iot pkt to msdu len */
IOT_ASSERT(iot_pkt_set_tail(msdu_buf, msdu_crc_ptr));
#if ((MAC_MM_SNIFFER_MODE == MAC_SNIFFER_TYPE_MSDU) || \
((MAC_MM_SNIFFER_MODE == MAC_SNIFFER_TYPE_MSDU_UART)))
mac_mm_sniffer_rx_msdu(proto, msdu_buf);
iot_pkt_free(msdu_buf);
return ERR_OK;
#endif
/* convert ieee 1901 msdu data to sg */
mac_data_msdu_i1901_to_sg(msdu_buf);
#if CPLC_IOT_CERT_SUPPORT
switch (mac_get_cert_test_mode()) {
case CERT_TEST_CMD_ENTER_MAC_T:
case CERT_TEST_CMD_ENTER_SEC:
iot_printf("msdu:len%d forward to uart\n", msdu);
if(g_mt_ctxt && g_mt_ctxt->mt_msdu_tx_funt) {
g_mt_ctxt->mt_msdu_tx_funt(vdev->start_cfg.mac_callback_arg,
msdu_buf);
} else {
iot_pkt_free(msdu_buf);
}
return 0;
default:
break;
}
#endif
/* upload to upper layer */
#if PLC_MAC_RX_DEBUG_LOG
iot_printf("msdu len %d formed \n", msdu);
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_INFO,
IOT_MAC_RX_MSDU_LENGTH_ID, 1, msdu);
#endif
if (vdev->start_cfg.mac_data_rx_func) {
#if (SIMU_DBG > 3)
iot_printf("%s, msdu->buf = %p", __FUNCTION__, iot_pkt_block_ptr(msdu_buf, IOT_PKT_BLOCK_DATA));
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_INFO,
IOT_MAC_RX_MSDU_PTR_ID, 1, iot_pkt_block_ptr(msdu_buf, IOT_PKT_BLOCK_DATA));
#endif
vdev->start_cfg.mac_data_rx_func(vdev->start_cfg.mac_callback_arg,
msdu_buf);
}
else {
iot_pkt_free(msdu_buf);
}
return ERR_OK;
}
uint32_t mac_send_msdu_ex_internal(pdevid_t pdev_id, vdevid_t vdev_id,
iot_pkt_t* msdu_buf, mac_tx_info *tx_info)
{
mac_pdev_t *pdev = get_pdev_ptr(pdev_id);
if(pdev->mac_pm.mac_pm_flag && !tx_info->pw_collapse)
{
iot_printf("mac entry power off mode, dorp non power_off_pkt\n");
return ERR_FAIL;
}
if(pdev->mac_pm.mac_pm_flag)
{
iot_printf("send power_off report pkt_\n");
}
lid_t lid = tx_info->link_id;
uint32_t bcn_region_type;
uint8_t *data = iot_pkt_data(msdu_buf);
uint8_t proto = (uint8_t)PHY_PROTO_TYPE_GET();
uint8_t retry_cnt = 0;
uint8_t l_phase;
uint8_t stream_trxn = IS_TX_STREAM;
#if PLC_SUPPORT_DBG_PKT_MODE
/* check meter dbg mode parameter valid */
if (tx_info->is_dbg_pkt) {
//check link id
if (lid > (lid_t)LID_CSMA_CAP3) {
lid = (lid_t)PLC_DBG_PKT_MODE_DEF_LID;
}
stream_trxn = IS_DBG_TX_STREAM;
/* fix debug pkt mode vdev id */
vdev_id = (vdevid_t)pdev->dbg_pkt_vdev_id;
IOT_ASSERT(vdev_id != (vdevid_t)PLC_INV_DBG_PKT_MODE_VDEV_ID);
}
#endif
mac_vdev_t *vdev = get_vdev_ptr(pdev_id, vdev_id);
if (!vdev->is_up || vdev->stop_flag) {
iot_printf("vdev %d not ready\n", vdev_id);
return ERR_NOT_READY;
}
if (vdev->tx_rx_suspend) {
return ERR_FAIL;
}
#if PLC_SUPPORT_DBG_PKT_MODE
if (!vdev_get_block_dbg_pkt_4_rx_only(vdev) && tx_info->is_dbg_pkt) {
lid += LID_BCSMA_START;
}
#endif
bcn_region_type = mac_get_bcn_region_type(lid);
/* check if has token for current sending */
if (ERR_NOMEM == mac_token_check(bcn_region_type, lid, 0)) {
iot_printf("warning:%s:no msdu for sending,lid=%d\r\n", \
__FUNCTION__, lid);
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_WARN,
IOT_MAC_WARING_NO_MSDU_FOR_SEND_ID, 1, lid);
mac_add_no_msdu_to_send_cnt();
return ERR_NOMEM;
}
/* convert sg msdu data to ieee1901 */
mac_data_msdu_sg_to_i1901(msdu_buf);
/* put crc len */
iot_pkt_put(msdu_buf, sizeof(uint32_t));
IOT_ASSERT(ERR_OK == mac_crc_set_msdu_swcrc(proto, msdu_buf));
/* for sof frame, find the correct peer and stream
* if the peer or stream is not created, then create it
* here
*/
uint32_t vdev_nid;
tei_t dtei = tx_info->receiver;
uint32_t ret;
mac_stream_t *stream;
mac_peer_t *peer;
if (ERR_OK != vdev_get_nid(vdev, (nid_t *)&vdev_nid)) {
iot_printf("warning:not nid for send,vid:%d,reduced:%d\r\n",\
vdev->vdev_id, vdev->mac_vdev_cfg.is_reduced_vdev);
return ERR_FAIL;
}
if (dtei == PLC_TEI_BCAST) {
/* broadcast address
* return bcast peer
*/
peer = (mac_peer_t*)vdev->bcast_peer;
/* must be a bcast flag */
IOT_ASSERT(tx_info->bcast);
}
else {
peer = find_peer(vdev, vdev_nid, dtei);
}
if (!peer) {
/* if the peer is not exist,
* create it right now
*/
ret = mac_peer_alloc(vdev, dtei, \
0, 1, 0, 0, &peer);
if (ret) {
/* create peer failed */
IOT_ASSERT(0);
}
}
stream = find_stream(peer, vdev_nid,
dtei, lid, stream_trxn, IS_PLC_STREAM);
if (!stream) {
/* if stream is not found
* create it now
*/
ret = mac_stream_alloc(peer, stream_trxn,
lid, IS_PLC_STREAM, &stream);
if (ret != ERR_OK && ret != ERR_EXIST) {
/* create stream failed */
IOT_ASSERT(0);
}
}
if (tx_info->phase > PLC_PHASE_CNT
|| tx_info->phase == PLC_PHASE_ALL) {
tx_info->phase = PLC_PHASE_A;
}
l_phase = tx_info->phase;
if (PLC_SUPPORT_CCO_TX_3_PHASE_SLOT ||
(mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO)) {
/* note that for sta role device, we always send packet in phase A hwq.
* logical phase only control the time slot the packet to be sent.
* while for cco role device, we always use phase A hwq as packet
* alwasy be sent in 3 physical phases simultaneously. logical phase
* only control the physical phase rx.
*/
tx_info->phase = PLC_PHASE_A;
}
mac_msdu_frame_t *mac_frame;
mac_desc_get(&g_mac_desc_eng, PLC_MAC_MSDU_FRAME_POOL, \
(void **)&mac_frame);
IOT_ASSERT(mac_frame);
if (tx_info->retry_prior) {
retry_cnt = (uint8_t)tx_info->retry_cnt;
} else {
retry_cnt = mac_msdu_retry_cnt_get(proto, data);
if (retry_cnt > 0) {
/* if retry_cnt exist,
* use it in mac header
*/
retry_cnt -= 1;
} else {
/* if mac header retry cnt = 0
* use retry cnt in tx_info
*/
retry_cnt = (uint8_t)tx_info->retry_cnt;
if (retry_cnt == 0) {
/* if tx_info retry cnt also = 0
* use retry cnt default value
*/
if (dtei != PLC_TEI_BCAST) {
retry_cnt = MAC_DEF_RETRY_CNT;
} else {
retry_cnt = MAC_BCAST_DEF_RETRY_CNT;
}
}
}
}
if (dtei != PLC_TEI_BCAST) {
retry_cnt = retry_cnt > MAC_UCAST_MAX_RETRY_CNT ? \
MAC_UCAST_MAX_RETRY_CNT : retry_cnt;
} else {
retry_cnt = retry_cnt > MAC_BCAST_MAX_RETRY_CNT ? \
MAC_BCAST_MAX_RETRY_CNT : retry_cnt;
}
/* NOTE: kl1 HW retry design: HW_retry_cnt = retry_cnt;
* tx cnt = HW_retry_cnt + 1;
* kl2 HW retry design: HW_retry_cnt = retry_cnt;
* tx cnt = HW_retry_cnt;
* SW retry action: tx cnt = retry_cnt;
*
* kl1 HW retry have a bug, so we need use SW retry replace HW retry.
* kl2 directly use HW retry.
*/
retry_cnt++;
/* calculate retry cnt if multi-band mode */
retry_cnt = mac_get_tx_retry_cnt_by_band(vdev,
phy_band_id_get(), retry_cnt);
mac_frame_list_init(mac_frame, msdu_buf, tx_info->bcast,
tx_info->phase, l_phase, retry_cnt, tx_info->is_dbg_pkt,
tx_info->tx_3_phase, !tx_info->same_vendor, tx_info->ppm_step,
tx_info->ppm_step_type);
if (!stream->msdu.tx.mac_frame_list) {
stream->msdu.tx.mac_frame_list = mac_frame;
stream->msdu.tx.last_mac_frame = mac_frame;
stream->msdu.tx.mac_frame_num = 1;
}
else {
/* TODO: put it at the end of list */
stream->msdu.tx.last_mac_frame->next = mac_frame;
stream->msdu.tx.last_mac_frame = mac_frame;
stream->msdu.tx.mac_frame_num++;
}
/* check if need to decrease token number */
mac_token_alloc(bcn_region_type, lid, 0);
/* TODO: put the stream to the swq */
mac_queue_t swq_id;
swq_id = mac_q_get_swq_type(bcn_region_type, \
tx_info->phase, (lid_t)lid);
/* check if swq type is support */
if (swq_id == MAX_MAC_QUE_NUM)
{
/* swq type error */
IOT_ASSERT(0);
}
mac_swsch_append(g_mac_swq[swq_id], tx_info->phase, stream);
#if STATIC_POWER_SAVE
if (pdev->mac_pm.is_start) {
mac_pm_stop(pdev);
}
#endif
mac_add_send_msdu_cnt();
/* trigger the sw scheduler to send */
/* send a msg to self */
return mac_swsch_trigger_tx(pdev_id, vdev_id);
}
/* interface expose to high mac - CL layer */
uint32_t mac_send_msdu_ex(pdevid_t pdev_id, vdevid_t vdev_id,
iot_pkt_t* msdu_buf, mac_tx_info *tx_info)
{
uint8_t *data;
uint32_t ret = 0;
#if ((MAC_MM_SNIFFER_MODE == MAC_SNIFFER_TYPE_MSDU) || \
((MAC_MM_SNIFFER_MODE == MAC_SNIFFER_TYPE_MSDU_UART)))
iot_pkt_free_tx_done(msdu_buf, IOT_PKT_STATE_TX_FAIL);
return ERR_OK;
#endif
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
iot_pkt_free_tx_done(msdu_buf, IOT_PKT_STATE_TX_FAIL);
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
/* make sure packet is started with 4 bytes aligned */
data = iot_pkt_data(msdu_buf);
IOT_ASSERT(((uint32_t)data & 0x3) == 0);
BUILD_BUG_ON(MAC_REQ_HEAD_RSVD_LEN >=
(sizeof(mac_tx_info) + sizeof(frame_control_t)));
/* put tx_info in the header of iot_pkt */
mac_tx_info *info = (mac_tx_info *)iot_pkt_block_ptr(msdu_buf,
IOT_PKT_BLOCK_HEAD);
IOT_ASSERT(info);
os_mem_cpy(info, tx_info, sizeof(mac_tx_info));
msg->type = MAC_MSG_TYPE_CVG;
msg->id = MAC_MSG_ID_CVG_MSDU_SEND;
msg->data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->data2 = msdu_buf;
msg->data3 = info;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
out:
return ret;
}