/**************************************************************************** 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 "iot_io.h" #include "mac_rx_buf_ring.h" #include "hw_tonemap.h" #include "iot_config.h" #include "mac_txq_hw.h" #include "plc_mac_header.h" #include "plc_const.h" #include "mac_tx_hw.h" #include "rx_pb_reorder.h" #include "mac_crc.h" #include "mac_rx_hw.h" #include "hw_tonemap.h" #include "mpdu_header.h" #include "mac_sched_hw.h" #include "iot_system_api.h" const uint32_t mac_crc24_init_proto_tab[] = { CRC24_INIT_VECT_SG, /* 0: PLC_PROTO_TYPE_SG */ CRC24_INIT_VECT_GP, /* 1: PLC_PROTO_TYPE_GP */ //TODO: need to confirm CRC24_INIT_VECT_GP, /* 2: PLC_PROTO_TYPE_AV */ //TODO: need to confirm CRC24_INIT_VECT_SPG /* 3: PLC_PROTO_TYPE_SPG */ }; /* fc crc */ uint32_t mac_crc_get_fc_swcrc(uint32_t proto, void *fc) { IOT_ASSERT(fc); uint8_t mpdu_fc_len = mac_get_mpdu_fc_len(proto); uint8_t mpdu_fccs_len = mac_get_mpdu_fccs_len(proto); IOT_ASSERT(mpdu_fc_len > mpdu_fccs_len); return iot_getcrc24((uint8_t *)fc, (uint8_t)(mpdu_fc_len - mpdu_fccs_len)); } /* pb crc */ /** * if fw set pb_header fill in payload, pb_head = NULL; * otherwise pb_head = actual pb header buffer point */ uint32_t mac_crc_get_pb_swcrc(uint32_t proto, void *pb_head, uint8_t *payload, uint32_t pb_sz, uint8_t delimiter) { uint32_t crc = 0; uint8_t pb_crc_len = 0, pb_hdr_crc_len = 0, pb_hdr_len = 0; #if IOT_CRC_DBG_ENABLE uint32_t buffer[4] = {0}; buffer[0] = pb_sz; buffer[1] = (uint32_t)pb_head; buffer[2] = (uint32_t)payload; IOT_ASSERT_DUMP(((pb_sz >= PB_SIZE_72 && pb_sz <= PB_SIZE_520) && (iot_data_addr_legal((uint32_t)pb_head)) && (iot_data_addr_legal((uint32_t)payload))), buffer, 4); #endif switch(delimiter) { case FC_DELIM_BEACON: pb_hdr_crc_len = mac_get_pb_hdr_crc_len(FC_DELIM_BEACON, proto); #if SUPPORT_IEEE_1901 crc = iot_getcrc32_update(CRC32_INIT_VECT_I1901, payload, pb_sz - pb_hdr_crc_len); #else crc = iot_getcrc24((uint8_t *)payload, pb_sz - pb_hdr_crc_len); #endif break; case FC_DELIM_SOF: pb_crc_len = mac_get_pb_crc_len(FC_DELIM_SOF, proto); pb_hdr_crc_len = mac_get_pb_hdr_crc_len(FC_DELIM_SOF, proto); pb_hdr_len = mac_get_pb_hdr_len(FC_DELIM_SOF, proto); if (NULL == pb_head) { #if SUPPORT_IEEE_1901 crc = iot_getcrc32_update(CRC32_INIT_VECT_I1901, payload, pb_sz - pb_crc_len); #else crc = iot_getcrc24(payload, pb_sz - pb_crc_len); #endif } else { #if IOT_CRC_DBG_ENABLE buffer[3] = pb_hdr_crc_len; IOT_ASSERT_DUMP((pb_sz > pb_hdr_crc_len), buffer, 4); #endif #if SUPPORT_IEEE_1901 crc = iot_getcrc32_update(CRC32_INIT_VECT_I1901, (uint8_t *)pb_head, pb_hdr_len); crc = iot_getcrc32_update(crc, payload, pb_sz - pb_hdr_crc_len); #else crc = iot_getcrc24_update(mac_crc24_init_proto_tab[proto], (uint8_t *)pb_head, pb_hdr_len); crc = iot_getcrc24_update(crc, payload, pb_sz - pb_hdr_crc_len); #endif } break; default: crc = (uint32_t)CRC_INIT_VECT_DEFAULT; break; } return crc; } /* bcn crc */ uint32_t mac_crc_get_bcn_swcrc(uint32_t proto, void *payload, uint32_t pb_sz, uint32_t *crc_value) { IOT_ASSERT(payload); uint8_t pb_pld_crc_len = mac_get_pb_pld_crc_len(FC_DELIM_BEACON, proto); uint8_t pb_crc_len = mac_get_pb_crc_len(FC_DELIM_BEACON, proto); uint8_t pb_resv_len = 0; if (PLC_PROTO_TYPE_SPG == proto) pb_resv_len = 1; int32_t sl = pb_sz - pb_crc_len - pb_pld_crc_len - pb_resv_len; if(sl < 0) { return ERR_CRC_LEN; } #if SUPPORT_IEEE_1901 *crc_value = iot_getcrc32_update(CRC32_INIT_VECT_I1901, (uint8_t *)payload, (uint32_t)sl); #else *crc_value = iot_getcrc32((uint8_t *)payload, (uint32_t)sl); #endif return ERR_OK; } uint8_t mac_crc_set_bcn_swcrc(uint32_t proto, void *payload, uint32_t pb_sz) { uint32_t crc = 0, data_len = 0; uint8_t pb_crc_len = 0; uint8_t pb_pld_crc_len = 0; uint8_t pb_resv_len = 0; IOT_ASSERT(payload); switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: break; #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: pb_resv_len = 1; break; #endif default: return ERR_NOSUPP; } pb_crc_len = mac_get_pb_crc_len(FC_DELIM_BEACON, proto); pb_pld_crc_len = mac_get_pb_pld_crc_len(FC_DELIM_BEACON, proto); if (mac_tx_hw_get_bcn_swcrc_cfg()) { IOT_ASSERT(payload); uint32_t ret = 0; ret = mac_crc_get_bcn_swcrc(proto, payload, pb_sz, &crc); if(ret){ return (uint8_t)ret; } data_len = pb_sz - pb_crc_len - pb_pld_crc_len - pb_resv_len; os_mem_cpy((uint8_t *)payload + data_len, &crc, pb_pld_crc_len); } return ERR_OK; } uint32_t mac_crc_get_msdu_swcrc(uint32_t proto, iot_pkt_t *msdu) { uint8_t *data = NULL, crc_len = 0; uint16_t msdu_len = 0; uint32_t crc = 0; IOT_ASSERT(msdu); switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { mac_header_t *sg_mac = (mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)sg_mac; if (sg_mac->mac_exist_flag) { data += MAC_HDR_LEN_WITH_ADDR; } else { data += MAC_HDR_LEN_NO_ADDR; } msdu_len = sg_mac->msdu_len; crc_len = SG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { spg_mac_header_t *spg_mac = (spg_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)spg_mac; if (spg_mac->mac_hdr_type) { data += sizeof(spg_mac_header_t); } else { data += sizeof(spg_mac_header_t) + sizeof(spg_mac_lheader_tail_t); } msdu_len = spg_mac->msdu_len; crc_len = SPG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_GREEN_PHY case PLC_PROTO_TYPE_GP: { gp_mac_header_t *gp_mac = (gp_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)gp_mac; if (gp_mac->mft == 0 || gp_mac->mft == 1) { data += sizeof(gp_mac_header_t); } else { data += sizeof(gp_mac_header_t) + sizeof(gp_ats_or_cfder_t); } msdu_len = gp_mac->mfl; crc_len = GP_MAC_MSDU_CRC_LEN; break; } #endif default: return (uint32_t)CRC_INIT_VECT_DEFAULT; } if (iot_pkt_data_len(msdu) < (uint32_t)((uint32_t)msdu_len + (uint32_t)crc_len + (uint32_t)(data - iot_pkt_data(msdu)))) { return (uint32_t)CRC_INIT_VECT_DEFAULT; } crc = iot_getcrc32(data, msdu_len); return crc; } uint32_t mac_crc_get_msdu_srccrc(uint32_t proto, iot_pkt_t *msdu) { uint8_t *data = NULL, crc_len = 0; uint16_t msdu_len = 0; uint32_t crc = 0; IOT_ASSERT(msdu); switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { mac_header_t *sg_mac = (mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)sg_mac; if (sg_mac->mac_exist_flag) { data += MAC_HDR_LEN_WITH_ADDR; } else { data += MAC_HDR_LEN_NO_ADDR; } msdu_len = sg_mac->msdu_len; crc_len = SG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { spg_mac_header_t *spg_mac = (spg_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)spg_mac; if (spg_mac->mac_hdr_type) { data += sizeof(spg_mac_header_t); } else { data += sizeof(spg_mac_header_t) + sizeof(spg_mac_lheader_tail_t); } msdu_len = spg_mac->msdu_len; crc_len = SPG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_GREEN_PHY case PLC_PROTO_TYPE_GP: { gp_mac_header_t *gp_mac = (gp_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)gp_mac; if (gp_mac->mft == 0 || gp_mac->mft == 1) { data += sizeof(gp_mac_header_t); } else { data += sizeof(gp_mac_header_t) + sizeof(gp_ats_or_cfder_t); } msdu_len = gp_mac->mfl; crc_len = GP_MAC_MSDU_CRC_LEN; break; } #endif default: return (uint32_t)CRC_INIT_VECT_DEFAULT; } if (iot_pkt_data_len(msdu) < (uint32_t)((uint32_t)msdu_len + (uint32_t)crc_len + (uint32_t)(data - iot_pkt_data(msdu)))) { return (uint32_t)CRC_INIT_VECT_DEFAULT; } os_mem_cpy(&crc, data + msdu_len, crc_len); return crc; } uint8_t mac_crc_set_msdu_swcrc(uint32_t proto, iot_pkt_t *msdu) { uint8_t *data = NULL, crc_len = 0; uint16_t msdu_len = 0; uint32_t crc = 0; IOT_ASSERT(msdu); switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { #if SUPPORT_IEEE_1901 i1901_mac_header_t *i1901_mac; i1901_mac = (i1901_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)i1901_mac; if (i1901_mac_hdr_var_is_valid(i1901_mac)) { if (i1901_mac_hdr_var_addr_is_valid(i1901_mac)) { data += MAC_HDR_LEN_WITH_VAR_ADDR_I1901; } else { data += MAC_HDR_LEN_WITH_VAR_I1901; } } else { data += MAC_HDR_LEN_NO_VAR_I1901; } msdu_len = i1901_mac->msdu_len; crc_len = I1901_MAC_MSDU_CRC_LEN; #else /* SUPPORT_IEEE_1901 */ mac_header_t *sg_mac = (mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)sg_mac; if (sg_mac->version == MAC_HEADER_SHORT_VER) { mac_short_header_t *sg_mac_s = (mac_short_header_t *)iot_pkt_data(msdu); data += MAC_HDR_LEN_SHORT; msdu_len = sg_mac_s->msdu_len; } else { if (sg_mac->mac_exist_flag) { data += MAC_HDR_LEN_WITH_ADDR; } else { data += MAC_HDR_LEN_NO_ADDR; } msdu_len = sg_mac->msdu_len; #if SIMU_DBG == 1 if (sg_mac->msdu_type == 48) { iot_printf("mac sending msdu_type = 48, iot_pkt=0x%x\n", msdu); } #endif } crc_len = SG_MAC_MSDU_CRC_LEN; #endif /* SUPPORT_IEEE_1901 */ break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { spg_mac_header_t *spg_mac = (spg_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)spg_mac; if (spg_mac->version == SPG_MAC_HEADER_SHORT_VER) { spg_mac_short_header_t *spg_mac_s = (spg_mac_short_header_t *)iot_pkt_data(msdu); data += MAC_SINGLE_HOP_HDR_LEN_SPG; msdu_len = spg_mac_s->msdu_len; } else { if (spg_mac->mac_hdr_type) { data += sizeof(spg_mac_header_t); } else { data += sizeof(spg_mac_header_t) + sizeof(spg_mac_lheader_tail_t); } msdu_len = spg_mac->msdu_len; } crc_len = SPG_MAC_MSDU_CRC_LEN; break; } #endif #if SUPPORT_GREEN_PHY case PLC_PROTO_TYPE_GP: { gp_mac_header_t *gp_mac = (gp_mac_header_t *)iot_pkt_data(msdu); data = (uint8_t *)gp_mac; if (gp_mac->mft == 0 || gp_mac->mft == 1) { data += sizeof(gp_mac_header_t); } else { data += sizeof(gp_mac_header_t) + sizeof(gp_ats_or_cfder_t); } msdu_len = gp_mac->mfl; crc_len = GP_MAC_MSDU_CRC_LEN; break; } #endif default: return ERR_NOSUPP; } if (iot_pkt_data_len(msdu) < (uint32_t)((uint32_t)msdu_len + (uint32_t)crc_len + (uint32_t)(data - iot_pkt_data(msdu)))) { return ERR_INVAL; } IOT_ASSERT(msdu_len); #if SUPPORT_IEEE_1901 crc = iot_getcrc32_update(CRC32_INIT_VECT_I1901, data, msdu_len); #else crc = iot_getcrc32(data, msdu_len); #endif os_mem_cpy(data + msdu_len, &crc, crc_len); return ERR_OK; } uint8_t mac_crc_mpdu_swcrc_verify(uint32_t proto, rx_buf_hdr_t *rx_buf_hdr, uint8_t bit_mask) { uint8_t crc_ret = 0; uint32_t pb_sz = 0; uint32_t crc_src = 0, crc_cal = 0; uint8_t *pb_payload = NULL; uint8_t *tmp = NULL; IOT_ASSERT(rx_buf_hdr); pb_payload = (uint8_t *)rx_buf_hdr + PB_PAYLOAD_OFFSET; uint8_t delimiter = (uint8_t)mac_get_rx_delimiter_from_fc(proto, mac_rx_mpdu_st_get_fc_addr(&rx_buf_hdr->mpdu_st)); /* get rx fc message */ rx_fc_msg_t rx_fc_msg = {0}; mac_get_rx_frm_msg_from_fc(proto, mac_rx_mpdu_st_get_fc_addr(&rx_buf_hdr->mpdu_st), &rx_fc_msg); /* get pb size */ switch (delimiter) { case FC_DELIM_BEACON: { phy_get_pb_size(proto, rx_fc_msg.tmi, 0, &pb_sz); break; } case FC_DELIM_SOF: { phy_get_pb_size(proto, rx_fc_msg.tmi, rx_fc_msg.tmi_ext, &pb_sz); break; } default: pb_sz = 0; break; } /* debug msg */ #if (MAC_CRC_DEBUG_LEVEL > 1) iot_printf("pb_sz = 0x%X, pb data is:\r\n", pb_sz); uint32_t i = 0; for (i = 0; i < pb_sz; i++) { iot_printf("0x%02X ", *(pb_payload + i)); } iot_printf("\r\n"); #endif /* fc - crc24 */ if (bit_mask & FC_CRC_ERR_MASK) { tmp = (uint8_t *)mac_rx_mpdu_st_get_fc_addr(&rx_buf_hdr->mpdu_st); crc_cal = mac_crc_get_fc_swcrc(proto, tmp); crc_src = rx_fc_msg.fccs; if (crc_src != crc_cal) { crc_ret |= FC_CRC_ERR_MASK; } else { crc_ret &= ~FC_CRC_ERR_MASK; } #if (MAC_CRC_DEBUG_LEVEL) iot_printf("fc crc, src=0x%08X, cal=0x%08X\r\n", crc_src, crc_cal); #endif } /* pb crc - crc24 */ if (bit_mask & PB_CRC_ERR_MASK) { crc_src = mac_rx_pb_end_get_pb_crc(&rx_buf_hdr->pb_ed); if (mac_rx_get_pb_hdr_to_buf_cfg()) { crc_cal = mac_crc_get_pb_swcrc(proto, NULL, pb_payload, pb_sz, delimiter); } else { switch (proto) { #if SUPPORT_SMART_GRID case PLC_PROTO_TYPE_SG: { sg_sof_pb_hdr_t sg_pb_head = {0}; sg_pb_head.mac_frame_start = (uint8_t)rx_buf_hdr->pb_st.first_pb; sg_pb_head.mac_frame_end = (uint8_t)rx_buf_hdr->pb_st.last_pb; sg_pb_head.seq = (uint8_t)rx_buf_hdr->pb_st.ssn; crc_cal = mac_crc_get_pb_swcrc(proto, &sg_pb_head, pb_payload, pb_sz, delimiter); break; } #endif #if SUPPORT_SOUTHERN_POWER_GRID case PLC_PROTO_TYPE_SPG: { spg_sof_pb_hdr_t spg_pb_head = {0}; spg_pb_head.seq = (uint16_t)rx_buf_hdr->pb_st.ssn; spg_pb_head.resv = 0; crc_cal = mac_crc_get_pb_swcrc(proto, &spg_pb_head, pb_payload, pb_sz, delimiter); break; } #endif #if SUPPORT_GREEN_PHY case PLC_PROTO_TYPE_GP: { gp_sof_pb_hdr_t gp_pb_head = {0}; gp_pb_head.ssn = (uint16_t)rx_buf_hdr->pb_st.ssn; crc_cal = mac_crc_get_pb_swcrc(proto, &gp_pb_head, pb_payload, pb_sz, delimiter); break; } #endif default: crc_cal = 0; break; } } if (crc_src != crc_cal) { crc_ret |= PB_CRC_ERR_MASK; } else { crc_ret &= ~PB_CRC_ERR_MASK; } #if (MAC_CRC_DEBUG_LEVEL) iot_printf("pb crc, src=0x%08X, cal=0x%08X\r\n", crc_src, crc_cal); #endif } /* payload crc - crc32 */ if ((bit_mask & PAYLOAD_CRC_ERR_MASK) && (FC_DELIM_BEACON == delimiter)) { uint8_t pb_hdr_resv_crc_len = mac_get_pb_hdr_resv_crc_len(FC_DELIM_BEACON, proto); uint8_t pb_pld_crc_len = mac_get_pb_pld_crc_len(FC_DELIM_BEACON, proto); tmp = pb_payload + pb_sz - pb_hdr_resv_crc_len - pb_pld_crc_len; os_mem_cpy(&crc_src, tmp, pb_pld_crc_len); mac_crc_get_bcn_swcrc(proto, pb_payload, pb_sz, &crc_cal); if (crc_src != crc_cal) { crc_ret |= PAYLOAD_CRC_ERR_MASK; } else { crc_ret &= ~PAYLOAD_CRC_ERR_MASK; } #if (MAC_CRC_DEBUG_LEVEL) iot_printf("bcn payload crc, src=0x%08X, cal=0x%08X\r\n", crc_src, crc_cal); #endif } #if (MAC_CRC_DEBUG_LEVEL) if (NULL != rx_buf_hdr) { iot_printf("hw crc:bcn_crc=%d,pb_crc=%d,fc_crc=%d\r\n", rx_buf_hdr->pb_ed.rx_beacon_pld_crc_err, rx_buf_hdr->pb_ed.rx_pb_crc_err, rx_buf_hdr->att.is_fcserr); } else { iot_printf("None rx pb\r\n"); } iot_printf("sw crc cfg bit_mask = 0x%02X\r\n", bit_mask); iot_printf("sw crc:payload_crc=%d,pb_crc=%d,fc_crc=%d\r\n", (crc_ret & PAYLOAD_CRC_ERR_MASK) ? 1 : 0, (crc_ret & PB_CRC_ERR_MASK) ? 1 : 0, (crc_ret & FC_CRC_ERR_MASK) ? 1 : 0); #endif return crc_ret; } uint8_t mac_crc_msdu_swcrc_verify(uint32_t proto, iot_pkt_t *msdu) { uint8_t crc_ret = 0; uint32_t crc_src, crc_cal; IOT_ASSERT(msdu); crc_src = mac_crc_get_msdu_srccrc(proto, msdu); crc_cal = mac_crc_get_msdu_swcrc(proto, msdu); if (crc_src != crc_cal) { crc_ret |= PAYLOAD_CRC_ERR_MASK; } else { crc_ret &= ~PAYLOAD_CRC_ERR_MASK; } #if (MAC_CRC_DEBUG_LEVEL) iot_printf("msdu crc, src=0x%08X, cal=0x%08X\r\n", crc_src, crc_cal); #endif return crc_ret; }