/**************************************************************************** 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 "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 "hw_desc.h" #include "mac_stream.h" #include "phy_bb.h" #include "plc_mac_cfg.h" #include "plc_utils.h" #include "mac_pdev.h" #include "mac_rf_pdev.h" #include "mac_rf_vdev.h" #include "sw_sched.h" #include "mac_crypto.h" #if HPLC_RF_DEV_SUPPORT static uint32_t mac_check_rf_msdu_len(uint8_t proto, iot_pkt_t *msdu_buf) { uint32_t len = 0; switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { len = sizeof(sg_sof_pb_520_t) - SG_SOF_PB_HDR_CRC_LEN - SG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { len = sizeof(spg_sof_pb_520_t) - SPG_SOF_PB_HDR_CRC_LEN - SPG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_GREEN_PHY case PLC_PROTO_TYPE_GP: { len = sizeof(gp_sof_pb_520_t) - GP_SOF_PB_HDR_CRC_LEN - GP_MAC_MSDU_CRC_LEN; break; } #endif default: IOT_ASSERT(0); } /* rf mpdu frame only support 1pb of 520 bytes */ if (iot_pkt_data_len(msdu_buf) > len) { return ERR_FAIL; } return ERR_OK; } uint32_t mac_send_rf_msdu_ex_internal(pdevid_t pdev_id, vdevid_t vdev_id, iot_pkt_t* msdu_buf, mac_tx_info *tx_info) { uint32_t ret = ERR_OK; mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(pdev_id, RF_PDEV_ID); if (!rf_pdev) { return ERR_NOSUPP; } mac_vdev_t *vdev = NULL; lid_t lid = tx_info->link_id; 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 */ mac_pdev_t *pdev = get_pdev_ptr(pdev_id); vdev_id = (vdevid_t)pdev->dbg_pkt_vdev_id; IOT_ASSERT(vdev_id != (vdevid_t)PLC_INV_DBG_PKT_MODE_VDEV_ID); } #endif vdev = get_vdev_ptr(pdev_id, vdev_id); mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(pdev_id, RF_PDEV_ID, vdev->rf_vdev_id); uint8_t *data = iot_pkt_data(msdu_buf); uint8_t proto = (uint8_t)PHY_PROTO_TYPE_GET(); uint8_t retry_cnt = 0; mac_peer_t *peer = NULL; mac_stream_t *stream = NULL; mac_msdu_frame_t *mac_frame = NULL; #if ENA_RF_CSMA_BCN_HWQ if (rf_vdev_get_node_role(rf_vdev) != PLC_DEV_ROLE_CCO) { /* lid 3 to csma beacon */ if (lid == LID_CSMA_CAP3) { lid = LID_CSMA_CAP2; } else if (lid == LID_CSMA_CAP2) { lid = LID_CSMA_CAP1; } else if (lid == LID_CSMA_CAP1) { lid = LID_CSMA_CAP0; } } #endif uint32_t bcn_region_type = mac_get_bcn_region_type(lid); mac_rf_queue_t swq_id; uint32_t vdev_nid; tei_t dtei = tx_info->receiver; if (!vdev || !rf_vdev) { return ERR_NOSUPP; } if (!vdev->is_up || vdev->stop_flag || rf_vdev->stop_flag) { iot_printf("plc vdev %d or rf vdev %d not ready\n", vdev_id, vdev->rf_vdev_id); return ERR_NOT_READY; } if (rf_vdev->tx_rx_suspend) { return ERR_FAIL; } if (mac_check_rf_msdu_len(proto, msdu_buf)) { iot_printf("warning:rf msdu len = %lu exceed!\n", iot_pkt_data_len(msdu_buf)); return ERR_FAIL; } /* check if has token for current sending */ if (ERR_NOMEM == mac_token_check(bcn_region_type, lid, 1)) { iot_printf("warning:rf no msdu for send,lid=%d\n", lid); /* TODO: add flash log and add no msdu send count */ return ERR_NOMEM; } 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; } /* put crc len */ iot_pkt_put(msdu_buf, sizeof(uint32_t)); if (tx_info->is_encrypt) { if (mac_crypto_check_msdu_buf(vdev, &msdu_buf, proto) != ERR_OK) { tx_info->is_encrypt = 0; IOT_ASSERT(ERR_OK == mac_crc_set_msdu_swcrc(proto, msdu_buf)); } } else { IOT_ASSERT(ERR_OK == mac_crc_set_msdu_swcrc(proto, msdu_buf)); } retry_cnt = mac_msdu_retry_cnt_get(proto, data); if (retry_cnt == 0) { /* 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_RF_DEF_RETRY_CNT; } else { retry_cnt = MAC_RF_BCAST_DEF_RETRY_CNT; } } } if (dtei != PLC_TEI_BCAST) { retry_cnt = retry_cnt > MAC_RF_UCAST_MAX_RETRY_CNT ? \ MAC_RF_UCAST_MAX_RETRY_CNT : retry_cnt; } else { retry_cnt = retry_cnt > MAC_RF_BCAST_MAX_RETRY_CNT ? \ MAC_RF_BCAST_MAX_RETRY_CNT : retry_cnt; } 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_RF_STREAM); if (!stream) { /* if stream is not found create it now */ ret = mac_stream_alloc(peer, stream_trxn, lid, IS_RF_STREAM, &stream); if (ret != ERR_OK && ret != ERR_EXIST) { /* create stream failed */ IOT_ASSERT(0); } } mac_desc_get(&g_mac_desc_eng, PLC_MAC_MSDU_FRAME_POOL, (void **)&mac_frame); IOT_ASSERT(mac_frame); mac_frame_list_init(mac_frame, msdu_buf, tx_info->bcast, tx_info->phase, 0, 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); mac_frame->need_encrypt = tx_info->is_encrypt; mac_frame->key_idx = (uint8_t)tx_info->key_idx; 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, 1); swq_id = mac_rf_q_get_swq_type(bcn_region_type, lid, tx_info->is_dbg_pkt); /* check if swq type is support */ if (swq_id == MAX_MAC_RF_QUE_NUM) { /* swq type error */ IOT_ASSERT(0); } mac_swsch_append(mac_swsch_get_g_swq(swq_id, 1), PLC_PHASE_A, stream); return mac_rf_swsch_trigger_tx(RF_PDEV_ID, rf_vdev->rf_vdev_id); } #endif /* HPLC_RF_DEV_SUPPORT */