mirror of https://github.com/ARMmbed/mbed-os.git
2713 lines
101 KiB
C
2713 lines
101 KiB
C
/*
|
|
* Copyright (c) 2014-2019, 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.
|
|
*/
|
|
|
|
/*
|
|
* \file mac_mcps_sap.c
|
|
* \brief Add short description about this file!!!
|
|
*
|
|
*/
|
|
#include "nsconfig.h"
|
|
#include "ns_types.h"
|
|
#include "eventOS_event.h"
|
|
#include "eventOS_scheduler.h"
|
|
#include "eventOS_callback_timer.h"
|
|
#include "string.h"
|
|
#include "ns_trace.h"
|
|
#include "nsdynmemLIB.h"
|
|
#include "ccmLIB.h"
|
|
#include "mlme.h"
|
|
#include "mac_api.h"
|
|
#include "fhss_api.h"
|
|
#include "platform/arm_hal_interrupt.h"
|
|
#include "common_functions.h"
|
|
#include "Core/include/ns_monitor.h"
|
|
|
|
#include "MAC/IEEE802_15_4/sw_mac_internal.h"
|
|
#include "MAC/IEEE802_15_4/mac_defines.h"
|
|
#include "MAC/IEEE802_15_4/mac_timer.h"
|
|
#include "MAC/IEEE802_15_4/mac_security_mib.h"
|
|
#include "MAC/IEEE802_15_4/mac_mlme.h"
|
|
#include "MAC/IEEE802_15_4/mac_filter.h"
|
|
#include "MAC/IEEE802_15_4/mac_pd_sap.h"
|
|
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
|
|
#include "MAC/IEEE802_15_4/mac_header_helper_functions.h"
|
|
#include "MAC/IEEE802_15_4/mac_indirect_data.h"
|
|
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
|
|
#include "MAC/rf_driver_storage.h"
|
|
|
|
#include "sw_mac.h"
|
|
|
|
#define TRACE_GROUP "mMCp"
|
|
|
|
// Used to set TX time (us) with FHSS. Must be <= 65ms.
|
|
#define MAC_TX_PROCESSING_DELAY_INITIAL 2000
|
|
|
|
typedef struct {
|
|
uint8_t address[8];
|
|
unsigned addr_type: 2;
|
|
uint8_t nonce_ptr[8];
|
|
uint32_t frameCounter;
|
|
uint8_t keyId;
|
|
} neighbour_security_update_t;
|
|
|
|
void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer);
|
|
static mac_pre_build_frame_t *mcps_sap_pd_req_queue_read(protocol_interface_rf_mac_setup_s *rf_mac_setup, bool is_bc_queue, bool flush);
|
|
static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer);
|
|
static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mac_pre_parsed_frame_t *ack_buf);
|
|
static void mac_set_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type);
|
|
static void mac_clear_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type);
|
|
static bool mac_read_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type);
|
|
static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer);
|
|
static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup);
|
|
|
|
static int8_t mac_tasklet_event_handler = -1;
|
|
|
|
/**
|
|
* Get PHY time stamp.
|
|
*
|
|
* \param rf_mac_setup pointer to MAC
|
|
* \return Timestamp from PHY
|
|
*
|
|
*/
|
|
uint32_t mac_mcps_sap_get_phy_timestamp(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
uint32_t timestamp;
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_TIMESTAMP, (uint8_t *)×tamp);
|
|
return timestamp;
|
|
}
|
|
|
|
static bool mac_data_counter_too_small(uint32_t current_counter, uint32_t packet_counter)
|
|
{
|
|
if ((current_counter - packet_counter) >= 2) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool mac_data_request_confirmation_finnish(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (!buffer->asynch_request) {
|
|
return true;
|
|
}
|
|
|
|
if (mlme_scan_analyze_next_channel(&buffer->asynch_channel_list, false) > 0x00ff) {
|
|
mac_mlme_rf_channel_change(rf_mac_setup, buffer->asynch_channel);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
static void mac_data_poll_radio_disable_check(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (rf_mac_setup->macCapRxOnIdle || rf_mac_setup->macWaitingData || rf_mac_setup->scan_active) {
|
|
return;
|
|
}
|
|
|
|
if (!rf_mac_setup->macRfRadioTxActive) {
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
}
|
|
}
|
|
|
|
static void mcps_data_confirm_cb(protocol_interface_rf_mac_setup_s *rf_mac_setup, mcps_data_conf_t *confirm, mac_pre_parsed_frame_t *ack_buf)
|
|
{
|
|
mac_data_poll_radio_disable_check(rf_mac_setup);
|
|
|
|
if (get_sw_mac_api(rf_mac_setup)) {
|
|
if (rf_mac_setup->mac_extension_enabled) {
|
|
mcps_data_conf_payload_t data_conf;
|
|
memset(&data_conf, 0, sizeof(mcps_data_conf_payload_t));
|
|
if (ack_buf) {
|
|
data_conf.payloadIeList = ack_buf->payloadsIePtr;
|
|
data_conf.payloadIeListLength = ack_buf->payloadsIeLength;
|
|
data_conf.headerIeList = ack_buf->headerIePtr;
|
|
data_conf.headerIeListLength = ack_buf->headerIeLength;
|
|
data_conf.payloadLength = ack_buf->mac_payload_length;
|
|
data_conf.payloadPtr = ack_buf->macPayloadPtr;
|
|
}
|
|
//Check Payload Here
|
|
get_sw_mac_api(rf_mac_setup)->data_conf_ext_cb(get_sw_mac_api(rf_mac_setup), confirm, &data_conf);
|
|
} else {
|
|
get_sw_mac_api(rf_mac_setup)->data_conf_cb(get_sw_mac_api(rf_mac_setup), confirm);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mcps_sap_data_req_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req)
|
|
{
|
|
mcps_data_req_ie_list_t ie_list;
|
|
memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t));
|
|
mcps_sap_data_req_handler_ext(rf_mac_setup, data_req, &ie_list, NULL);
|
|
}
|
|
|
|
static bool mac_ie_vector_length_validate(ns_ie_iovec_t *ie_vector, uint16_t iov_length, uint16_t *length_out)
|
|
{
|
|
if (length_out) {
|
|
*length_out = 0;
|
|
}
|
|
|
|
if (!iov_length) {
|
|
return true;
|
|
}
|
|
|
|
if (iov_length != 0 && !ie_vector) {
|
|
return false;
|
|
}
|
|
|
|
uint16_t msg_length = 0;
|
|
ns_ie_iovec_t *msg_iov = ie_vector;
|
|
for (uint_fast16_t i = 0; i < iov_length; i++) {
|
|
if (msg_iov->iovLen != 0 && !msg_iov->ieBase) {
|
|
return false;
|
|
}
|
|
msg_length += msg_iov->iovLen;
|
|
if (msg_length < msg_iov->iovLen) {
|
|
return false;
|
|
}
|
|
msg_iov++;
|
|
}
|
|
|
|
if (length_out) {
|
|
*length_out = msg_length;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req, const mcps_data_req_ie_list_t *ie_list, const channel_list_s *asynch_channel_list)
|
|
{
|
|
uint8_t status = MLME_SUCCESS;
|
|
mac_pre_build_frame_t *buffer = NULL;
|
|
|
|
if (rf_mac_setup->mac_edfe_enabled && data_req->ExtendedFrameExchange) {
|
|
if (rf_mac_setup->mac_edfe_info->state != MAC_EDFE_FRAME_IDLE) {
|
|
tr_debug("Accept only 1 active Efde Data request push");
|
|
status = MLME_UNSUPPORTED_LEGACY;
|
|
goto verify_status;
|
|
}
|
|
|
|
if (data_req->DstAddrMode != MAC_ADDR_MODE_64_BIT) {
|
|
status = MLME_INVALID_PARAMETER;
|
|
goto verify_status;
|
|
}
|
|
}
|
|
|
|
if (!rf_mac_setup->mac_security_enabled) {
|
|
if (data_req->Key.SecurityLevel) {
|
|
status = MLME_UNSUPPORTED_SECURITY;
|
|
goto verify_status;
|
|
}
|
|
}
|
|
|
|
uint16_t ie_header_length = 0;
|
|
uint16_t ie_payload_length = 0;
|
|
|
|
if (!mac_ie_vector_length_validate(ie_list->headerIeVectorList, ie_list->headerIovLength, &ie_header_length)) {
|
|
status = MLME_INVALID_PARAMETER;
|
|
goto verify_status;
|
|
}
|
|
|
|
if (!mac_ie_vector_length_validate(ie_list->payloadIeVectorList, ie_list->payloadIovLength, &ie_payload_length)) {
|
|
status = MLME_INVALID_PARAMETER;
|
|
goto verify_status;
|
|
}
|
|
|
|
if ((ie_header_length || ie_payload_length || asynch_channel_list) && !rf_mac_setup->mac_extension_enabled) {
|
|
//Report error when feature is not enaled yet
|
|
status = MLME_INVALID_PARAMETER;
|
|
goto verify_status;
|
|
} else if (asynch_channel_list && data_req->TxAckReq) {
|
|
//Report Asynch Message is not allowed to call with ACK requested.
|
|
status = MLME_INVALID_PARAMETER;
|
|
goto verify_status;
|
|
}
|
|
|
|
if ((data_req->msduLength + ie_header_length + ie_payload_length) > rf_mac_setup->phy_mtu_size - MAC_DATA_PACKET_MIN_HEADER_LENGTH) {
|
|
tr_debug("packet %u, %u", data_req->msduLength, rf_mac_setup->phy_mtu_size);
|
|
status = MLME_FRAME_TOO_LONG;
|
|
goto verify_status;
|
|
}
|
|
buffer = mcps_sap_prebuild_frame_buffer_get(0);
|
|
//tr_debug("Data Req");
|
|
if (!buffer) {
|
|
//Make Confirm Here
|
|
status = MLME_TRANSACTION_OVERFLOW;
|
|
goto verify_status;
|
|
}
|
|
|
|
if (!rf_mac_setup->macUpState || rf_mac_setup->scan_active) {
|
|
status = MLME_TRX_OFF;
|
|
goto verify_status;
|
|
}
|
|
|
|
if (asynch_channel_list) {
|
|
//Copy Asynch data list
|
|
buffer->asynch_channel_list = *asynch_channel_list;
|
|
buffer->asynch_request = true;
|
|
}
|
|
|
|
buffer->upper_layer_request = true;
|
|
buffer->fcf_dsn.frametype = FC_DATA_FRAME;
|
|
buffer->ExtendedFrameExchange = data_req->ExtendedFrameExchange;
|
|
buffer->WaitResponse = data_req->TxAckReq;
|
|
if (data_req->ExtendedFrameExchange) {
|
|
buffer->fcf_dsn.ackRequested = false;
|
|
} else {
|
|
buffer->fcf_dsn.ackRequested = data_req->TxAckReq;
|
|
}
|
|
|
|
buffer->mac_header_length_with_security = 3;
|
|
mac_header_security_parameter_set(&buffer->aux_header, &data_req->Key);
|
|
buffer->security_mic_len = mac_security_mic_length_get(buffer->aux_header.securityLevel);
|
|
if (buffer->aux_header.securityLevel) {
|
|
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
buffer->fcf_dsn.securityEnabled = true;
|
|
}
|
|
|
|
buffer->mac_header_length_with_security += mac_header_security_aux_header_length(buffer->aux_header.securityLevel, buffer->aux_header.KeyIdMode);
|
|
|
|
buffer->msduHandle = data_req->msduHandle;
|
|
buffer->fcf_dsn.DstAddrMode = data_req->DstAddrMode;
|
|
memcpy(buffer->DstAddr, data_req->DstAddr, 8);
|
|
buffer->DstPANId = data_req->DstPANId;
|
|
buffer->SrcPANId = mac_mlme_get_panid(rf_mac_setup);
|
|
buffer->fcf_dsn.SrcAddrMode = data_req->SrcAddrMode;
|
|
buffer->fcf_dsn.framePending = data_req->PendingBit;
|
|
|
|
if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE && !rf_mac_setup->mac_extension_enabled) {
|
|
if (buffer->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE) {
|
|
status = MLME_INVALID_ADDRESS;
|
|
goto verify_status;
|
|
}
|
|
|
|
if (rf_mac_setup->shortAdressValid) {
|
|
buffer->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_16_BIT;
|
|
} else {
|
|
buffer->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_64_BIT;
|
|
}
|
|
}
|
|
|
|
mac_frame_src_address_set_from_interface(buffer->fcf_dsn.SrcAddrMode, rf_mac_setup, buffer->SrcAddr);
|
|
|
|
buffer->ie_elements.headerIeVectorList = ie_list->headerIeVectorList;
|
|
buffer->ie_elements.headerIovLength = ie_list->headerIovLength;
|
|
buffer->ie_elements.payloadIeVectorList = ie_list->payloadIeVectorList;
|
|
buffer->ie_elements.payloadIovLength = ie_list->payloadIovLength;
|
|
buffer->headerIeLength = ie_header_length;
|
|
buffer->payloadsIeLength = ie_payload_length;
|
|
|
|
|
|
if (rf_mac_setup->mac_extension_enabled) {
|
|
//Handle mac extension's
|
|
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2015;
|
|
if (ie_header_length || ie_payload_length) {
|
|
buffer->fcf_dsn.informationElementsPresets = true;
|
|
}
|
|
|
|
buffer->fcf_dsn.sequenceNumberSuppress = data_req->SeqNumSuppressed;
|
|
if (buffer->fcf_dsn.sequenceNumberSuppress) {
|
|
buffer->mac_header_length_with_security--;
|
|
}
|
|
/* PAN-ID compression bit enable when necessary */
|
|
if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE && buffer->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE) {
|
|
buffer->fcf_dsn.intraPan = !data_req->PanIdSuppressed;
|
|
} else if (buffer->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE) {
|
|
buffer->fcf_dsn.intraPan = data_req->PanIdSuppressed;
|
|
} else if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE || (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT && buffer->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT)) {
|
|
buffer->fcf_dsn.intraPan = data_req->PanIdSuppressed;
|
|
} else { /* two addresses, at least one address short */
|
|
// ignore or fault panidsuppressed
|
|
if (buffer->DstPANId == buffer->SrcPANId) {
|
|
buffer->fcf_dsn.intraPan = true;
|
|
}
|
|
}
|
|
} else {
|
|
/* PAN-ID compression bit enable when necessary */
|
|
if ((buffer->fcf_dsn.DstAddrMode && buffer->fcf_dsn.SrcAddrMode) && (buffer->DstPANId == buffer->SrcPANId)) {
|
|
buffer->fcf_dsn.intraPan = true;
|
|
}
|
|
}
|
|
|
|
//Check PanID presents at header
|
|
buffer->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buffer->fcf_dsn);
|
|
buffer->fcf_dsn.SrcPanPresents = mac_src_panid_present(&buffer->fcf_dsn);
|
|
//Calculate address length
|
|
buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn);
|
|
buffer->mac_payload = data_req->msdu;
|
|
buffer->mac_payload_length = data_req->msduLength;
|
|
//check that header + payload length is not bigger than MAC MTU
|
|
|
|
if (data_req->InDirectTx) {
|
|
mac_indirect_queue_write(rf_mac_setup, buffer);
|
|
} else {
|
|
mcps_sap_pd_req_queue_write(rf_mac_setup, buffer);
|
|
}
|
|
|
|
verify_status:
|
|
if (status != MLME_SUCCESS) {
|
|
tr_debug("DATA REQ Fail %u", status);
|
|
rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = data_req->msduHandle;
|
|
rf_mac_setup->mac_mcps_data_conf_fail.status = status;
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
if (mcps_sap_pd_confirm_failure(rf_mac_setup) != 0) {
|
|
// event sending failed, calling handler directly
|
|
mac_pd_data_confirm_failure_handle(rf_mac_setup);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int8_t mac_virtual_data_req_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *data_ptr, uint16_t data_length)
|
|
{
|
|
|
|
if (!rf_mac_setup->macUpState || data_length > rf_mac_setup->phy_mtu_size) {
|
|
return -1;
|
|
}
|
|
|
|
//protocol_interface_rf_mac_setup_s *rf_mac_setup = (protocol_interface_rf_mac_setup_s*)api;
|
|
mac_pre_build_frame_t *buffer = mcps_sap_prebuild_frame_buffer_get(data_length);
|
|
//tr_debug("Data Req");
|
|
if (!buffer) {
|
|
//Make Confirm Here
|
|
return -1;
|
|
}
|
|
|
|
mac_header_parse_fcf_dsn(&buffer->fcf_dsn, data_ptr);
|
|
// Use MAC sequence as handle
|
|
buffer->msduHandle = buffer->fcf_dsn.DSN;
|
|
memcpy(buffer->mac_payload, data_ptr, data_length);
|
|
buffer->mac_payload_length = data_length;
|
|
|
|
// Read destination MAC address from MAC header
|
|
mac_header_get_dst_address(&buffer->fcf_dsn, data_ptr, buffer->DstAddr);
|
|
|
|
mcps_sap_pd_req_queue_write(rf_mac_setup, buffer);
|
|
|
|
if (!buffer->fcf_dsn.ackRequested) {
|
|
phy_device_driver_s *driver = rf_mac_setup->tun_extension_rf_driver->phy_driver;
|
|
driver->phy_tx_done_cb(rf_mac_setup->tun_extension_rf_driver->id, 1, PHY_LINK_TX_SUCCESS, 1, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_virtual_mlme_nap_req_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const arm_mlme_req_t *mlme_req)
|
|
{
|
|
const uint8_t *ptr = mlme_req->mlme_ptr;
|
|
switch (mlme_req->primitive) {
|
|
case MLME_SCAN: {
|
|
if (mlme_req->ptr_length != 47) {
|
|
return -1;
|
|
}
|
|
|
|
mlme_scan_t mlme_scan_req;
|
|
mlme_scan_req.ScanType = (mac_scan_type_t) * ptr++;
|
|
mlme_scan_req.ScanChannels.channel_page = (channel_page_e) * ptr++;
|
|
memcpy(mlme_scan_req.ScanChannels.channel_mask, ptr, 32);
|
|
ptr += 32;
|
|
mlme_scan_req.ScanDuration = *ptr++;
|
|
mlme_scan_req.ChannelPage = *ptr++;
|
|
mlme_scan_req.Key.SecurityLevel = *ptr++;
|
|
mlme_scan_req.Key.KeyIdMode = *ptr++;
|
|
mlme_scan_req.Key.KeyIndex = *ptr++;
|
|
memcpy(mlme_scan_req.Key.Keysource, ptr, 8);
|
|
mac_mlme_scan_request(&mlme_scan_req, rf_mac_setup);
|
|
return 0;
|
|
}
|
|
case MLME_SET: {
|
|
if (mlme_req->ptr_length < 3) {
|
|
return -1;
|
|
}
|
|
mlme_set_t mlme_set_req;
|
|
mlme_set_req.attr = (mlme_attr_t) * ptr++;
|
|
mlme_set_req.attr_index = *ptr++;
|
|
mlme_set_req.value_pointer = ptr;
|
|
mlme_set_req.value_size = mlme_req->ptr_length - 2;
|
|
|
|
return mac_mlme_set_req(rf_mac_setup, &mlme_set_req);
|
|
}
|
|
case MLME_START: {
|
|
mlme_start_t mlme_start_req;
|
|
if (mlme_req->ptr_length != 34) {
|
|
return -1;
|
|
}
|
|
mlme_start_req.PANId = common_read_16_bit(ptr);
|
|
ptr += 2;
|
|
mlme_start_req.LogicalChannel = *ptr++;
|
|
mlme_start_req.StartTime = common_read_32_bit(ptr);
|
|
ptr += 4;
|
|
mlme_start_req.BeaconOrder = *ptr++;
|
|
mlme_start_req.SuperframeOrder = *ptr++;
|
|
mlme_start_req.PANCoordinator = *ptr++;
|
|
mlme_start_req.BatteryLifeExtension = *ptr++;
|
|
mlme_start_req.CoordRealignment = *ptr++;
|
|
mlme_start_req.CoordRealignKey.SecurityLevel = *ptr++;
|
|
mlme_start_req.CoordRealignKey.KeyIdMode = *ptr++;
|
|
mlme_start_req.CoordRealignKey.KeyIndex = *ptr++;
|
|
memcpy(mlme_start_req.CoordRealignKey.Keysource, ptr, 8);
|
|
ptr += 8;
|
|
mlme_start_req.BeaconRealignKey.SecurityLevel = *ptr++;
|
|
mlme_start_req.BeaconRealignKey.KeyIdMode = *ptr++;
|
|
mlme_start_req.BeaconRealignKey.KeyIndex = *ptr++;
|
|
memcpy(mlme_start_req.BeaconRealignKey.Keysource, ptr, 8);
|
|
ptr += 8;
|
|
return mac_mlme_start_req(&mlme_start_req, rf_mac_setup);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int8_t mac_virtual_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
|
|
{
|
|
if (!identifier || !message) {
|
|
return -1;
|
|
}
|
|
|
|
if (message->id == MACTUN_PD_SAP_NAP_IND) {
|
|
return mac_virtual_data_req_handler(identifier, message->message.generic_data_ind.data_ptr, message->message.generic_data_ind.data_len);
|
|
}
|
|
|
|
if (message->id == MACTUN_MLME_NAP_EXTENSION) {
|
|
return mac_virtual_mlme_nap_req_handler(identifier, &message->message.mlme_request);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
//static void mac_data_interface_minium_security_level_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_security_level_descriptor_t *security_level_compare) {
|
|
// //TODO get securily level table and verify current packet
|
|
// (void)rf_mac_setup;
|
|
// //Accept all true from mac
|
|
// security_level_compare->SecurityMinimum = 0;
|
|
//}
|
|
|
|
static void mac_security_interface_aux_ccm_nonce_set(uint8_t *noncePtr, uint8_t *mac64, uint32_t securityFrameCounter, uint8_t securityLevel)
|
|
{
|
|
memcpy(noncePtr, mac64, 8);
|
|
noncePtr += 8;
|
|
noncePtr = common_write_32_bit(securityFrameCounter, noncePtr);
|
|
*noncePtr = securityLevel;
|
|
}
|
|
|
|
/* Compare two security levels, as per 802.15.4-2011 7.4.1.1 */
|
|
/* Returns true if sec1 is at least as secure as sec2 */
|
|
//static bool mac_security_interface_security_level_compare(uint8_t sec1, uint8_t sec2)
|
|
//{
|
|
// /* bit 2 is "encrypted" - must be as encrypted
|
|
// bits 1-0 are "authentication level" - must be at least as high */
|
|
// return (sec1 & 4) >= (sec2 & 4) &&
|
|
// (sec1 & 3) >= (sec2 & 3);
|
|
//}
|
|
|
|
|
|
static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme_security_t *security_params)
|
|
{
|
|
uint8_t *key;
|
|
mlme_key_descriptor_t *key_description;
|
|
mlme_key_device_descriptor_t *key_device_description = NULL;
|
|
uint8_t device_descriptor_handle;
|
|
uint8_t openPayloadLength = 0;
|
|
bool security_by_pass = false;
|
|
protocol_interface_rf_mac_setup_s *rf_mac_setup = (protocol_interface_rf_mac_setup_s *)b->mac_class_ptr;
|
|
// mlme_security_level_descriptor_t security_level_compare;
|
|
|
|
|
|
if (!rf_mac_setup->mac_security_enabled) {
|
|
if (security_params->SecurityLevel) {
|
|
return MLME_UNSUPPORTED_SECURITY;
|
|
}
|
|
//TODO verify this with Kevin
|
|
return MLME_UNSUPPORTED_LEGACY;
|
|
}
|
|
|
|
// security_level_compare.FrameType = b->fcf_dsn.frametype;
|
|
if (b->fcf_dsn.frametype == MAC_FRAME_CMD) {
|
|
openPayloadLength = 1;
|
|
// security_level_compare.CommandFrameIdentifier = mcps_mac_command_frame_id_get(b);
|
|
}
|
|
|
|
//TODO do this proper way when security description is implemeted
|
|
|
|
// mac_data_interface_minium_security_level_get(rf_mac_setup, &security_level_compare);
|
|
//
|
|
// //Validate Security Level
|
|
// if (!mac_security_interface_security_level_compare(security_params->SecurityLevel, security_level_compare.SecurityMinimum)) {
|
|
// //Drop packet reason rx level was less secured than requested one
|
|
// tr_debug("RX Security level less than minimum level");
|
|
// return MLME_IMPROPER_SECURITY_LEVEL;
|
|
// }
|
|
|
|
neighbour_security_update_t neighbour_validation;
|
|
memset(&neighbour_validation, 0, sizeof(neighbour_validation));
|
|
neighbour_validation.frameCounter = mcps_mac_security_frame_counter_read(b);
|
|
|
|
if (neighbour_validation.frameCounter == 0xffffffff) {
|
|
tr_debug("Max Framecounter value..Drop");
|
|
return MLME_COUNTER_ERROR;
|
|
}
|
|
|
|
//READ SRC Address
|
|
|
|
uint16_t SrcPANId = mac_header_get_src_panid(&b->fcf_dsn, mac_header_message_start_pointer(b), rf_mac_setup->pan_id);
|
|
|
|
if (b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
|
|
memcpy(neighbour_validation.address, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
|
|
neighbour_validation.addr_type = MAC_ADDR_MODE_64_BIT;
|
|
} else {
|
|
mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address);
|
|
neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode;
|
|
}
|
|
neighbour_validation.keyId = security_params->KeyIndex;
|
|
|
|
// Get A Key description
|
|
key_description = mac_sec_key_description_get(rf_mac_setup, security_params, b->fcf_dsn.SrcAddrMode, neighbour_validation.address, SrcPANId);
|
|
if (!key_description) {
|
|
return MLME_UNAVAILABLE_KEY;
|
|
}
|
|
|
|
if (key_description->unique_key_descriptor) {
|
|
//Discover device table by device description handle
|
|
key_device_description = key_description->KeyDeviceList;
|
|
device_descriptor_handle = key_device_description->DeviceDescriptorHandle;
|
|
//Discover device descriptor by handle
|
|
b->neigh_info = mac_sec_mib_device_description_get_attribute_index(rf_mac_setup, device_descriptor_handle);
|
|
if (!b->neigh_info) {
|
|
return MLME_UNSUPPORTED_SECURITY;
|
|
}
|
|
} else {
|
|
|
|
if (!b->neigh_info) {
|
|
if (SrcPANId == rf_mac_setup->pan_id && rf_mac_setup->mac_security_bypass_unknow_device &&
|
|
(b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT && security_params->SecurityLevel > AES_SECURITY_LEVEL_ENC)) {
|
|
security_by_pass = true;//Accept by pass only from same PAN-ID
|
|
} else {
|
|
return MLME_UNSUPPORTED_SECURITY;
|
|
}
|
|
}
|
|
|
|
device_descriptor_handle = mac_mib_device_descption_attribute_get_by_descriptor(rf_mac_setup, b->neigh_info);
|
|
key_device_description = mac_sec_mib_key_device_description_discover_from_list(key_description, device_descriptor_handle);
|
|
}
|
|
|
|
if (key_device_description) {
|
|
//validate BlackList status
|
|
if (key_device_description->Blacklisted) {
|
|
tr_debug("Blacklisted key for device %s", trace_array(b->neigh_info->ExtAddress, 8));
|
|
return MLME_UNAVAILABLE_KEY;
|
|
}
|
|
|
|
if (b->neigh_info) {
|
|
uint32_t min_accepted_frame_counter = mac_mib_key_device_frame_counter_get(key_description, b->neigh_info, device_descriptor_handle);
|
|
if (neighbour_validation.frameCounter < min_accepted_frame_counter) {
|
|
tr_debug("MLME_COUNTER_ERROR");
|
|
return MLME_COUNTER_ERROR;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
key = key_description->Key;
|
|
if (security_by_pass) {
|
|
memcpy(neighbour_validation.nonce_ptr, neighbour_validation.address, 8);
|
|
} else {
|
|
memcpy(neighbour_validation.nonce_ptr, b->neigh_info->ExtAddress, 8);
|
|
}
|
|
|
|
ccm_globals_t ccm_ptr;
|
|
|
|
if (!ccm_sec_init(&ccm_ptr, security_params->SecurityLevel, key, AES_CCM_DECRYPT, 2)) {
|
|
return MLME_UNSUPPORTED_SECURITY;
|
|
}
|
|
|
|
mac_security_interface_aux_ccm_nonce_set(ccm_ptr.exp_nonce, neighbour_validation.nonce_ptr, neighbour_validation.frameCounter, security_params->SecurityLevel);
|
|
|
|
if (ccm_ptr.mic_len) {
|
|
// this is asuming that there is no headroom for buffers.
|
|
ccm_ptr.adata_len = mcps_mac_header_length_from_received_frame(b) + openPayloadLength;
|
|
//SET MIC PTR
|
|
ccm_ptr.mic = mcps_security_mic_pointer_get(b);
|
|
ccm_ptr.adata_ptr = mac_header_message_start_pointer(b);
|
|
}
|
|
|
|
ccm_ptr.data_ptr = (mcps_mac_payload_pointer_get(b) + openPayloadLength);
|
|
ccm_ptr.data_len = b->mac_payload_length - openPayloadLength;
|
|
if (ccm_process_run(&ccm_ptr) != 0) {
|
|
return MLME_SECURITY_FAIL;
|
|
}
|
|
|
|
//Update key device and key description tables
|
|
if (!security_by_pass) {
|
|
|
|
mac_sec_mib_key_device_frame_counter_set(key_description, b->neigh_info, neighbour_validation.frameCounter + 1, device_descriptor_handle);
|
|
|
|
if (!key_device_description) {
|
|
if (!rf_mac_setup->secFrameCounterPerKey) {
|
|
// Black list old used keys by this device
|
|
mac_sec_mib_device_description_blacklist(rf_mac_setup, device_descriptor_handle);
|
|
}
|
|
|
|
key_device_description = mac_sec_mib_key_device_description_list_update(key_description);
|
|
if (key_device_description) {
|
|
tr_debug("Set new device user %u for key", device_descriptor_handle);
|
|
key_device_description->DeviceDescriptorHandle = device_descriptor_handle;
|
|
}
|
|
}
|
|
}
|
|
|
|
return MLME_SUCCESS;
|
|
}
|
|
|
|
static void mcps_comm_status_indication_generate(uint8_t status, mac_pre_parsed_frame_t *buf, mac_api_t *mac)
|
|
{
|
|
mlme_comm_status_t comm_status;
|
|
protocol_interface_rf_mac_setup_s *rf_ptr = buf->mac_class_ptr;
|
|
memset(&comm_status, 0, sizeof(mlme_comm_status_t));
|
|
comm_status.status = status;
|
|
//Call com status
|
|
comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_ptr->pan_id);
|
|
comm_status.DstAddrMode = buf->fcf_dsn.DstAddrMode;;
|
|
mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.DstAddr);
|
|
comm_status.SrcAddrMode = buf->fcf_dsn.SrcAddrMode;
|
|
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.SrcAddr);
|
|
mac_header_security_components_read(buf, &comm_status.Key);
|
|
mac->mlme_ind_cb(mac, MLME_COMM_STATUS, &comm_status);
|
|
}
|
|
|
|
|
|
|
|
static int8_t mac_data_interface_host_accept_data(mcps_data_ind_t *data_ind, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if ((data_ind->DstAddrMode == MAC_ADDR_MODE_16_BIT) && (data_ind->DstAddr[0] == 0xff && data_ind->DstAddr[1] == 0xff)) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (data_ind->msduLength) {
|
|
if (!rf_mac_setup->macRxDataAtPoll && rf_mac_setup->macDataPollReq) {
|
|
eventOS_callback_timer_stop(rf_mac_setup->mlme_timer_id);
|
|
rf_mac_setup->macRxDataAtPoll = true;
|
|
eventOS_callback_timer_start(rf_mac_setup->mlme_timer_id, 400); //20ms
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL_AFTER_DATA;
|
|
rf_mac_setup->mlme_tick_count = 0;
|
|
}
|
|
return 0;
|
|
} else {
|
|
eventOS_callback_timer_stop(rf_mac_setup->mlme_timer_id);
|
|
mac_mlme_poll_process_confirm(rf_mac_setup, MLME_NO_DATA);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_api_t *mac)
|
|
{
|
|
int8_t retval = -1;
|
|
uint8_t status;
|
|
|
|
//allocate Data ind primitiv and parse packet to that
|
|
mcps_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(mcps_data_ind_t));
|
|
|
|
if (!data_ind) {
|
|
goto DROP_PACKET;
|
|
}
|
|
memset(data_ind, 0, sizeof(mcps_data_ind_t));
|
|
//Parse data
|
|
data_ind->DSN = buf->fcf_dsn.DSN;
|
|
data_ind->DSN_suppressed = buf->fcf_dsn.sequenceNumberSuppress;
|
|
data_ind->DstAddrMode = buf->fcf_dsn.DstAddrMode;
|
|
mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->DstAddr);
|
|
data_ind->SrcAddrMode = buf->fcf_dsn.SrcAddrMode;
|
|
|
|
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->SrcAddr);
|
|
|
|
data_ind->SrcPANId = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
|
|
data_ind->DstPANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
|
|
|
|
data_ind->mpduLinkQuality = buf->LQI;
|
|
data_ind->signal_dbm = buf->dbm;
|
|
data_ind->timestamp = buf->timestamp;
|
|
/* Parse security part */
|
|
mac_header_security_components_read(buf, &data_ind->Key);
|
|
if (data_ind->SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
|
|
memcpy(data_ind->SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
|
|
data_ind->SrcAddrMode = MAC_ADDR_MODE_64_BIT;
|
|
}
|
|
|
|
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, data_ind->SrcAddr, data_ind->SrcAddrMode, data_ind->SrcPANId);
|
|
if (buf->fcf_dsn.securityEnabled) {
|
|
status = mac_data_interface_decrypt_packet(buf, &data_ind->Key);
|
|
if (status != MLME_SUCCESS) {
|
|
mcps_comm_status_indication_generate(status, buf, mac);
|
|
goto DROP_PACKET;
|
|
}
|
|
}
|
|
|
|
if (!mac_payload_information_elements_parse(buf)) {
|
|
goto DROP_PACKET;
|
|
}
|
|
data_ind->msduLength = buf->mac_payload_length;
|
|
data_ind->msdu_ptr = buf->macPayloadPtr;
|
|
|
|
/* Validate Polling device */
|
|
if (!rf_mac_setup->macCapRxOnIdle) {
|
|
if (mac_data_interface_host_accept_data(data_ind, rf_mac_setup) != 0) {
|
|
//tr_debug("Drop by not Accept");
|
|
goto DROP_PACKET;
|
|
}
|
|
}
|
|
|
|
if (mac) {
|
|
|
|
if (buf->fcf_dsn.frameVersion == MAC_FRAME_VERSION_2015) {
|
|
if (!rf_mac_setup->mac_extension_enabled) {
|
|
goto DROP_PACKET;
|
|
}
|
|
mcps_data_ie_list_t ie_list;
|
|
ie_list.payloadIeList = buf->payloadsIePtr;
|
|
ie_list.payloadIeListLength = buf->payloadsIeLength;
|
|
ie_list.headerIeList = buf->headerIePtr;
|
|
ie_list.headerIeListLength = buf->headerIeLength;
|
|
//Swap compressed address to broadcast when dst Address is elided
|
|
if (buf->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE) {
|
|
data_ind->DstAddrMode = MAC_ADDR_MODE_16_BIT;
|
|
data_ind->DstAddr[0] = 0xff;
|
|
data_ind->DstAddr[1] = 0xff;
|
|
}
|
|
mac->data_ind_ext_cb(mac, data_ind, &ie_list);
|
|
|
|
} else {
|
|
mac->data_ind_cb(mac, data_ind);
|
|
}
|
|
retval = 0;
|
|
}
|
|
|
|
DROP_PACKET:
|
|
ns_dyn_mem_free(data_ind);
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
return retval;
|
|
}
|
|
|
|
static void mac_lib_res_no_data_to_req(mac_pre_parsed_frame_t *buffer, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mac_pre_build_frame_t *buf = mcps_sap_prebuild_frame_buffer_get(0);
|
|
if (!buf) {
|
|
return;
|
|
}
|
|
|
|
buf->fcf_dsn.SrcAddrMode = buffer->fcf_dsn.DstAddrMode;
|
|
buf->fcf_dsn.DstAddrMode = buffer->fcf_dsn.SrcAddrMode;
|
|
//SET PANID
|
|
buf->SrcPANId = mac_header_get_dst_panid(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer), rf_mac_setup->pan_id);
|
|
buf->DstPANId = buf->SrcPANId;
|
|
|
|
mac_header_get_dst_address(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer), buf->SrcAddr);
|
|
mac_header_get_src_address(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer), buf->DstAddr);
|
|
|
|
buf->fcf_dsn.securityEnabled = buffer->fcf_dsn.securityEnabled;
|
|
buf->fcf_dsn.intraPan = true;
|
|
buf->WaitResponse = buf->fcf_dsn.ackRequested = true;
|
|
buf->mac_header_length_with_security = 3;
|
|
//Check PanID presents at header
|
|
buf->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buf->fcf_dsn);
|
|
buf->fcf_dsn.SrcPanPresents = mac_src_panid_present(&buf->fcf_dsn);
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
buf->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
buf->aux_header.securityLevel = rf_mac_setup->mac_auto_request.SecurityLevel;
|
|
buf->aux_header.KeyIdMode = rf_mac_setup->mac_auto_request.KeyIdMode;
|
|
buf->aux_header.KeyIndex = rf_mac_setup->mac_auto_request.KeyIndex;
|
|
memcpy(buf->aux_header.Keysource, rf_mac_setup->mac_auto_request.Keysource, 8);
|
|
}
|
|
buf->fcf_dsn.frametype = FC_DATA_FRAME;
|
|
buf->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
|
|
buf->mac_payload = NULL;
|
|
buf->mac_payload_length = 0;
|
|
buf->security_mic_len = mac_security_mic_length_get(buf->aux_header.securityLevel);
|
|
buf->mac_header_length_with_security += mac_header_security_aux_header_length(buf->aux_header.securityLevel, buf->aux_header.KeyIdMode);
|
|
buf->mac_header_length_with_security += mac_header_address_length(&buf->fcf_dsn);
|
|
mcps_sap_pd_req_queue_write(rf_mac_setup, buf);
|
|
}
|
|
|
|
static int8_t mac_beacon_request_handler(mac_pre_parsed_frame_t *buffer, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
|
|
if (buffer->fcf_dsn.SrcAddrMode != MAC_ADDR_MODE_NONE || buffer->fcf_dsn.DstAddrMode != MAC_ADDR_MODE_16_BIT) {
|
|
return -1;
|
|
}
|
|
// Note FHSS from received beacon request
|
|
if (rf_mac_setup->fhss_api) {
|
|
rf_mac_setup->fhss_api->receive_frame(rf_mac_setup->fhss_api, 0, NULL, 0, NULL, FHSS_SYNCH_REQUEST_FRAME);
|
|
}
|
|
// mac_data_interface_build_beacon() uses the same buffer to build the response
|
|
// and it is then feed to protocol buffer. Buffer should be freed only if it returns zero.
|
|
return mac_mlme_beacon_tx(rf_mac_setup);
|
|
|
|
}
|
|
|
|
static int8_t mac_command_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_api_t *mac)
|
|
{
|
|
int8_t retval = -1;
|
|
mlme_security_t security_params;
|
|
uint8_t mac_command;
|
|
uint8_t status;
|
|
uint8_t temp_src_address[8];
|
|
|
|
|
|
//Read address and pan-id
|
|
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), temp_src_address);
|
|
uint8_t address_mode = buf->fcf_dsn.SrcAddrMode;
|
|
uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
|
|
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, temp_src_address, address_mode, pan_id);
|
|
//Decrypt Packet if secured
|
|
if (buf->fcf_dsn.securityEnabled) {
|
|
mac_header_security_components_read(buf, &security_params);
|
|
|
|
status = mac_data_interface_decrypt_packet(buf, &security_params);
|
|
if (status != MLME_SUCCESS) {
|
|
|
|
mcps_comm_status_indication_generate(status, buf, mac);
|
|
goto DROP_PACKET;
|
|
}
|
|
}
|
|
|
|
mac_command = mcps_mac_command_frame_id_get(buf);
|
|
|
|
switch (mac_command) {
|
|
case MAC_DATA_REQ:
|
|
//Here 2 check
|
|
if (mac_indirect_data_req_handle(buf, rf_mac_setup) == 0) {
|
|
mac_lib_res_no_data_to_req(buf, rf_mac_setup);
|
|
}
|
|
retval = 0;
|
|
break;
|
|
case MAC_BEACON_REQ:
|
|
retval = mac_beacon_request_handler(buf, rf_mac_setup);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
DROP_PACKET:
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
return retval;
|
|
}
|
|
|
|
static void mac_nap_tun_data_handler(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
phy_device_driver_s *driver = rf_mac_setup->tun_extension_rf_driver->phy_driver;
|
|
if (driver->phy_rx_cb) {
|
|
driver->phy_rx_cb(buf->buf, buf->frameLength, buf->LQI, buf->dbm, rf_mac_setup->tun_extension_rf_driver->id);
|
|
}
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
}
|
|
|
|
static void mac_data_interface_parse_beacon(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mlme_beacon_ind_t ind_data;
|
|
|
|
uint16_t len;
|
|
uint8_t *ptr;
|
|
mlme_beacon_gts_spec_t gts_spec;
|
|
// uint8_t *gts_info = NULL;
|
|
uint8_t *pending_address_list = NULL;
|
|
uint8_t SuperframeSpec[2];
|
|
|
|
uint16_t src_pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
|
|
|
|
//validate beacon pan-id and filter other network out
|
|
if (rf_mac_setup->pan_id < 0xffff && (rf_mac_setup->pan_id != src_pan_id && !rf_mac_setup->macAcceptAnyBeacon)) {
|
|
tr_debug("Drop Beacon by unknow panid");
|
|
return;
|
|
}
|
|
|
|
if (!mac_payload_information_elements_parse(buf)) {
|
|
return;
|
|
}
|
|
|
|
/*Add received bytes in statistics*/
|
|
tr_debug("mac_parse_beacon");
|
|
|
|
ptr = buf->macPayloadPtr;
|
|
len = buf->mac_payload_length;
|
|
SuperframeSpec[0] = *ptr++;
|
|
SuperframeSpec[1] = *ptr++;
|
|
gts_spec.description_count = (*ptr & 7);
|
|
gts_spec.gts_permit = ((*ptr++ & 0x80) >> 7);
|
|
len -= 3;
|
|
if (gts_spec.description_count) {
|
|
tr_error("GTS info count not zero");
|
|
//calucalate Length
|
|
uint8_t gts_field_length = ((gts_spec.description_count) * 3);
|
|
if (len < gts_field_length) {
|
|
return;
|
|
}
|
|
len -= gts_field_length;
|
|
ptr += gts_field_length;
|
|
}
|
|
//Pendinlist
|
|
ind_data.PendAddrSpec.short_address_count = (*ptr & 7);
|
|
ind_data.PendAddrSpec.extended_address_count = ((*ptr++ & 0x70) >> 4);
|
|
len -= 1;
|
|
if (ind_data.PendAddrSpec.short_address_count || ind_data.PendAddrSpec.extended_address_count) {
|
|
if ((ind_data.PendAddrSpec.extended_address_count + ind_data.PendAddrSpec.short_address_count) > 7) {
|
|
//over 7 address
|
|
return;
|
|
}
|
|
uint8_t pending_address_list_size = (ind_data.PendAddrSpec.short_address_count * 2);
|
|
pending_address_list_size += (ind_data.PendAddrSpec.extended_address_count * 8);
|
|
if (len < pending_address_list_size) {
|
|
return;
|
|
}
|
|
pending_address_list = ptr;
|
|
ptr += pending_address_list_size;
|
|
len -= pending_address_list_size;
|
|
}
|
|
|
|
memset(&ind_data.PANDescriptor, 0, sizeof(mlme_pan_descriptor_t));
|
|
|
|
if (rf_mac_setup->fhss_api) {
|
|
ind_data.PANDescriptor.LogicalChannel = 0; //Force Allways same channel
|
|
} else {
|
|
ind_data.PANDescriptor.LogicalChannel = rf_mac_setup->mac_channel;
|
|
}
|
|
ind_data.PANDescriptor.ChannelPage = 0;
|
|
ind_data.PANDescriptor.CoordAddrMode = buf->fcf_dsn.SrcAddrMode;
|
|
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), ind_data.PANDescriptor.CoordAddress);
|
|
ind_data.PANDescriptor.CoordPANId = src_pan_id;
|
|
ind_data.PANDescriptor.LinkQuality = buf->LQI;
|
|
ind_data.PANDescriptor.GTSPermit = gts_spec.gts_permit;
|
|
ind_data.PANDescriptor.Timestamp = buf->timestamp;
|
|
mac_header_security_components_read(buf, &ind_data.PANDescriptor.Key);
|
|
ind_data.PANDescriptor.SecurityFailure = 0;
|
|
ind_data.PANDescriptor.SuperframeSpec[0] = SuperframeSpec[0];
|
|
ind_data.PANDescriptor.SuperframeSpec[1] = SuperframeSpec[1];
|
|
|
|
ind_data.BSN = buf->fcf_dsn.DSN;
|
|
ind_data.AddrList = pending_address_list;
|
|
ind_data.beacon_data_length = len;
|
|
ind_data.beacon_data = ptr;
|
|
|
|
mac_mlme_beacon_notify(rf_mac_setup, &ind_data);
|
|
|
|
}
|
|
|
|
static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf)
|
|
{
|
|
protocol_interface_rf_mac_setup_s *rf_mac_setup = buf->mac_class_ptr;
|
|
if (!rf_mac_setup) {
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
return;
|
|
}
|
|
/* push data to stack if sniffer mode is enabled */
|
|
if (rf_mac_setup->macProminousMode) {
|
|
mac_nap_tun_data_handler(buf, rf_mac_setup);
|
|
return;
|
|
}
|
|
mac_api_t *mac = get_sw_mac_api(rf_mac_setup);
|
|
if (!mac || (rf_mac_setup->mac_mlme_scan_resp && buf->fcf_dsn.frametype != MAC_FRAME_BEACON)) {
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
return;
|
|
}
|
|
if (buf->fcf_dsn.ackRequested == false) {
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_BC_RX_COUNT, 0);
|
|
}
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_RX_COUNT, 0);
|
|
switch (buf->fcf_dsn.frametype) {
|
|
case MAC_FRAME_BEACON:
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_BEA_RX_COUNT, 0);
|
|
mac_data_interface_parse_beacon(buf, rf_mac_setup);
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
break;
|
|
case MAC_FRAME_DATA:
|
|
if (rf_mac_setup->tun_extension_rf_driver) {
|
|
mac_nap_tun_data_handler(buf, rf_mac_setup);
|
|
return;
|
|
}
|
|
mac_data_sap_rx_handler(buf, rf_mac_setup, mac);
|
|
break;
|
|
case MAC_FRAME_CMD:
|
|
if (rf_mac_setup->tun_extension_rf_driver) {
|
|
if (mcps_mac_command_frame_id_get(buf) != MAC_BEACON_REQ) {
|
|
mac_nap_tun_data_handler(buf, rf_mac_setup);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//Handle Command Frame
|
|
mac_command_sap_rx_handler(buf, rf_mac_setup, mac);
|
|
break;
|
|
|
|
default:
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
}
|
|
|
|
}
|
|
|
|
static void mac_mcps_asynch_finish(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (buffer->asynch_request && rf_mac_setup->fhss_api) {
|
|
// Must return to scheduled channel after asynch process by calling TX done
|
|
rf_mac_setup->fhss_api->data_tx_done(rf_mac_setup->fhss_api, false, true, buffer->msduHandle);
|
|
}
|
|
}
|
|
|
|
void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (!rf_mac_setup) {
|
|
return;
|
|
}
|
|
while (!rf_mac_setup->active_pd_data_request) {
|
|
bool is_bc_queue = false;
|
|
mac_pre_build_frame_t *buffer;
|
|
// With FHSS, poll broadcast queue on broadcast channel first
|
|
if (rf_mac_setup->fhss_api) {
|
|
if (rf_mac_setup->fhss_api->is_broadcast_channel(rf_mac_setup->fhss_api) == true) {
|
|
if (rf_mac_setup->pd_data_request_bc_queue_to_go) {
|
|
is_bc_queue = true;
|
|
}
|
|
}
|
|
}
|
|
buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, is_bc_queue, false);
|
|
|
|
if (buffer) {
|
|
//Here
|
|
if (buffer->ExtendedFrameExchange) {
|
|
//Update here state and store peer
|
|
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
|
|
}
|
|
rf_mac_setup->active_pd_data_request = buffer;
|
|
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
|
|
if (buffer->ExtendedFrameExchange) {
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
|
|
}
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mac_mcps_asynch_finish(rf_mac_setup, buffer);
|
|
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
|
|
} else {
|
|
return;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
//allocate Data ind primitiv and parse packet to that
|
|
mlme_security_t key;
|
|
uint8_t srcAddressMode;
|
|
uint8_t SrcAddr[8]; /**< Source address */
|
|
memset(SrcAddr, 0, 8);
|
|
memset(&key, 0, sizeof(mlme_security_t));
|
|
srcAddressMode = buf->fcf_dsn.SrcAddrMode;
|
|
if (buf->fcf_dsn.SrcAddrMode) {
|
|
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr);
|
|
} else {
|
|
if (rf_mac_setup->mac_edfe_enabled && (buf->fcf_dsn.frametype == FC_DATA_FRAME && !buf->fcf_dsn.ackRequested)) {
|
|
memcpy(SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
|
|
srcAddressMode = MAC_ADDR_MODE_64_BIT;
|
|
}
|
|
}
|
|
uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
|
|
/* Parse security part */
|
|
mac_header_security_components_read(buf, &key);
|
|
|
|
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, srcAddressMode, pan_id);
|
|
if (buf->fcf_dsn.securityEnabled) {
|
|
uint8_t status = mac_data_interface_decrypt_packet(buf, &key);
|
|
if (status != MLME_SUCCESS) {
|
|
rf_mac_setup->mac_tx_result = MAC_ACK_SECURITY_FAIL;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (buf->mac_payload_length && !mac_payload_information_elements_parse(buf)) {
|
|
rf_mac_setup->mac_tx_result = MAC_ACK_SECURITY_FAIL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mac_pd_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (rf_mac_setup->active_pd_data_request) {
|
|
mac_pre_build_frame_t *buffer = rf_mac_setup->active_pd_data_request;
|
|
if (mac_data_request_confirmation_finnish(rf_mac_setup, buffer)) {
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mac_mcps_asynch_finish(rf_mac_setup, buffer);
|
|
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
|
|
} else {
|
|
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mac_mcps_asynch_finish(rf_mac_setup, buffer);
|
|
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
|
|
}
|
|
|
|
static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mcps_data_conf_t mcps_data_conf;
|
|
memset(&mcps_data_conf, 0, sizeof(mcps_data_conf_t));
|
|
mcps_data_conf.msduHandle = rf_mac_setup->mac_mcps_data_conf_fail.msduHandle;
|
|
mcps_data_conf.status = rf_mac_setup->mac_mcps_data_conf_fail.status;
|
|
mcps_data_confirm_cb(rf_mac_setup, &mcps_data_conf, NULL);
|
|
}
|
|
|
|
|
|
static void mac_pd_data_ack_handler(mac_pre_parsed_frame_t *buf)
|
|
{
|
|
protocol_interface_rf_mac_setup_s *rf_mac_setup = buf->mac_class_ptr;
|
|
|
|
if (!rf_mac_setup->active_pd_data_request) {
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
tr_debug("RX ack without active buffer");
|
|
} else {
|
|
mac_pre_build_frame_t *buffer = rf_mac_setup->active_pd_data_request;
|
|
|
|
//Validate here ack is proper to active buffer
|
|
if (!mac_pd_sap_ack_validation(rf_mac_setup, &buf->fcf_dsn, mac_header_message_start_pointer(buf))) {
|
|
tr_debug("Not a valid ACK for active tx process");
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
return;
|
|
}
|
|
|
|
if (mac_ack_sap_rx_handler(buf, rf_mac_setup)) {
|
|
//Do not forward ACK payload but Accept ACK
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
buf = NULL;
|
|
|
|
}
|
|
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mcps_data_confirm_handle(rf_mac_setup, buffer, buf);
|
|
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
|
|
|
}
|
|
|
|
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
|
|
}
|
|
|
|
|
|
static void mac_mcps_sap_data_tasklet(arm_event_s *event)
|
|
{
|
|
uint8_t event_type = event->event_type;
|
|
|
|
switch (event_type) {
|
|
case MCPS_SAP_DATA_IND_EVENT:
|
|
if (event->data_ptr) {
|
|
mac_data_interface_frame_handler((mac_pre_parsed_frame_t *)event->data_ptr);
|
|
}
|
|
|
|
break;
|
|
|
|
case MCPS_SAP_DATA_CNF_EVENT:
|
|
//mac_data_interface_tx_done(event->data_ptr);
|
|
mac_pd_data_confirm_handle((protocol_interface_rf_mac_setup_s *)event->data_ptr);
|
|
break;
|
|
|
|
case MCPS_SAP_DATA_CNF_FAIL_EVENT:
|
|
mac_pd_data_confirm_failure_handle((protocol_interface_rf_mac_setup_s *)event->data_ptr);
|
|
break;
|
|
|
|
case MCPS_SAP_DATA_ACK_CNF_EVENT:
|
|
mac_pd_data_ack_handler((mac_pre_parsed_frame_t *)event->data_ptr);
|
|
break;
|
|
|
|
case MAC_MLME_EVENT_HANDLER:
|
|
mac_mlme_event_cb(event->data_ptr);
|
|
break;
|
|
case MAC_MCPS_INDIRECT_TIMER_CB:
|
|
mac_indirect_data_ttl_handle((protocol_interface_rf_mac_setup_s *)event->data_ptr, (uint16_t)event->event_data);
|
|
break;
|
|
|
|
case MAC_MLME_SCAN_CONFIRM_HANDLER:
|
|
mac_mlme_scan_confirmation_handle((protocol_interface_rf_mac_setup_s *) event->data_ptr);
|
|
break;
|
|
case MAC_CCA_THR_UPDATE:
|
|
mac_cca_threshold_update((protocol_interface_rf_mac_setup_s *) event->data_ptr, event->event_data >> 8, (int8_t) event->event_data);
|
|
break;
|
|
case MAC_SAP_TRIG_TX:
|
|
mac_clear_active_event((protocol_interface_rf_mac_setup_s *) event->data_ptr, MAC_SAP_TRIG_TX);
|
|
mac_mcps_trig_buffer_from_queue((protocol_interface_rf_mac_setup_s *) event->data_ptr);
|
|
//No break necessary
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int8_t mac_mcps_sap_tasklet_init(void)
|
|
{
|
|
if (mac_tasklet_event_handler < 0) {
|
|
mac_tasklet_event_handler = eventOS_event_handler_create(&mac_mcps_sap_data_tasklet, 0);
|
|
}
|
|
|
|
return mac_tasklet_event_handler;
|
|
}
|
|
|
|
mac_pre_build_frame_t *mcps_sap_prebuild_frame_buffer_get(uint16_t payload_size)
|
|
{
|
|
mac_pre_build_frame_t *buffer = ns_dyn_mem_temporary_alloc(sizeof(mac_pre_build_frame_t));
|
|
if (!buffer) {
|
|
return NULL;
|
|
}
|
|
memset(buffer, 0, sizeof(mac_pre_build_frame_t));
|
|
buffer->initial_tx_channel = 0xffff;
|
|
buffer->aux_header.frameCounter = 0xffffffff;
|
|
buffer->DSN_allocated = false;
|
|
if (payload_size) {
|
|
//Mac interlnal payload allocate
|
|
buffer->mac_payload = ns_dyn_mem_temporary_alloc(payload_size);
|
|
if (!buffer->mac_payload) {
|
|
ns_dyn_mem_free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer->mac_allocated_payload_ptr = true;
|
|
buffer->mac_payload_length = payload_size;
|
|
} else {
|
|
buffer->mac_allocated_payload_ptr = false;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
|
|
void mcps_sap_prebuild_frame_buffer_free(mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (!buffer) {
|
|
return;
|
|
}
|
|
|
|
if (buffer->mac_allocated_payload_ptr) {
|
|
ns_dyn_mem_free(buffer->mac_payload);
|
|
}
|
|
//Free Buffer frame
|
|
ns_dyn_mem_free(buffer);
|
|
|
|
}
|
|
|
|
static mlme_key_descriptor_t *mac_frame_security_key_get(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
/* Encrypt the packet payload if AES encyption bit is set */
|
|
mlme_security_t key_source;
|
|
key_source.KeyIdMode = buffer->aux_header.KeyIdMode;
|
|
key_source.KeyIndex = buffer->aux_header.KeyIndex;
|
|
key_source.SecurityLevel = buffer->aux_header.securityLevel;
|
|
memcpy(key_source.Keysource, buffer->aux_header.Keysource, 8);
|
|
return mac_sec_key_description_get(rf_ptr, &key_source, buffer->fcf_dsn.DstAddrMode, buffer->DstAddr, buffer->DstPANId);
|
|
}
|
|
|
|
|
|
static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mlme_key_descriptor_t *key_description)
|
|
{
|
|
/* Encrypt the packet payload if AES encyption bit is set */
|
|
mlme_device_descriptor_t *device_description;
|
|
uint8_t *nonce_ext_64_ptr;
|
|
|
|
if (key_description->unique_key_descriptor) {
|
|
device_description = mac_sec_mib_device_description_get_attribute_index(rf_ptr, key_description->KeyDeviceList->DeviceDescriptorHandle);
|
|
if (!device_description) {
|
|
|
|
buffer->status = MLME_UNAVAILABLE_KEY;
|
|
return false;
|
|
}
|
|
nonce_ext_64_ptr = device_description->ExtAddress;
|
|
} else {
|
|
//Discover device descriptor only unicast packet which need ack
|
|
if (buffer->fcf_dsn.DstAddrMode && buffer->fcf_dsn.ackRequested) {
|
|
device_description = mac_sec_mib_device_description_get(rf_ptr, buffer->DstAddr, buffer->fcf_dsn.DstAddrMode, buffer->DstPANId);
|
|
if (!device_description) {
|
|
buffer->status = MLME_UNAVAILABLE_KEY;
|
|
return false;
|
|
}
|
|
}
|
|
nonce_ext_64_ptr = rf_ptr->mac64;
|
|
}
|
|
|
|
uint8_t *key_ptr = key_description->Key;
|
|
|
|
//Check If frame counter overflow is coming
|
|
if (buffer->aux_header.frameCounter == 0xffffffff) {
|
|
buffer->status = MLME_COUNTER_ERROR;
|
|
return false;
|
|
}
|
|
|
|
if (!ccm_sec_init(ccm_ptr, buffer->aux_header.securityLevel, key_ptr, AES_CCM_ENCRYPT, 2)) {
|
|
buffer->status = MLME_SECURITY_FAIL;
|
|
return false;
|
|
}
|
|
|
|
mac_security_interface_aux_ccm_nonce_set(ccm_ptr->exp_nonce, nonce_ext_64_ptr, buffer->aux_header.frameCounter,
|
|
buffer->aux_header.securityLevel);
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buf)
|
|
{
|
|
mac_event_t m_event;
|
|
/* Raed MAC TX state */
|
|
m_event = (mac_event_t) rf_mac_setup->mac_tx_result;
|
|
rf_mac_setup->mac_tx_result = MAC_STATE_IDLE;
|
|
|
|
/* Discard Tx timeout timer */
|
|
timer_mac_stop(rf_mac_setup);
|
|
if (m_event == MAC_CCA_FAIL) {
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_FAIL, 0);
|
|
tr_info("MAC CCA fail");
|
|
/* CCA fail */
|
|
//rf_mac_setup->cca_failure++;
|
|
buf->status = MLME_BUSY_CHAN;
|
|
} else {
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_COUNT, buf->mac_payload_length);
|
|
if (m_event == MAC_TX_FAIL) {
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_FAIL, 0);
|
|
tr_info("MAC tx fail");
|
|
buf->status = MLME_TX_NO_ACK;
|
|
} else if (m_event == MAC_TX_DONE) {
|
|
if (mac_is_ack_request_set(buf) == false) {
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_BC_TX_COUNT, 0);
|
|
}
|
|
if (buf->fcf_dsn.frametype == FC_CMD_FRAME && buf->mac_command_id == MAC_DATA_REQ) {
|
|
buf->status = MLME_NO_DATA;
|
|
} else {
|
|
buf->status = MLME_SUCCESS;
|
|
}
|
|
|
|
} else if (m_event == MAC_TX_DONE_PENDING) {
|
|
buf->status = MLME_SUCCESS;
|
|
} else if (m_event == MAC_TX_TIMEOUT) {
|
|
/* Make MAC Soft Reset */;
|
|
tr_debug("Driver TO event");
|
|
//Disable allways
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
//Enable Radio
|
|
mac_mlme_mac_radio_enable(rf_mac_setup);
|
|
buf->status = MLME_TRANSACTION_EXPIRED;
|
|
} else if (m_event == MAC_UNKNOWN_DESTINATION) {
|
|
buf->status = MLME_UNAVAILABLE_KEY;
|
|
} else if (m_event == MAC_ACK_SECURITY_FAIL) {
|
|
buf->status = MLME_TX_NO_ACK;
|
|
}/** else if (m_event == MAC_TX_PRECOND_FAIL) {
|
|
* Nothing to do, status already set to buf->status.
|
|
}**/
|
|
}
|
|
}
|
|
|
|
void mac_data_wait_timer_start(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
eventOS_callback_timer_stop(rf_mac_setup->mlme_timer_id);
|
|
eventOS_callback_timer_start(rf_mac_setup->mlme_timer_id, 200); //10ms
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL;
|
|
rf_mac_setup->mlme_tick_count = 30; //300ms
|
|
}
|
|
|
|
static void mac_data_interface_internal_tx_confirm_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buf)
|
|
{
|
|
//GET Interface
|
|
|
|
switch (buf->mac_command_id) {
|
|
case MAC_DATA_REQ:
|
|
|
|
if (buf->status == MLME_SUCCESS) {
|
|
if (!rf_mac_setup->macRxDataAtPoll) {
|
|
//Start Timer
|
|
mac_data_wait_timer_start(rf_mac_setup);
|
|
//Set Buffer back to
|
|
}
|
|
rf_mac_setup->active_pd_data_request = buf;
|
|
return;
|
|
|
|
} else {
|
|
//Disable Radio
|
|
if (!rf_mac_setup->macCapRxOnIdle) {
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
}
|
|
rf_mac_setup->macDataPollReq = false;
|
|
|
|
mac_api_t *mac_api = get_sw_mac_api(rf_mac_setup);
|
|
|
|
if (mac_api) {
|
|
mlme_poll_conf_t confirm;
|
|
confirm.status = buf->status;
|
|
mac_api->mlme_conf_cb(mac_api, MLME_POLL, &confirm);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case MAC_BEACON_REQ:
|
|
mac_mlme_active_scan_response_timer_start(rf_mac_setup);
|
|
break;
|
|
|
|
default:
|
|
if (rf_mac_setup->tun_extension_rf_driver) {
|
|
if (buf->fcf_dsn.ackRequested) {
|
|
phy_device_driver_s *driver = rf_mac_setup->tun_extension_rf_driver->phy_driver;
|
|
driver->phy_tx_done_cb(rf_mac_setup->tun_extension_rf_driver->id, 1, (phy_link_tx_status_e)buf->status, rf_mac_setup->mac_tx_status.cca_cnt, rf_mac_setup->mac_tx_status.retry);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
mcps_sap_prebuild_frame_buffer_free(buf);
|
|
|
|
}
|
|
|
|
static bool mcps_buffer_edfe_data_failure(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (!rf_ptr->mac_edfe_enabled || !buffer->ExtendedFrameExchange) {
|
|
return false;
|
|
}
|
|
|
|
if (rf_ptr->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
|
|
//Set to idle
|
|
tr_debug("Edfe Data send fail");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mac_pre_parsed_frame_t *ack_buf)
|
|
{
|
|
|
|
sw_mac_stats_update(rf_ptr, STAT_MAC_TX_CCA_ATT, rf_ptr->mac_tx_status.cca_cnt);
|
|
sw_mac_stats_update(rf_ptr, STAT_MAC_TX_RETRY, rf_ptr->mac_tx_status.retry);
|
|
mcps_data_conf_t confirm;
|
|
if (rf_ptr->fhss_api && !buffer->asynch_request) {
|
|
// FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
|
|
if (!mcps_buffer_edfe_data_failure(rf_ptr, buffer) && ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL))) {
|
|
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) {
|
|
|
|
if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
|
|
buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry;
|
|
} else {
|
|
buffer->fhss_retry_count += rf_ptr->mac_tx_status.retry;
|
|
}
|
|
buffer->fhss_cca_retry_count += rf_ptr->mac_tx_status.cca_cnt;
|
|
mcps_sap_pd_req_queue_write(rf_ptr, buffer);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (rf_ptr->mac_edfe_enabled && buffer->ExtendedFrameExchange) {
|
|
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
|
|
}
|
|
|
|
}
|
|
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt + buffer->fhss_cca_retry_count;
|
|
confirm.tx_retries = rf_ptr->mac_tx_status.retry + buffer->fhss_retry_count;
|
|
mac_common_data_confirmation_handle(rf_ptr, buffer);
|
|
confirm.msduHandle = buffer->msduHandle;
|
|
confirm.status = buffer->status;
|
|
if (ack_buf) {
|
|
confirm.timestamp = ack_buf->timestamp;
|
|
} else {
|
|
confirm.timestamp = 0;
|
|
}
|
|
|
|
if (buffer->upper_layer_request) {
|
|
//Check tunnel
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
mcps_data_confirm_cb(rf_ptr, &confirm, ack_buf);
|
|
} else {
|
|
mac_data_interface_internal_tx_confirm_handle(rf_ptr, buffer);
|
|
}
|
|
}
|
|
|
|
static void mac_security_data_params_set(ccm_globals_t *ccm_ptr, uint8_t *data_ptr, uint16_t msduLength)
|
|
{
|
|
ccm_ptr->data_len = msduLength;
|
|
ccm_ptr->data_ptr = data_ptr;
|
|
}
|
|
|
|
|
|
static void mac_security_authentication_data_params_set(ccm_globals_t *ccm_ptr, uint8_t *a_data_ptr,
|
|
uint8_t a_data_length)
|
|
{
|
|
if (ccm_ptr->mic_len) {
|
|
|
|
ccm_ptr->adata_len = a_data_length;
|
|
ccm_ptr->adata_ptr = a_data_ptr;
|
|
ccm_ptr->mic = ccm_ptr->data_ptr;
|
|
ccm_ptr->mic += ccm_ptr->data_len;
|
|
}
|
|
}
|
|
|
|
static uint32_t mcps_calculate_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint32_t time_to_tx)
|
|
{
|
|
// Max. time to TX is 65ms
|
|
if (time_to_tx > 65000) {
|
|
time_to_tx = 65000;
|
|
}
|
|
return mac_mcps_sap_get_phy_timestamp(rf_mac_setup) + time_to_tx;
|
|
}
|
|
|
|
static void mcps_generic_sequence_number_allocate(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (buffer->fcf_dsn.frameVersion < MAC_FRAME_VERSION_2015 || (buffer->fcf_dsn.frameVersion == MAC_FRAME_VERSION_2015 && !buffer->fcf_dsn.sequenceNumberSuppress)) {
|
|
/* Allocate SQN */
|
|
switch (buffer->fcf_dsn.frametype) {
|
|
case MAC_FRAME_CMD:
|
|
case MAC_FRAME_DATA:
|
|
if (!buffer->DSN_allocated) {
|
|
buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr);
|
|
buffer->DSN_allocated = true;
|
|
}
|
|
break;
|
|
case MAC_FRAME_BEACON:
|
|
buffer->fcf_dsn.DSN = mac_mlme_set_new_beacon_sqn(rf_ptr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static uint32_t mcps_generic_backoff_calc(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
uint32_t random_period = mac_csma_backoff_get(rf_ptr);
|
|
if (rf_ptr->rf_csma_extension_supported) {
|
|
return mcps_calculate_tx_time(rf_ptr, random_period);
|
|
}
|
|
return random_period;
|
|
}
|
|
|
|
static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver;
|
|
dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer;
|
|
|
|
ccm_globals_t ccm_ptr;
|
|
|
|
if (buffer->mac_header_length_with_security == 0) {
|
|
rf_ptr->mac_tx_status.length = buffer->mac_payload_length;
|
|
uint8_t *ptr = tx_buf->buf;
|
|
if (dev_driver->phy_header_length) {
|
|
ptr += dev_driver->phy_header_length;
|
|
}
|
|
tx_buf->len = buffer->mac_payload_length;
|
|
|
|
memcpy(ptr, buffer->mac_payload, buffer->mac_payload_length);
|
|
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
|
|
return 0;
|
|
}
|
|
|
|
//This will prepare MHR length with Header IE
|
|
mac_header_information_elements_preparation(buffer);
|
|
|
|
mcps_generic_sequence_number_allocate(rf_ptr, buffer);
|
|
mlme_key_descriptor_t *key_desc = NULL;
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
bool increment_framecounter = false;
|
|
//Remember to update security counter here!
|
|
key_desc = mac_frame_security_key_get(rf_ptr, buffer);
|
|
if (!key_desc) {
|
|
buffer->status = MLME_UNAVAILABLE_KEY;
|
|
return -2;
|
|
}
|
|
|
|
//GET Counter
|
|
uint32_t new_frameCounter = mac_sec_mib_key_outgoing_frame_counter_get(rf_ptr, key_desc);
|
|
// If buffer frame counter is set, this is FHSS channel retry, update frame counter only if something was sent after failure
|
|
if ((buffer->aux_header.frameCounter == 0xffffffff) || buffer->asynch_request || mac_data_counter_too_small(new_frameCounter, buffer->aux_header.frameCounter)) {
|
|
buffer->aux_header.frameCounter = new_frameCounter;
|
|
increment_framecounter = true;
|
|
}
|
|
|
|
if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) {
|
|
return -2;
|
|
}
|
|
//Increment security counter
|
|
if (increment_framecounter) {
|
|
mac_sec_mib_key_outgoing_frame_counter_increment(rf_ptr, key_desc);
|
|
}
|
|
}
|
|
|
|
//Calculate Payload length here with IE extension
|
|
uint16_t frame_length = mac_buffer_total_payload_length(buffer);
|
|
//Storage Mac Payload length here
|
|
uint16_t mac_payload_length = frame_length;
|
|
|
|
if (mac_payload_length > MAC_IEEE_802_15_4_MAX_MAC_SAFE_PAYLOAD_SIZE &&
|
|
rf_ptr->phy_mtu_size == MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) {
|
|
/* IEEE 802.15.4-2003 only allowed unsecured payloads up to 102 bytes
|
|
* (always leaving room for maximum MAC overhead).
|
|
* IEEE 802.15.4-2006 allows bigger if MAC header is small enough, but
|
|
* we have to set the version field.
|
|
*/
|
|
if (buffer->fcf_dsn.frameVersion < MAC_FRAME_VERSION_2006) {
|
|
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
}
|
|
}
|
|
|
|
if (rf_ptr->mac_ack_tx_active) {
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
ccm_free(&ccm_ptr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//Add MHR length to total length
|
|
frame_length += buffer->mac_header_length_with_security + buffer->security_mic_len;
|
|
if ((frame_length) > rf_ptr->phy_mtu_size - 2) {
|
|
tr_debug("Too Long %u, %u pa %u header %u mic %u", frame_length, mac_payload_length, buffer->mac_header_length_with_security, buffer->security_mic_len, rf_ptr->phy_mtu_size);
|
|
buffer->status = MLME_FRAME_TOO_LONG;
|
|
//decrement security counter
|
|
if (key_desc) {
|
|
mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
rf_ptr->mac_tx_status.length = frame_length;
|
|
uint8_t *ptr = tx_buf->buf;
|
|
if (dev_driver->phy_header_length) {
|
|
ptr += dev_driver->phy_header_length;
|
|
}
|
|
|
|
tx_buf->len = frame_length;
|
|
uint8_t *mhr_start = ptr;
|
|
if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
|
|
buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later
|
|
} else {
|
|
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
|
|
}
|
|
|
|
ptr = mac_generic_packet_write(rf_ptr, ptr, buffer);
|
|
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
uint8_t open_payload = 0;
|
|
if (buffer->fcf_dsn.frametype == MAC_FRAME_CMD) {
|
|
open_payload = 1;
|
|
}
|
|
mac_security_data_params_set(&ccm_ptr, (mhr_start + (buffer->mac_header_length_with_security + open_payload)), (mac_payload_length - open_payload));
|
|
mac_security_authentication_data_params_set(&ccm_ptr, mhr_start, (buffer->mac_header_length_with_security + open_payload));
|
|
ccm_process_run(&ccm_ptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int8_t mcps_generic_ack_data_request_init(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload)
|
|
{
|
|
mac_pre_build_frame_t *buffer = &rf_ptr->enhanced_ack_buffer;
|
|
//save timestamp
|
|
rf_ptr->enhanced_ack_handler_timestamp = mac_mcps_sap_get_phy_timestamp(rf_ptr);
|
|
|
|
memset(buffer, 0, sizeof(mac_pre_build_frame_t));
|
|
buffer->fcf_dsn.frametype = FC_ACK_FRAME;
|
|
buffer->fcf_dsn.frameVersion = fcf->frameVersion;
|
|
buffer->fcf_dsn.framePending = rf_ptr->mac_frame_pending;
|
|
buffer->fcf_dsn.DSN = fcf->DSN;
|
|
buffer->fcf_dsn.intraPan = fcf->intraPan;
|
|
buffer->fcf_dsn.sequenceNumberSuppress = fcf->sequenceNumberSuppress;
|
|
buffer->fcf_dsn.DstPanPresents = fcf->DstPanPresents;
|
|
buffer->fcf_dsn.SrcAddrMode = fcf->DstAddrMode;
|
|
buffer->fcf_dsn.SrcPanPresents = fcf->SrcPanPresents;
|
|
buffer->fcf_dsn.DstAddrMode = fcf->SrcAddrMode;
|
|
|
|
if (buffer->fcf_dsn.sequenceNumberSuppress) {
|
|
buffer->mac_header_length_with_security = 2;
|
|
} else {
|
|
buffer->mac_header_length_with_security = 3;
|
|
}
|
|
|
|
buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn);
|
|
|
|
buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr, rf_ptr->pan_id);
|
|
buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr, rf_ptr->pan_id);
|
|
mac_header_get_src_address(fcf, data_ptr, buffer->DstAddr);
|
|
mac_header_get_dst_address(fcf, data_ptr, buffer->SrcAddr);
|
|
|
|
//Security
|
|
buffer->fcf_dsn.securityEnabled = fcf->securityEnabled;
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
//Read Security AUX headers
|
|
const uint8_t *ptr = data_ptr;
|
|
ptr += mac_header_off_set_to_aux_header(fcf);
|
|
//Start parsing AUX header
|
|
mlme_security_t aux_parse;
|
|
mac_header_security_aux_header_parse(ptr, &aux_parse);
|
|
buffer->aux_header.KeyIdMode = aux_parse.KeyIdMode;
|
|
buffer->aux_header.KeyIndex = aux_parse.KeyIndex;
|
|
buffer->aux_header.securityLevel = aux_parse.SecurityLevel;
|
|
memcpy(buffer->aux_header.Keysource, aux_parse.Keysource, 8);
|
|
|
|
buffer->security_mic_len = mac_security_mic_length_get(buffer->aux_header.securityLevel);
|
|
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
buffer->mac_header_length_with_security += mac_header_security_aux_header_length(buffer->aux_header.securityLevel, buffer->aux_header.KeyIdMode);
|
|
|
|
}
|
|
|
|
uint16_t ie_header_length = 0;
|
|
uint16_t ie_payload_length = 0;
|
|
|
|
if (!mac_ie_vector_length_validate(ack_payload->ie_elements.headerIeVectorList, ack_payload->ie_elements.headerIovLength, &ie_header_length)) {
|
|
return -1;
|
|
}
|
|
|
|
if (!mac_ie_vector_length_validate(ack_payload->ie_elements.payloadIeVectorList, ack_payload->ie_elements.payloadIovLength, &ie_payload_length)) {
|
|
return -1;
|
|
}
|
|
|
|
buffer->ie_elements.headerIeVectorList = ack_payload->ie_elements.headerIeVectorList;
|
|
buffer->ie_elements.headerIovLength = ack_payload->ie_elements.headerIovLength;
|
|
buffer->ie_elements.payloadIeVectorList = ack_payload->ie_elements.payloadIeVectorList;
|
|
buffer->ie_elements.payloadIovLength = ack_payload->ie_elements.payloadIovLength;
|
|
buffer->headerIeLength = ie_header_length;
|
|
buffer->payloadsIeLength = ie_payload_length;
|
|
buffer->mac_payload = ack_payload->payloadPtr;
|
|
buffer->mac_payload_length = ack_payload->payloadLength;
|
|
|
|
//This will prepare MHR length with Header IE
|
|
mac_header_information_elements_preparation(buffer);
|
|
return 0;
|
|
}
|
|
|
|
int8_t mcps_generic_edfe_frame_init(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_edfe_response_t *response)
|
|
{
|
|
//Data Here
|
|
mac_pre_build_frame_t *buffer;
|
|
if (response->wait_response) {
|
|
if (rf_ptr->active_pd_data_request == NULL) {
|
|
return -1;
|
|
}
|
|
buffer = rf_ptr->active_pd_data_request;
|
|
buffer->message_builded = false;
|
|
} else {
|
|
buffer = &rf_ptr->enhanced_ack_buffer;
|
|
memset(buffer, 0, sizeof(mac_pre_build_frame_t));
|
|
buffer->fcf_dsn.frametype = FC_DATA_FRAME;
|
|
buffer->fcf_dsn.frameVersion = fcf->frameVersion;
|
|
buffer->fcf_dsn.DstPanPresents = fcf->DstPanPresents;
|
|
buffer->fcf_dsn.DstAddrMode = response->DstAddrMode;
|
|
buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr, rf_ptr->pan_id);
|
|
buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr, rf_ptr->pan_id);
|
|
memcpy(buffer->DstAddr, response->Address, 8);
|
|
}
|
|
buffer->fcf_dsn.intraPan = response->PanIdSuppressed;
|
|
buffer->fcf_dsn.SrcAddrMode = response->SrcAddrMode;
|
|
buffer->fcf_dsn.SrcPanPresents = response->SrcAddrMode;
|
|
buffer->fcf_dsn.framePending = false;
|
|
buffer->fcf_dsn.sequenceNumberSuppress = fcf->sequenceNumberSuppress;
|
|
|
|
buffer->WaitResponse = response->wait_response;
|
|
buffer->ExtendedFrameExchange = true;
|
|
|
|
if (buffer->fcf_dsn.sequenceNumberSuppress) {
|
|
buffer->mac_header_length_with_security = 2;
|
|
} else {
|
|
buffer->mac_header_length_with_security = 3;
|
|
}
|
|
|
|
buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn);
|
|
|
|
//Security
|
|
buffer->fcf_dsn.securityEnabled = fcf->securityEnabled;
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
//Read Security AUX headers
|
|
const uint8_t *ptr = data_ptr;
|
|
ptr += mac_header_off_set_to_aux_header(fcf);
|
|
//Start parsing AUX header
|
|
mlme_security_t aux_parse;
|
|
mac_header_security_aux_header_parse(ptr, &aux_parse);
|
|
buffer->aux_header.KeyIdMode = aux_parse.KeyIdMode;
|
|
buffer->aux_header.KeyIndex = aux_parse.KeyIndex;
|
|
buffer->aux_header.securityLevel = aux_parse.SecurityLevel;
|
|
memcpy(buffer->aux_header.Keysource, aux_parse.Keysource, 8);
|
|
|
|
buffer->security_mic_len = mac_security_mic_length_get(buffer->aux_header.securityLevel);
|
|
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
buffer->mac_header_length_with_security += mac_header_security_aux_header_length(buffer->aux_header.securityLevel, buffer->aux_header.KeyIdMode);
|
|
|
|
}
|
|
|
|
uint16_t ie_header_length = 0;
|
|
uint16_t ie_payload_length = 0;
|
|
|
|
if (!mac_ie_vector_length_validate(response->ie_response.headerIeVectorList, response->ie_response.headerIovLength, &ie_header_length)) {
|
|
return -1;
|
|
}
|
|
|
|
if (!mac_ie_vector_length_validate(response->ie_response.payloadIeVectorList, response->ie_response.payloadIovLength, &ie_payload_length)) {
|
|
return -1;
|
|
}
|
|
|
|
buffer->ie_elements.headerIeVectorList = response->ie_response.headerIeVectorList;
|
|
buffer->ie_elements.headerIovLength = response->ie_response.headerIovLength;
|
|
buffer->ie_elements.payloadIeVectorList = response->ie_response.payloadIeVectorList;
|
|
buffer->ie_elements.payloadIovLength = response->ie_response.payloadIovLength;
|
|
buffer->headerIeLength = ie_header_length;
|
|
buffer->payloadsIeLength = ie_payload_length;
|
|
buffer->mac_payload = NULL;
|
|
buffer->mac_payload_length = 0;
|
|
|
|
//This will prepare MHR length with Header IE
|
|
mac_header_information_elements_preparation(buffer);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool init_build)
|
|
{
|
|
phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver;
|
|
dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer;
|
|
|
|
ccm_globals_t ccm_ptr;
|
|
mac_pre_build_frame_t *buffer = &rf_ptr->enhanced_ack_buffer;
|
|
mlme_key_descriptor_t *key_desc = NULL;
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
//Remember to update security counter here!
|
|
key_desc = mac_frame_security_key_get(rf_ptr, buffer);
|
|
if (!key_desc) {
|
|
#ifdef __linux__
|
|
tr_debug("Drop a ACK missing key desc");
|
|
#endif
|
|
buffer->status = MLME_UNAVAILABLE_KEY;
|
|
return -2;
|
|
}
|
|
if (init_build) {
|
|
buffer->aux_header.frameCounter = mac_sec_mib_key_outgoing_frame_counter_get(rf_ptr, key_desc);
|
|
}
|
|
if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) {
|
|
#ifdef __linux__
|
|
tr_debug("Drop a ACK ignored by security init");
|
|
#endif
|
|
return -2;
|
|
}
|
|
if (init_build) {
|
|
//Increment security counter
|
|
mac_sec_mib_key_outgoing_frame_counter_increment(rf_ptr, key_desc);
|
|
}
|
|
}
|
|
|
|
//Calculate Payload length here with IE extension
|
|
uint16_t frame_length = mac_buffer_total_payload_length(buffer);
|
|
//Storage Mac Payload length here
|
|
uint16_t mac_payload_length = frame_length;
|
|
|
|
//Add MHR length to total length
|
|
frame_length += buffer->mac_header_length_with_security + buffer->security_mic_len;
|
|
uint16_t ack_mtu_size;
|
|
if (ENHANCED_ACK_MAX_LENGTH > rf_ptr->phy_mtu_size) {
|
|
ack_mtu_size = rf_ptr->phy_mtu_size;
|
|
} else {
|
|
ack_mtu_size = ENHANCED_ACK_MAX_LENGTH;
|
|
}
|
|
|
|
|
|
if ((frame_length) > ack_mtu_size - 2) {
|
|
buffer->status = MLME_FRAME_TOO_LONG;
|
|
|
|
if (key_desc) {
|
|
//decrement security counter
|
|
mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc);
|
|
ccm_free(&ccm_ptr);
|
|
}
|
|
#ifdef __linux__
|
|
tr_debug("Drop a ACK send by frame too long %u", frame_length);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
rf_ptr->mac_tx_status.length = frame_length;
|
|
uint8_t *ptr = tx_buf->enhanced_ack_buf;
|
|
if (dev_driver->phy_header_length) {
|
|
ptr += dev_driver->phy_header_length;
|
|
}
|
|
|
|
tx_buf->ack_len = frame_length;
|
|
uint8_t *mhr_start = ptr;
|
|
buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 1000; // 1ms delay before Ack
|
|
|
|
ptr = mac_generic_packet_write(rf_ptr, ptr, buffer);
|
|
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
mac_security_data_params_set(&ccm_ptr, (mhr_start + (buffer->mac_header_length_with_security)), (mac_payload_length));
|
|
mac_security_authentication_data_params_set(&ccm_ptr, mhr_start, (buffer->mac_header_length_with_security));
|
|
ccm_process_run(&ccm_ptr);
|
|
}
|
|
//Disable TX Time
|
|
phy_csma_params_t csma_params;
|
|
csma_params.backoff_time = 0;
|
|
csma_params.cca_enabled = false;
|
|
rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params);
|
|
if (rf_ptr->active_pd_data_request) {
|
|
timer_mac_stop(rf_ptr);
|
|
mac_pd_abort_active_tx(rf_ptr);
|
|
}
|
|
return mcps_pd_data_cca_trig(rf_ptr, buffer);
|
|
}
|
|
|
|
|
|
static int8_t mcps_generic_packet_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver;
|
|
dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer;
|
|
ccm_globals_t ccm_ptr;
|
|
|
|
if (!buffer) {
|
|
return -1;
|
|
}
|
|
|
|
if (buffer->mac_header_length_with_security == 0) {
|
|
rf_ptr->mac_tx_status.length = buffer->mac_payload_length;
|
|
uint8_t *ptr = tx_buf->buf;
|
|
if (dev_driver->phy_header_length) {
|
|
ptr += dev_driver->phy_header_length;
|
|
}
|
|
tx_buf->len = buffer->mac_payload_length;
|
|
|
|
memcpy(ptr, buffer->mac_payload, buffer->mac_payload_length);
|
|
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
|
|
return 0;
|
|
}
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
|
|
mlme_key_descriptor_t *key_desc = mac_frame_security_key_get(rf_ptr, buffer);
|
|
if (!key_desc) {
|
|
buffer->status = MLME_UNAVAILABLE_KEY;
|
|
return -2;
|
|
}
|
|
|
|
if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) {
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
//Calculate Payload length here with IE extension
|
|
uint16_t frame_length = mac_buffer_total_payload_length(buffer);
|
|
//Storage Mac Payload length here
|
|
uint16_t mac_payload_length = frame_length;
|
|
|
|
//Add MHR length to total length
|
|
frame_length += buffer->mac_header_length_with_security + buffer->security_mic_len;
|
|
|
|
rf_ptr->mac_tx_status.length = frame_length;
|
|
uint8_t *ptr = tx_buf->buf;
|
|
if (dev_driver->phy_header_length) {
|
|
ptr += dev_driver->phy_header_length;
|
|
}
|
|
|
|
tx_buf->len = frame_length;
|
|
uint8_t *mhr_start = ptr;
|
|
if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
|
|
buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later
|
|
} else {
|
|
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
|
|
}
|
|
|
|
ptr = mac_generic_packet_write(rf_ptr, ptr, buffer);
|
|
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
uint8_t open_payload = 0;
|
|
if (buffer->fcf_dsn.frametype == MAC_FRAME_CMD) {
|
|
open_payload = 1;
|
|
}
|
|
mac_security_data_params_set(&ccm_ptr, (mhr_start + (buffer->mac_header_length_with_security + open_payload)), (mac_payload_length - open_payload));
|
|
mac_security_authentication_data_params_set(&ccm_ptr, mhr_start, (buffer->mac_header_length_with_security + open_payload));
|
|
ccm_process_run(&ccm_ptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
platform_enter_critical();
|
|
mac_mlme_mac_radio_enable(rf_ptr);
|
|
rf_ptr->macTxProcessActive = true;
|
|
if (rf_ptr->rf_csma_extension_supported) {
|
|
//Write TX time
|
|
bool cca_enabled;
|
|
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) {
|
|
cca_enabled = false;
|
|
rf_ptr->mac_ack_tx_active = true;
|
|
} else {
|
|
if (buffer->ExtendedFrameExchange) {
|
|
if (buffer->fcf_dsn.SrcAddrMode) {
|
|
cca_enabled = true;
|
|
} else {
|
|
//Response
|
|
if (!buffer->WaitResponse) {
|
|
//Response
|
|
if (rf_ptr->mac_ack_tx_active) {
|
|
mac_csma_backoff_start(rf_ptr);
|
|
platform_exit_critical();
|
|
return -1;
|
|
}
|
|
rf_ptr->mac_edfe_response_tx_active = true;
|
|
} else {
|
|
rf_ptr->mac_edfe_response_tx_active = false;
|
|
}
|
|
cca_enabled = false;
|
|
rf_ptr->mac_edfe_tx_active = true;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (rf_ptr->mac_ack_tx_active) {
|
|
mac_csma_backoff_start(rf_ptr);
|
|
platform_exit_critical();
|
|
return -1;
|
|
}
|
|
cca_enabled = true;
|
|
}
|
|
|
|
}
|
|
// Use double CCA check with FHSS for data packets only
|
|
if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active && !rf_ptr->active_pd_data_request->asynch_request) {
|
|
if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) {
|
|
buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1;
|
|
buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1));
|
|
}
|
|
}
|
|
mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled);
|
|
if (mac_plme_cca_req(rf_ptr) != 0) {
|
|
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK || (buffer->ExtendedFrameExchange && rf_ptr->mac_edfe_response_tx_active)) {
|
|
//ACK or EFDE Response
|
|
rf_ptr->mac_ack_tx_active = false;
|
|
// For Ack, stop the active TX process
|
|
rf_ptr->macTxProcessActive = false;
|
|
rf_ptr->mac_edfe_tx_active = false;
|
|
rf_ptr->mac_edfe_response_tx_active = false;
|
|
// If MAC had TX process active before Ack transmission,
|
|
// the TX process has to be restarted in case the Ack transmission failed.
|
|
if (rf_ptr->active_pd_data_request) {
|
|
mac_csma_backoff_start(rf_ptr);
|
|
}
|
|
#ifdef __linux__
|
|
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) {
|
|
tr_debug("Drop ACK by CCA request");
|
|
}
|
|
#endif
|
|
platform_exit_critical();
|
|
return -1;
|
|
}
|
|
mac_csma_backoff_start(rf_ptr);
|
|
}
|
|
} else {
|
|
timer_mac_start(rf_ptr, MAC_TIMER_CCA, (uint16_t)(buffer->tx_time / 50));
|
|
}
|
|
platform_exit_critical();
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
rf_ptr->macTxRequestAck = false;
|
|
|
|
memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
|
|
rf_ptr->mac_cca_retry = 0;
|
|
rf_ptr->mac_tx_retry = 0;
|
|
rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel;
|
|
mac_csma_param_init(rf_ptr);
|
|
if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
|
|
return -1;
|
|
}
|
|
rf_ptr->macTxRequestAck = buffer->WaitResponse;
|
|
if (!rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active) {
|
|
return mcps_pd_data_cca_trig(rf_ptr, buffer);
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
int8_t mcps_edfe_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
rf_ptr->macTxRequestAck = false;
|
|
memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
|
|
rf_ptr->mac_cca_retry = 0;
|
|
rf_ptr->mac_tx_retry = 0;
|
|
rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel;
|
|
buffer->aux_header.frameCounter = 0xffffffff;
|
|
mac_csma_param_init(rf_ptr);
|
|
if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
|
|
return -1;
|
|
}
|
|
rf_ptr->macTxRequestAck = buffer->WaitResponse;//buffer->fcf_dsn.ackRequested;
|
|
|
|
return mcps_pd_data_cca_trig(rf_ptr, buffer);
|
|
|
|
}
|
|
|
|
int8_t mcps_pd_data_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (mcps_generic_packet_rebuild(rf_ptr, buffer) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return mcps_pd_data_cca_trig(rf_ptr, buffer);
|
|
}
|
|
|
|
|
|
bool mac_is_ack_request_set(mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (buffer->fcf_dsn.ackRequested || buffer->WaitResponse) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int mac_convert_frame_type_to_fhss(uint8_t frame_type)
|
|
{
|
|
if (FC_BEACON_FRAME == frame_type) {
|
|
return FHSS_SYNCH_FRAME;
|
|
}
|
|
if (FC_CMD_FRAME == frame_type) {
|
|
return FHSS_SYNCH_REQUEST_FRAME;
|
|
}
|
|
return FHSS_DATA_FRAME;
|
|
}
|
|
|
|
void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (!rf_mac_setup || !buffer) {
|
|
return;
|
|
}
|
|
if (!rf_mac_setup->active_pd_data_request) {
|
|
// Push broadcast buffers to queue when broadcast disabled flag is set
|
|
if ((rf_mac_setup->macBroadcastDisabled == true) && !mac_is_ack_request_set(buffer)) {
|
|
goto push_to_queue;
|
|
}
|
|
|
|
if (buffer->ExtendedFrameExchange) {
|
|
//Update here state and store peer
|
|
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
|
|
}
|
|
if (rf_mac_setup->fhss_api && (buffer->asynch_request == false)) {
|
|
uint16_t frame_length = buffer->mac_payload_length + buffer->headerIeLength + buffer->payloadsIeLength;
|
|
if (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer),
|
|
buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), frame_length,
|
|
rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == false) {
|
|
if (buffer->ExtendedFrameExchange) {
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
|
|
}
|
|
goto push_to_queue;
|
|
}
|
|
}
|
|
//Start TX process immediately
|
|
rf_mac_setup->active_pd_data_request = buffer;
|
|
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
|
|
rf_mac_setup->mac_tx_result = MAC_TX_PRECOND_FAIL;
|
|
rf_mac_setup->macTxRequestAck = false;
|
|
if (buffer->ExtendedFrameExchange) {
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
|
|
}
|
|
if (mcps_sap_pd_confirm(rf_mac_setup) != 0) {
|
|
// can't send event, try calling error handler directly
|
|
rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = buffer->msduHandle;
|
|
rf_mac_setup->mac_mcps_data_conf_fail.status = buffer->status;
|
|
if (buffer->ExtendedFrameExchange) {
|
|
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
|
|
}
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mac_pd_data_confirm_failure_handle(rf_mac_setup);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
push_to_queue:
|
|
rf_mac_setup->direct_queue_bytes += buffer->mac_payload_length;
|
|
mac_pre_build_frame_t *prev = NULL;
|
|
mac_pre_build_frame_t *cur = rf_mac_setup->pd_data_request_queue_to_go;
|
|
bool use_bc_queue = false;
|
|
|
|
// When FHSS is enabled, broadcast buffers are pushed to own queue
|
|
if (rf_mac_setup->fhss_api && (buffer->asynch_request == false)) {
|
|
if (rf_mac_setup->fhss_api->use_broadcast_queue(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer),
|
|
mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) {
|
|
cur = rf_mac_setup->pd_data_request_bc_queue_to_go;
|
|
use_bc_queue = true;
|
|
rf_mac_setup->broadcast_queue_size++;
|
|
}
|
|
}
|
|
if (use_bc_queue == false) {
|
|
rf_mac_setup->unicast_queue_size++;
|
|
}
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_QUEUE, rf_mac_setup->unicast_queue_size + rf_mac_setup->broadcast_queue_size);
|
|
|
|
//Push to queue
|
|
if (!cur) {
|
|
if (rf_mac_setup->fhss_api && (use_bc_queue == true)) {
|
|
rf_mac_setup->pd_data_request_bc_queue_to_go = buffer;
|
|
return;
|
|
} else {
|
|
rf_mac_setup->pd_data_request_queue_to_go = buffer;
|
|
return;
|
|
}
|
|
}
|
|
|
|
while (cur) {
|
|
if (cur->priority < buffer->priority) {
|
|
//Set before cur
|
|
if (prev) {
|
|
prev->next = buffer;
|
|
buffer->next = cur;
|
|
} else {
|
|
buffer->next = cur;
|
|
if (rf_mac_setup->fhss_api && (use_bc_queue == true)) {
|
|
rf_mac_setup->pd_data_request_bc_queue_to_go = buffer;
|
|
} else {
|
|
rf_mac_setup->pd_data_request_queue_to_go = buffer;
|
|
}
|
|
}
|
|
cur = NULL;
|
|
|
|
} else if (cur->next == NULL) {
|
|
cur->next = buffer;
|
|
cur = NULL;
|
|
} else {
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static mac_pre_build_frame_t *mcps_sap_pd_req_queue_read(protocol_interface_rf_mac_setup_s *rf_mac_setup, bool is_bc_queue, bool flush)
|
|
{
|
|
mac_pre_build_frame_t *queue = rf_mac_setup->pd_data_request_queue_to_go;
|
|
if (is_bc_queue == true) {
|
|
queue = rf_mac_setup->pd_data_request_bc_queue_to_go;
|
|
}
|
|
|
|
if (!queue) {
|
|
return NULL;
|
|
}
|
|
|
|
mac_pre_build_frame_t *buffer = queue;
|
|
mac_pre_build_frame_t *prev = NULL;
|
|
// With FHSS, check TX conditions
|
|
if (rf_mac_setup->fhss_api) {
|
|
while (buffer) {
|
|
if (buffer->asynch_request || (flush == true) || (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer),
|
|
buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), buffer->mac_payload_length,
|
|
rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == true)) {
|
|
break;
|
|
}
|
|
prev = buffer;
|
|
buffer = buffer->next;
|
|
}
|
|
}
|
|
// This check is here to prevent (Linux) border router from pushing broadcast frames to RF interface on unicast channel.
|
|
while (buffer) {
|
|
/* Allow returning buffer when:
|
|
* - Flush is enabled
|
|
* - Broadcast not disabled
|
|
* - Broadcast is disabled and buffer has unicast destination
|
|
*/
|
|
if ((flush == true) || (rf_mac_setup->macBroadcastDisabled == false) || ((rf_mac_setup->macBroadcastDisabled == true) && mac_is_ack_request_set(buffer))) {
|
|
break;
|
|
}
|
|
prev = buffer;
|
|
buffer = buffer->next;
|
|
}
|
|
if (!buffer) {
|
|
return NULL;
|
|
}
|
|
// When other than first buffer is read out, link next buffer to previous buffer
|
|
if (prev) {
|
|
prev->next = buffer->next;
|
|
}
|
|
|
|
// When the first buffer is read out, set next buffer as the new first buffer
|
|
if (is_bc_queue == false) {
|
|
if (!prev) {
|
|
rf_mac_setup->pd_data_request_queue_to_go = buffer->next;
|
|
}
|
|
rf_mac_setup->unicast_queue_size--;
|
|
} else {
|
|
if (!prev) {
|
|
rf_mac_setup->pd_data_request_bc_queue_to_go = buffer->next;
|
|
}
|
|
rf_mac_setup->broadcast_queue_size--;
|
|
}
|
|
buffer->next = NULL;
|
|
rf_mac_setup->direct_queue_bytes -= buffer->mac_payload_length;
|
|
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_QUEUE, rf_mac_setup->unicast_queue_size + rf_mac_setup->broadcast_queue_size);
|
|
return buffer;
|
|
}
|
|
|
|
void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf)
|
|
{
|
|
if (!buf) {
|
|
return;
|
|
}
|
|
|
|
if (buf->mac_class_ptr && buf->fcf_dsn.frametype == FC_ACK_FRAME) {
|
|
struct protocol_interface_rf_mac_setup *rf_mac_setup = buf->mac_class_ptr;
|
|
if (rf_mac_setup->rf_pd_ack_buffer_is_in_use) {
|
|
rf_mac_setup->rf_pd_ack_buffer_is_in_use = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
ns_dyn_mem_free(buf);
|
|
}
|
|
|
|
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length)
|
|
{
|
|
mac_pre_parsed_frame_t *buffer = ns_dyn_mem_temporary_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length);
|
|
|
|
if (buffer) {
|
|
memset(buffer, 0, sizeof(mac_pre_parsed_frame_t) + frame_length);
|
|
buffer->frameLength = frame_length;
|
|
memcpy(mac_header_message_start_pointer(buffer), data_ptr, frame_length);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_ack_buffer_get(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t frame_length)
|
|
{
|
|
|
|
if (rf_ptr->rf_pd_ack_buffer_is_in_use) {
|
|
#ifdef __linux__
|
|
tr_debug("mac ACK buffer get fail: already active");
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
if (frame_length > rf_ptr->allocated_ack_buffer_length) {
|
|
//Free Current
|
|
if (rf_ptr->pd_rx_ack_buffer) {
|
|
ns_dyn_mem_free(rf_ptr->pd_rx_ack_buffer);
|
|
rf_ptr->allocated_ack_buffer_length = 0;
|
|
}
|
|
rf_ptr->pd_rx_ack_buffer = ns_dyn_mem_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length);
|
|
if (!rf_ptr->pd_rx_ack_buffer) {
|
|
return NULL;
|
|
}
|
|
rf_ptr->allocated_ack_buffer_length = frame_length;
|
|
}
|
|
memset(rf_ptr->pd_rx_ack_buffer, 0, sizeof(mac_pre_parsed_frame_t) + rf_ptr->allocated_ack_buffer_length);
|
|
rf_ptr->pd_rx_ack_buffer->frameLength = frame_length;
|
|
memcpy(mac_header_message_start_pointer(rf_ptr->pd_rx_ack_buffer), data_ptr, frame_length);
|
|
//Mark active ACK buffer state
|
|
rf_ptr->rf_pd_ack_buffer_is_in_use = true;
|
|
return rf_ptr->pd_rx_ack_buffer;
|
|
}
|
|
|
|
|
|
static void mac_set_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type)
|
|
{
|
|
rf_mac_setup->active_mac_events |= (1 << event_type);
|
|
}
|
|
|
|
static void mac_clear_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type)
|
|
{
|
|
rf_mac_setup->active_mac_events &= ~(1 << event_type);
|
|
}
|
|
|
|
static bool mac_read_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type)
|
|
{
|
|
if (rf_mac_setup->active_mac_events & (1 << event_type)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int8_t mcps_sap_pd_ind(mac_pre_parsed_frame_t *buffer)
|
|
{
|
|
if (mac_tasklet_event_handler < 0 || !buffer) {
|
|
return -1;
|
|
}
|
|
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = buffer,
|
|
.event_type = MCPS_SAP_DATA_IND_EVENT,
|
|
.priority = ARM_LIB_HIGH_PRIORITY_EVENT,
|
|
};
|
|
|
|
return eventOS_event_send(&event);
|
|
}
|
|
|
|
int8_t mcps_sap_pd_confirm(void *mac_ptr)
|
|
{
|
|
if (mac_tasklet_event_handler < 0 || !mac_ptr) {
|
|
return -2;
|
|
}
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = mac_ptr,
|
|
.event_type = MCPS_SAP_DATA_CNF_EVENT,
|
|
.priority = ARM_LIB_HIGH_PRIORITY_EVENT,
|
|
};
|
|
|
|
return eventOS_event_send(&event);
|
|
}
|
|
|
|
int8_t mcps_sap_pd_confirm_failure(void *mac_ptr)
|
|
{
|
|
if (mac_tasklet_event_handler < 0 || !mac_ptr) {
|
|
return -2;
|
|
}
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = mac_ptr,
|
|
.event_type = MCPS_SAP_DATA_CNF_FAIL_EVENT,
|
|
.priority = ARM_LIB_HIGH_PRIORITY_EVENT,
|
|
};
|
|
|
|
return eventOS_event_send(&event);
|
|
}
|
|
|
|
int8_t mcps_sap_pd_ack(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_parsed_frame_t *buffer)
|
|
{
|
|
if (mac_tasklet_event_handler < 0 || !buffer) {
|
|
return -1;
|
|
}
|
|
|
|
if (buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
|
|
arm_event_storage_t *event = &rf_ptr->mac_ack_event;
|
|
event->data.data_ptr = buffer;
|
|
event->data.event_data = 0;
|
|
event->data.event_id = 0;
|
|
event->data.event_type = MCPS_SAP_DATA_ACK_CNF_EVENT;
|
|
event->data.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
|
|
event->data.sender = 0;
|
|
event->data.receiver = mac_tasklet_event_handler;
|
|
eventOS_event_send_user_allocated(event);
|
|
|
|
return 0;
|
|
}
|
|
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = buffer,
|
|
.event_type = MCPS_SAP_DATA_ACK_CNF_EVENT,
|
|
.priority = ARM_LIB_HIGH_PRIORITY_EVENT,
|
|
};
|
|
|
|
return eventOS_event_send(&event);
|
|
}
|
|
|
|
void mcps_sap_trig_tx(void *mac_ptr)
|
|
{
|
|
if (mac_tasklet_event_handler < 0 || !mac_ptr) {
|
|
return;
|
|
}
|
|
if (mac_read_active_event(mac_ptr, MAC_SAP_TRIG_TX) == true) {
|
|
return;
|
|
}
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = mac_ptr,
|
|
.event_type = MAC_SAP_TRIG_TX,
|
|
.priority = ARM_LIB_MED_PRIORITY_EVENT,
|
|
};
|
|
|
|
if (eventOS_event_send(&event) == 0) {
|
|
mac_set_active_event(mac_ptr, MAC_SAP_TRIG_TX);
|
|
}
|
|
}
|
|
|
|
void mac_cca_threshold_event_send(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int16_t dbm)
|
|
{
|
|
// Return if feature is not initialized
|
|
if (!rf_ptr->cca_threshold) {
|
|
return;
|
|
}
|
|
uint16_t data = channel << 8 | (uint8_t) dbm;
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.event_data = data,
|
|
.data_ptr = rf_ptr,
|
|
.event_type = MAC_CCA_THR_UPDATE,
|
|
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
|
|
};
|
|
|
|
eventOS_event_send(&event);
|
|
}
|
|
|
|
void mac_generic_event_trig(uint8_t event_type, void *mac_ptr, bool low_latency)
|
|
{
|
|
arm_library_event_priority_e priority;
|
|
if (low_latency) {
|
|
priority = ARM_LIB_LOW_PRIORITY_EVENT;
|
|
} else {
|
|
priority = ARM_LIB_HIGH_PRIORITY_EVENT;
|
|
}
|
|
arm_event_s event = {
|
|
.receiver = mac_tasklet_event_handler,
|
|
.sender = 0,
|
|
.event_id = 0,
|
|
.data_ptr = mac_ptr,
|
|
.event_type = event_type,
|
|
.priority = priority,
|
|
};
|
|
|
|
eventOS_event_send(&event);
|
|
}
|
|
|
|
void mac_mcps_buffer_queue_free(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
|
|
if (rf_mac_setup->active_pd_data_request) {
|
|
mcps_sap_prebuild_frame_buffer_free(rf_mac_setup->active_pd_data_request);
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
}
|
|
|
|
while (rf_mac_setup->pd_data_request_queue_to_go) {
|
|
mac_pre_build_frame_t *buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, false, true);
|
|
if (buffer) {
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
}
|
|
}
|
|
|
|
while (rf_mac_setup->pd_data_request_bc_queue_to_go) {
|
|
mac_pre_build_frame_t *buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, true, true);
|
|
if (buffer) {
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
}
|
|
}
|
|
|
|
while (rf_mac_setup->indirect_pd_data_request_queue) {
|
|
mac_pre_build_frame_t *buffer = rf_mac_setup->indirect_pd_data_request_queue;
|
|
if (buffer) {
|
|
rf_mac_setup->indirect_pd_data_request_queue = buffer->next;
|
|
mcps_sap_prebuild_frame_buffer_free(buffer);
|
|
}
|
|
}
|
|
|
|
if (rf_mac_setup->pd_rx_ack_buffer) {
|
|
if (rf_mac_setup->rf_pd_ack_buffer_is_in_use) {
|
|
eventOS_cancel(&rf_mac_setup->mac_ack_event);
|
|
rf_mac_setup->rf_pd_ack_buffer_is_in_use = false;
|
|
}
|
|
ns_dyn_mem_free(rf_mac_setup->pd_rx_ack_buffer);
|
|
rf_mac_setup->pd_rx_ack_buffer = NULL;
|
|
rf_mac_setup->allocated_ack_buffer_length = 0;
|
|
}
|
|
|
|
}
|
|
/**
|
|
* Function return list start pointer
|
|
*/
|
|
static mac_pre_build_frame_t *mcps_sap_purge_from_list(mac_pre_build_frame_t *list_ptr_original, uint8_t msduhandle, uint8_t *status)
|
|
{
|
|
mac_pre_build_frame_t *list_prev = NULL;
|
|
mac_pre_build_frame_t *list_ptr = list_ptr_original;
|
|
while (list_ptr) {
|
|
if (list_ptr->fcf_dsn.frametype == MAC_FRAME_DATA && list_ptr->msduHandle == msduhandle) {
|
|
|
|
if (list_prev) {
|
|
list_prev->next = list_ptr->next;
|
|
} else {
|
|
list_ptr_original = list_ptr->next;
|
|
}
|
|
list_ptr->next = NULL;
|
|
|
|
//Free data and buffer
|
|
mcps_sap_prebuild_frame_buffer_free(list_ptr);
|
|
list_ptr = NULL;
|
|
*status = true;
|
|
} else {
|
|
list_prev = list_ptr;
|
|
list_ptr = list_ptr->next;
|
|
}
|
|
}
|
|
return list_ptr_original;
|
|
}
|
|
|
|
|
|
static bool mcps_sap_purge_req_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t msduhandle)
|
|
{
|
|
//Discover from TX queue data packets with given
|
|
uint8_t status = false;
|
|
rf_mac_setup->pd_data_request_queue_to_go = mcps_sap_purge_from_list(rf_mac_setup->pd_data_request_queue_to_go, msduhandle, &status);
|
|
|
|
if (!status) {
|
|
rf_mac_setup->indirect_pd_data_request_queue = mcps_sap_purge_from_list(rf_mac_setup->indirect_pd_data_request_queue, msduhandle, &status);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_purge_t *purge_req)
|
|
{
|
|
mcps_purge_conf_t confirmation;
|
|
confirmation.msduHandle = purge_req->msduHandle;
|
|
|
|
if (mcps_sap_purge_req_from_queue(rf_mac_setup, confirmation.msduHandle)) {
|
|
confirmation.status = MLME_SUCCESS;
|
|
} else {
|
|
confirmation.status = MLME_INVALID_HANDLE;
|
|
}
|
|
|
|
if (get_sw_mac_api(rf_mac_setup)) {
|
|
get_sw_mac_api(rf_mac_setup)->purge_conf_cb(get_sw_mac_api(rf_mac_setup), &confirmation);
|
|
}
|
|
|
|
return confirmation.status;
|
|
}
|
|
|
|
void mcps_pending_packet_counter_update_check(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
|
|
{
|
|
if (buffer->fcf_dsn.securityEnabled) {
|
|
mlme_key_descriptor_t *key_desc = mac_frame_security_key_get(rf_mac_setup, buffer);
|
|
if (key_desc) {
|
|
uint32_t current_counter = mac_sec_mib_key_outgoing_frame_counter_get(rf_mac_setup, key_desc);
|
|
if (mac_data_counter_too_small(current_counter, buffer->aux_header.frameCounter)) {
|
|
buffer->aux_header.frameCounter = current_counter;
|
|
mac_sec_mib_key_outgoing_frame_counter_increment(rf_mac_setup, key_desc);
|
|
}
|
|
}
|
|
}
|
|
}
|