mbed-os/source/MAC/IEEE802_15_4/mac_header_helper_functions.c

786 lines
24 KiB
C

/*
* Copyright (c) 2016-2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include "ns_types.h"
#include "string.h"
#include "ns_trace.h"
#include "mlme.h"
#include "mac_api.h"
#include "fhss_api.h"
#include "common_functions.h"
#include "mac_common_defines.h"
#include "MAC/IEEE802_15_4/mac_defines.h"
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
#include "MAC/IEEE802_15_4/mac_header_helper_functions.h"
#include "MAC/rf_driver_storage.h"
static uint8_t *mcps_mac_security_aux_header_start_pointer_get(const mac_pre_parsed_frame_t *buffer);
static uint8_t *mac_header_information_elements_write(const mac_pre_build_frame_t *buffer, uint8_t *ptr);
static uint8_t mac_fcf_length(const mac_fcf_sequence_t *header)
{
uint8_t length;
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (header->sequenceNumberSuppress) {
length = 2; //Skip FCF
} else {
length = 3; //Skip FCF + DSN
}
} else {
length = 3; //Skip FCF + DSN
}
return length;
}
bool mac_dst_panid_present(const mac_fcf_sequence_t *header)
{
bool presents = false;
if (header->DstAddrMode && header->SrcAddrMode) {
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (header->DstAddrMode == MAC_ADDR_MODE_64_BIT && header->SrcAddrMode == MAC_ADDR_MODE_64_BIT && header->intraPan) {
} else {
presents = true;
}
} else {
presents = true;
}
} else if (header->DstAddrMode && !header->SrcAddrMode) {
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (!header->intraPan) {
presents = true;
}
} else {
presents = true;
}
} else if (!header->DstAddrMode && !header->SrcAddrMode) {
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (header->intraPan) {
presents = true;
}
}
}
return presents;
}
bool mac_src_panid_present(const mac_fcf_sequence_t *header)
{
bool presents = false;
if (header->DstAddrMode && header->SrcAddrMode) {
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (header->DstAddrMode == MAC_ADDR_MODE_64_BIT && header->SrcAddrMode == MAC_ADDR_MODE_64_BIT) {
} else if (!header->intraPan) {
presents = true;
}
} else if (!header->intraPan) {
presents = true;
}
} else if (header->SrcAddrMode) {
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
if (!header->intraPan) {
presents = true;
}
} else {
presents = true;
}
}
return presents;
}
uint8_t mac_address_length(uint8_t address_mode)
{
uint8_t length = 0;
switch (address_mode) {
case MAC_ADDR_MODE_NONE:
break;
case MAC_ADDR_MODE_16_BIT:
length = 2;
break;
case MAC_ADDR_MODE_64_BIT:
length = 8;
break;
}
return length;
}
static uint8_t mac_dst_address_length_with_panid(const mac_fcf_sequence_t *header)
{
uint8_t length = 0;
if (header->DstPanPresents) {
length += 2;
}
length += mac_address_length(header->DstAddrMode);
return length;
}
static uint8_t mac_src_address_length_with_panid(const mac_fcf_sequence_t *header)
{
uint8_t length = 0;
if (header->SrcPanPresents) {
length += 2;
}
length += mac_address_length(header->SrcAddrMode);
return length;
}
uint8_t mac_security_mic_length_get(uint8_t security_level)
{
uint8_t mic_length;
switch (security_level) {
case 1:
case 5:
mic_length = 4;
break;
case 2:
case 6:
mic_length = 8;
break;
case 3:
case 7:
mic_length = 16;
break;
default:
mic_length = 0;
break;
}
return mic_length;
}
uint8_t mac_header_security_aux_header_length(uint8_t security_level, uint8_t keyIdmode)
{
if (security_level == 0) {
return 0;
}
uint8_t header_length = 5; //Header + 32-bit counter
switch (keyIdmode) {
case MAC_KEY_ID_MODE_SRC8_IDX:
header_length += 4; //64-bit key source first part
/* fall through */
case MAC_KEY_ID_MODE_SRC4_IDX:
header_length += 4; //32-bit key source inline
/* fall through */
case MAC_KEY_ID_MODE_IDX:
header_length += 1;
break;
default:
break;
}
return header_length;
}
uint8_t mac_header_address_length(const mac_fcf_sequence_t *fcf)
{
uint8_t address_length = 0;
address_length += mac_dst_address_length_with_panid(fcf);
address_length += mac_src_address_length_with_panid(fcf);
return address_length;
}
void mac_header_security_parameter_set(mac_aux_security_header_t *header, const mlme_security_t *frame_setup)
{
header->securityLevel = frame_setup->SecurityLevel;
if (header->securityLevel) {
uint8_t keysource_len = 0;
header->KeyIdMode = frame_setup->KeyIdMode;
switch (header->KeyIdMode) {
case MAC_KEY_ID_MODE_IMPLICIT:
//Security header + 32-bit security counter
break;
case MAC_KEY_ID_MODE_SRC8_IDX:
keysource_len += 4; //64-bit key source first part
/* fall through */
case MAC_KEY_ID_MODE_SRC4_IDX:
keysource_len += 4; //32-bit key source inline
/* fall through */
case MAC_KEY_ID_MODE_IDX:
//Security header + 32-bit security counter + Key index
header->KeyIndex = frame_setup->KeyIndex;
break;
}
if (keysource_len) {
memcpy(header->Keysource, frame_setup->Keysource, keysource_len);
}
}
}
const uint8_t *mac_header_parse_fcf_dsn(mac_fcf_sequence_t *header, const uint8_t *ptr)
{
uint16_t fcf = common_read_16_bit_inverse(ptr);
ptr += 2;
//Read Frame Type
header->frametype = ((fcf & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT);
header->securityEnabled = ((fcf & MAC_FCF_SECURITY_BIT_MASK) >> MAC_FCF_SECURITY_BIT_SHIFT);
header->framePending = ((fcf & MAC_FCF_PENDING_BIT_MASK) >> MAC_FCF_PENDING_BIT_SHIFT);
header->ackRequested = ((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT);
header->intraPan = ((fcf & MAC_FCF_INTRA_PANID_MASK) >> MAC_FCF_INTRA_PANID_SHIFT);
header->DstAddrMode = ((fcf & MAC_FCF_DST_ADDR_MASK) >> MAC_FCF_DST_ADDR_SHIFT);
header->frameVersion = ((fcf & MAC_FCF_VERSION_MASK) >> MAC_FCF_VERSION_SHIFT);
header->SrcAddrMode = ((fcf & MAC_FCF_SRC_ADDR_MASK) >> MAC_FCF_SRC_ADDR_SHIFT);
if (header->frameVersion == MAC_FRAME_VERSION_2015) {
header->sequenceNumberSuppress = ((fcf & MAC_FCF_SEQ_NUM_SUPPRESS_MASK) >> MAC_FCF_SEQ_NUM_SUPPRESS_SHIFT);
header->informationElementsPresets = ((fcf & MAC_FCF_IE_PRESENTS_MASK) >> MAC_FCF_IE_PRESENTS_SHIFT);
} else {
//SET False to ALL 2015 Extension's by default
header->sequenceNumberSuppress = false;
header->informationElementsPresets = false;
}
if (header->frameVersion < MAC_FRAME_VERSION_2015 || (header->frameVersion == MAC_FRAME_VERSION_2015 && !header->sequenceNumberSuppress)) {
header->DSN = *ptr++;
} else {
header->DSN = 0;
}
//Check PanID presents at header
header->DstPanPresents = mac_dst_panid_present(header);
header->SrcPanPresents = mac_src_panid_present(header);
return ptr;
}
static uint8_t *mac_header_write_fcf_dsn(const mac_fcf_sequence_t *header, uint8_t *ptr)
{
uint16_t fcf = 0;
//Read Frame Type
fcf |= (header->frametype << MAC_FCF_FRAME_TYPE_SHIFT);
fcf |= (header->securityEnabled << MAC_FCF_SECURITY_BIT_SHIFT);
fcf |= (header->framePending << MAC_FCF_PENDING_BIT_SHIFT);
fcf |= (header->ackRequested << MAC_FCF_ACK_REQ_BIT_SHIFT);
fcf |= (header->intraPan << MAC_FCF_INTRA_PANID_SHIFT);
fcf |= (header->sequenceNumberSuppress << MAC_FCF_SEQ_NUM_SUPPRESS_SHIFT);
fcf |= (header->informationElementsPresets << MAC_FCF_IE_PRESENTS_SHIFT);
fcf |= (header->DstAddrMode << MAC_FCF_DST_ADDR_SHIFT);
fcf |= (header->frameVersion << MAC_FCF_VERSION_SHIFT);
fcf |= (header->SrcAddrMode << MAC_FCF_SRC_ADDR_SHIFT);
ptr = common_write_16_bit_inverse(fcf, ptr);
if (header->frameVersion < MAC_FRAME_VERSION_2015 || (header->frameVersion == MAC_FRAME_VERSION_2015 && !header->sequenceNumberSuppress)) {
*ptr++ = header->DSN;
}
return ptr;
}
uint16_t mac_header_off_set_to_aux_header(const mac_fcf_sequence_t *fcf)
{
//Skip first FCF & address field
uint16_t offset = mac_fcf_length(fcf);//Skip FCF + DSN
offset += mac_dst_address_length_with_panid(fcf);
offset += mac_address_length(fcf->SrcAddrMode);
if (fcf->SrcPanPresents) {
offset += 2; //Skip PanId
}
return offset;
}
void mac_header_security_aux_header_parse(const uint8_t *ptr, mlme_security_t *security_params)
{
uint8_t key_source_len = 0;
security_params->KeyIdMode = (*ptr >> 3);
security_params->SecurityLevel = *ptr++;
ptr += 4; //Skip Frame counter
switch (security_params->KeyIdMode) {
case MAC_KEY_ID_MODE_IMPLICIT:
break;
case MAC_KEY_ID_MODE_SRC8_IDX:
key_source_len += 4;
/* fall through */
case MAC_KEY_ID_MODE_SRC4_IDX:
key_source_len += 4;
memcpy(security_params->Keysource, ptr, key_source_len);
ptr += key_source_len;
/* fall through */
case MAC_KEY_ID_MODE_IDX:
security_params->KeyIndex = *ptr;
break;
}
}
void mac_header_security_components_read(mac_pre_parsed_frame_t *buffer, mlme_security_t *security_params)
{
memset(security_params, 0, sizeof(mlme_security_t));
if (!buffer->fcf_dsn.securityEnabled) {
return;
}
mac_header_security_aux_header_parse(mcps_mac_security_aux_header_start_pointer_get(buffer), security_params);
}
static bool mac_header_pan_full_compressed(const mac_fcf_sequence_t *header)
{
if (header->frameVersion == MAC_FRAME_VERSION_2015 && (!header->DstPanPresents && !header->SrcPanPresents) && header->intraPan) {
return true;
}
return false;
}
static uint16_t mac_header_read_src_pan(const mac_fcf_sequence_t *header, const uint8_t *ptr)
{
ptr += mac_fcf_length(header);//Skip FCF + DSN
ptr += mac_dst_address_length_with_panid(header); //Skip Dst panID & Address
return common_read_16_bit_inverse(ptr);
}
static uint16_t mac_header_read_dst_pan(const mac_fcf_sequence_t *header, const uint8_t *ptr)
{
ptr += mac_fcf_length(header);//Skip FCF + DSN
return common_read_16_bit_inverse(ptr);
}
uint16_t mac_header_get_src_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint16_t configured_pan_id)
{
if (mac_header_pan_full_compressed(header)) {
return configured_pan_id;
}
if (!header->SrcPanPresents) {
if (!header->DstPanPresents) {
return 0xffff;
}
return mac_header_read_dst_pan(header, ptr);
}
return mac_header_read_src_pan(header, ptr);
}
uint16_t mac_header_get_dst_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint16_t configured_pan_id)
{
if (mac_header_pan_full_compressed(header)) {
return configured_pan_id;
}
if (!header->DstPanPresents) {
if (header->SrcPanPresents && header->frameVersion == MAC_FRAME_VERSION_2015 && header->DstAddrMode == MAC_ADDR_MODE_NONE) {
return mac_header_read_src_pan(header, ptr);
}
return 0xffff;
}
return mac_header_read_dst_pan(header, ptr);
}
void mac_header_get_src_address(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint8_t *address_ptr)
{
if (header->SrcAddrMode == MAC_ADDR_MODE_NONE) {
return;
}
ptr += mac_fcf_length(header);//Skip FCF + DSN
ptr += mac_dst_address_length_with_panid(header);
uint8_t address_len, address_index, i;
address_len = mac_address_length(header->SrcAddrMode);
if (header->SrcPanPresents) {
ptr += 2; //Skip PanId
}
address_index = address_len - 1;
for (i = 0; i < address_len; i++) {
address_ptr[address_index - i] = *ptr++;
}
}
void mac_header_get_dst_address(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint8_t *address_ptr)
{
if (header->DstAddrMode == MAC_ADDR_MODE_NONE) {
return;
}
uint8_t address_len, address_index, i;
ptr += mac_fcf_length(header);//Skip FCF + DSN
address_len = mac_address_length(header->DstAddrMode);
if (header->DstPanPresents) {
ptr += 2; //Skip PanId
}
address_index = address_len - 1;
for (i = 0; i < address_len; i++) {
address_ptr[address_index - i] = *ptr++;
}
}
static uint16_t mac_payload_length_calc_with_ie(uint16_t payload_length, uint16_t payload_ie_length)
{
uint16_t length = payload_length;
if (payload_ie_length) {
if (length) {
length += 2;
}
length += payload_ie_length;
}
return length;
}
uint8_t mcps_mac_header_length_from_received_frame(const mac_pre_parsed_frame_t *buffer)
{
return (buffer->mac_header_length + buffer->security_aux_header_length + buffer->header_ie_length);
}
uint8_t *mcps_mac_payload_pointer_get(const mac_pre_parsed_frame_t *buffer)
{
uint8_t *ptr = (uint8_t *) mac_header_message_start_pointer(buffer);
ptr += mcps_mac_header_length_from_received_frame(buffer);
return ptr;
}
uint8_t *mcps_security_mic_pointer_get(const mac_pre_parsed_frame_t *buffer)
{
uint8_t *ptr = mcps_mac_payload_pointer_get(buffer) + buffer->mac_payload_length;
return ptr;
}
static uint8_t *mcps_mac_security_aux_header_start_pointer_get(const mac_pre_parsed_frame_t *buffer)
{
if (!buffer->fcf_dsn.securityEnabled) {
return NULL;
}
return (uint8_t *)(mac_header_message_start_pointer(buffer) + buffer->mac_header_length);
}
uint8_t mcps_mac_command_frame_id_get(const mac_pre_parsed_frame_t *buffer)
{
const uint8_t *ptr = mcps_mac_payload_pointer_get(buffer);
return *ptr;
}
uint32_t mcps_mac_security_frame_counter_read(const mac_pre_parsed_frame_t *buffer)
{
if (!buffer->fcf_dsn.securityEnabled) {
return 0xffffffff;
}
const uint8_t *ptr = (mac_header_message_start_pointer(buffer) + buffer->mac_header_length + 1);
return common_read_32_bit_inverse(ptr);
}
static uint8_t *mcps_mac_frame_address_write(uint8_t *ptr, uint8_t addressType, const uint8_t *addressPtr)
{
if (addressType == MAC_ADDR_MODE_16_BIT) {
uint16_t tempMac16 = common_read_16_bit(addressPtr);
ptr = common_write_16_bit_inverse(tempMac16, ptr);
} else if (addressType == MAC_ADDR_MODE_64_BIT) {
uint8_t i;
for (i = 0; i < 8; i++) {
*ptr++ = addressPtr[7 - i];
}
}
return ptr;
}
static uint8_t *mac_security_interface_aux_security_header_write(uint8_t *ptr, const mac_aux_security_header_t *auxHeader)
{
uint8_t auxBaseHeader;
auxBaseHeader = auxHeader->securityLevel;
auxBaseHeader |= (auxHeader->KeyIdMode << 3);
*ptr++ = auxBaseHeader;
ptr = common_write_32_bit_inverse(auxHeader->frameCounter, ptr);
switch (auxHeader->KeyIdMode) {
case MAC_KEY_ID_MODE_SRC8_IDX:
memcpy(ptr, auxHeader->Keysource, 8);
ptr += 8;
*ptr++ = auxHeader->KeyIndex;
break;
case MAC_KEY_ID_MODE_SRC4_IDX:
memcpy(ptr, auxHeader->Keysource, 4);
ptr += 4;
*ptr++ = auxHeader->KeyIndex;
break;
case MAC_KEY_ID_MODE_IDX:
*ptr++ = auxHeader->KeyIndex;
break;
default:
break;
}
return ptr;
}
uint8_t *mac_generic_packet_write(struct protocol_interface_rf_mac_setup *rf_ptr, uint8_t *ptr, const mac_pre_build_frame_t *buffer)
{
ptr = mac_header_write_fcf_dsn(&buffer->fcf_dsn, ptr);
if (buffer->fcf_dsn.DstPanPresents) {
ptr = common_write_16_bit_inverse(buffer->DstPANId, ptr);
}
if (buffer->fcf_dsn.DstAddrMode) {
//Write DST
ptr = mcps_mac_frame_address_write(ptr, buffer->fcf_dsn.DstAddrMode, buffer->DstAddr);
}
if (buffer->fcf_dsn.SrcPanPresents) {
ptr = common_write_16_bit_inverse(buffer->SrcPANId, ptr);
}
if (buffer->fcf_dsn.SrcAddrMode) {
ptr = mcps_mac_frame_address_write(ptr, buffer->fcf_dsn.SrcAddrMode, buffer->SrcAddr);
}
if (buffer->fcf_dsn.securityEnabled) {
ptr = mac_security_interface_aux_security_header_write(ptr, &buffer->aux_header);
}
uint8_t *ie_start = ptr;
//Copy Payload and set IE Elemets
ptr = mac_header_information_elements_write(buffer, ptr);
if (buffer->mac_payload_length) {
memcpy(ptr, buffer->mac_payload, buffer->mac_payload_length);
ptr += buffer->mac_payload_length;
}
if (rf_ptr->fhss_api) {
if (buffer->fcf_dsn.frametype == FC_BEACON_FRAME) {
dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer;
uint8_t *synch_info = tx_buf->buf + rf_ptr->dev_driver->phy_driver->phy_header_length + tx_buf->len - FHSS_SYNCH_INFO_LENGTH;
rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, synch_info, FHSS_SYNCH_INFO_LENGTH, FHSS_SYNCH_FRAME, buffer->tx_time);
} else {
rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, ie_start, buffer->headerIeLength, FHSS_DATA_FRAME, buffer->tx_time);
}
}
return ptr;
}
static uint8_t *mac_write_ie_vector_list(ns_ie_iovec_t *list, uint16_t length, uint8_t *ptr)
{
const ns_ie_iovec_t *msg_iov = list;
for (uint_fast16_t i = 0; i < length; i++, msg_iov++) {
memcpy(ptr, msg_iov->ieBase, msg_iov->iovLen);
ptr += msg_iov->iovLen;
}
return ptr;
}
static bool mac_parse_header_ie(mac_header_IE_t *header_element, uint8_t *ptr)
{
uint16_t ie_dummy = common_read_16_bit_inverse(ptr);
if (ie_dummy & 0x8000) {
return false;
}
header_element->length = (ie_dummy & 0x007f);
header_element->id = ((ie_dummy & 0x7f80) >> 7);
header_element->content_ptr = ptr + 2;
return true;
}
static bool mac_parse_payload_ie(mac_payload_IE_t *payload_element, uint8_t *ptr)
{
uint16_t ie_dummy = common_read_16_bit_inverse(ptr);
if (!(ie_dummy & 0x8000)) {
return false;
}
payload_element->length = (ie_dummy & 0x07ff);
payload_element->id = ((ie_dummy & 0x7800) >> 11);
payload_element->content_ptr = ptr + 2;
return true;
}
bool mac_header_information_elements_parse(mac_pre_parsed_frame_t *buffer)
{
uint8_t *ptr = (mac_header_message_start_pointer(buffer) + buffer->mac_header_length + buffer->security_aux_header_length);
buffer->headerIePtr = NULL;
buffer->headerIeLength = 0;
buffer->payloadsIePtr = NULL;
buffer->payloadsIeLength = 0;
buffer->header_ie_length = 0;
if (!buffer->fcf_dsn.informationElementsPresets) {
buffer->macPayloadPtr = ptr;
return true;
}
if (buffer->mac_payload_length < 2) {
return false;
}
mac_header_IE_t header_ie;
buffer->headerIePtr = ptr;
while (buffer->mac_payload_length >= 2) {
if (!mac_parse_header_ie(&header_ie, ptr)) {
return false;
}
buffer->mac_payload_length -= 2;
if (header_ie.length > buffer->mac_payload_length) {
return false;
}
buffer->mac_payload_length -= header_ie.length;
buffer->header_ie_length += header_ie.length + 2;
ptr += (2 + header_ie.length);
if (header_ie.id == MAC_HEADER_TERMINATION1_IE_ID) {
break;
} else if (header_ie.id == MAC_HEADER_TERMINATION2_IE_ID) {
buffer->macPayloadPtr = ptr;
return true;
}
buffer->headerIeLength += header_ie.length + 2;
}
return true;
}
bool mac_payload_information_elements_parse(mac_pre_parsed_frame_t *buffer)
{
uint8_t *ptr = (mac_header_message_start_pointer(buffer) + buffer->mac_header_length + buffer->security_aux_header_length + buffer->header_ie_length);
if (!buffer->fcf_dsn.informationElementsPresets) {
return true;
}
if (buffer->mac_payload_length < 2) {
return false;
}
//Parse Payload IE
buffer->payloadsIePtr = ptr;
mac_payload_IE_t payload_ie;
while (buffer->mac_payload_length >= 2) {
if (!mac_parse_payload_ie(&payload_ie, ptr)) {
return false;
}
buffer->mac_payload_length -= 2;
if (payload_ie.length > buffer->mac_payload_length) {
return false;
}
buffer->mac_payload_length -= payload_ie.length;
if (payload_ie.id == MAC_PAYLOAD_TERMINATION_IE_GROUP_ID) {
break;
}
buffer->payloadsIeLength += payload_ie.length + 2;
buffer->macPayloadPtr += payload_ie.length + 2;
ptr += (2 + payload_ie.length);
}
buffer->macPayloadPtr = ptr;
return true;
}
static uint8_t *mac_header_ie_terimate(uint8_t *ptr, uint8_t type)
{
uint16_t ie_dummy = 0;
ie_dummy |= (type << 7);
return common_write_16_bit_inverse(ie_dummy, ptr);
}
static uint8_t *mac_payload_ie_terimate(uint8_t *ptr)
{
uint16_t ie_dummy = 0;
ie_dummy |= (MAC_PAYLOAD_TERMINATION_IE_GROUP_ID << 11);
ie_dummy |= (1 << 15);
return common_write_16_bit_inverse(ie_dummy, ptr);
}
void mac_header_information_elements_preparation(mac_pre_build_frame_t *buffer)
{
if (buffer->message_builded) {
return;
}
if (buffer->headerIeLength || buffer->payloadsIeLength) {
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2015;
buffer->fcf_dsn.informationElementsPresets = true;
buffer->message_builded = true;
//Write Header elements
if (buffer->headerIeLength) {
buffer->mac_header_length_with_security += buffer->headerIeLength;
if (!buffer->payloadsIeLength && !buffer->mac_payload_length) {
//No termination needed
return;
}
//Terminate
buffer->mac_header_length_with_security += 2;
} else {
buffer->mac_header_length_with_security += 2;
}
}
}
uint16_t mac_buffer_total_payload_length(mac_pre_build_frame_t *buffer)
{
return mac_payload_length_calc_with_ie(buffer->mac_payload_length, buffer->payloadsIeLength);
}
static uint8_t *mac_header_information_elements_write(const mac_pre_build_frame_t *buffer, uint8_t *ptr)
{
if (buffer->fcf_dsn.frameVersion == MAC_FRAME_VERSION_2015 && buffer->fcf_dsn.informationElementsPresets) {
//Write Header elements
if (buffer->headerIeLength) {
ptr = mac_write_ie_vector_list(buffer->ie_elements.headerIeVectorList, buffer->ie_elements.headerIovLength, ptr);
if (!buffer->payloadsIeLength && !buffer->mac_payload_length) {
//No termination needed
return ptr;
} else if (!buffer->payloadsIeLength && buffer->mac_payload_length) {
return mac_header_ie_terimate(ptr, MAC_HEADER_TERMINATION2_IE_ID);
}
}
//Add Header Termination
ptr = mac_header_ie_terimate(ptr, MAC_HEADER_TERMINATION1_IE_ID);
if (buffer->payloadsIeLength) {
ptr = mac_write_ie_vector_list(buffer->ie_elements.payloadIeVectorList, buffer->ie_elements.payloadIovLength, ptr);
if (buffer->mac_payload_length) {
ptr = mac_payload_ie_terimate(ptr);
}
}
}
return ptr;
}