mirror of https://github.com/ARMmbed/mbed-os.git
1827 lines
64 KiB
C
1827 lines
64 KiB
C
/*
|
|
* Copyright (c) 2013-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_mlme.c
|
|
* \brief MLME API for MAC control
|
|
*
|
|
* MLME API for MAC certification.
|
|
*
|
|
*/
|
|
|
|
#include "nsconfig.h"
|
|
#include <string.h>
|
|
#include "ns_types.h"
|
|
#include "eventOS_event.h"
|
|
#include "eventOS_scheduler.h"
|
|
#include "eventOS_callback_timer.h"
|
|
#include "ns_trace.h"
|
|
#include "randLIB.h"
|
|
#include "nsdynmemLIB.h"
|
|
#include "platform/arm_hal_interrupt.h"
|
|
#include "common_functions.h"
|
|
#include "sw_mac.h"
|
|
#include "mlme.h"
|
|
#include "mac_api.h"
|
|
#include "fhss_api.h"
|
|
|
|
#include "MAC/IEEE802_15_4/sw_mac_internal.h"
|
|
#include "MAC/IEEE802_15_4/mac_defines.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_security_mib.h"
|
|
#include "MAC/IEEE802_15_4/mac_mlme.h"
|
|
#include "MAC/IEEE802_15_4/mac_timer.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_cca_threshold.h"
|
|
#include "MAC/virtual_rf/virtual_rf_defines.h"
|
|
#include "MAC/rf_driver_storage.h"
|
|
|
|
#define TRACE_GROUP "mlme"
|
|
|
|
#define MAC_ACK_WAIT_DURATION 90
|
|
|
|
static int8_t mac_mlme_rf_disable(struct protocol_interface_rf_mac_setup *rf_mac_setup);
|
|
static int8_t mac_mlme_rf_receiver_enable(struct protocol_interface_rf_mac_setup *rf_mac_setup);
|
|
|
|
static void mac_mlme_write_mac16(protocol_interface_rf_mac_setup_s *rf_setup, uint8_t *addrPtr);
|
|
static void mac_mlme_write_mac64(struct protocol_interface_rf_mac_setup *rf_setup, uint8_t *addrPtr);
|
|
static void mac_mlme_timers_disable(protocol_interface_rf_mac_setup_s *rf_ptr);
|
|
static void mac_mlme_free_scan_temporary_data(protocol_interface_rf_mac_setup_s *rf_mac_setup);
|
|
static int8_t mac_mlme_set_panid(struct protocol_interface_rf_mac_setup *rf_setup, uint16_t pan_id);
|
|
static int8_t mac_mlme_set_mac16(struct protocol_interface_rf_mac_setup *rf_setup, uint16_t mac16);
|
|
static int8_t mac_mlme_rf_channel_set(struct protocol_interface_rf_mac_setup *rf_setup, uint8_t new_channel);
|
|
static void mac_mlme_timer_cb(int8_t timer_id, uint16_t slots);
|
|
static void mac_mlme_start_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_start_conf_t *conf);
|
|
static void mac_mlme_scan_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_scan_conf_t *conf);
|
|
static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_setup);
|
|
static int mac_mlme_allocate_tx_buffers(protocol_interface_rf_mac_setup_s *rf_mac_setup, arm_device_driver_list_s *dev_driver, uint16_t mtu_size);
|
|
|
|
static void mac_mlme_energy_scan_start(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t channel)
|
|
{
|
|
phy_device_driver_s *dev_driver = rf_mac_setup->dev_driver->phy_driver;
|
|
rf_mac_setup->mac_channel = channel;
|
|
if (rf_mac_setup->macRfRadioOn) {
|
|
if (dev_driver->state_control) {
|
|
dev_driver->state_control(PHY_INTERFACE_DOWN, 0);
|
|
}
|
|
}
|
|
if (dev_driver->state_control) {
|
|
dev_driver->state_control(PHY_INTERFACE_RX_ENERGY_STATE, channel);
|
|
}
|
|
rf_mac_setup->macRfRadioOn = true;
|
|
rf_mac_setup->macRfRadioTxActive = false;
|
|
}
|
|
|
|
uint16_t mlme_scan_analyze_next_channel(channel_list_s *mac_channel_list, bool clear_channel)
|
|
{
|
|
uint8_t i, j = 0, k = 1;
|
|
uint32_t mask = 1;
|
|
uint32_t *channel_mask = mac_channel_list->channel_mask;
|
|
|
|
if (mac_channel_list->channel_page == CHANNEL_PAGE_9 ||
|
|
mac_channel_list->channel_page == CHANNEL_PAGE_10) {
|
|
k = 8;
|
|
}
|
|
for (j = 0; j < k; j++) {
|
|
for (i = 0; i < 32; i++) {
|
|
if (*channel_mask & mask) {
|
|
if (clear_channel) {
|
|
*channel_mask &= ~mask;
|
|
}
|
|
return (i + j * 32);
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
mask = 1;
|
|
channel_mask++;
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
static uint32_t mac_mlme_channel_symbol_rate(uint8_t channel_page, uint8_t channel)
|
|
{
|
|
|
|
uint32_t symbol_rate;
|
|
|
|
// Gets symbol rate for channel
|
|
switch (channel_page) {
|
|
case CHANNEL_PAGE_0:
|
|
// 868 Mhz BPSK
|
|
if (channel == 0) {
|
|
symbol_rate = 20000;
|
|
// 915 Mhz BPSK
|
|
} else if (channel >= 1 && channel <= 10) {
|
|
symbol_rate = 40000;
|
|
// 2450 Mhz O-QPSK
|
|
} else {
|
|
symbol_rate = 62500;
|
|
}
|
|
break;
|
|
case CHANNEL_PAGE_1:
|
|
// 868 MHz ASK
|
|
if (channel == 0) {
|
|
symbol_rate = 12500;
|
|
// 915 MHz ASK
|
|
} else {
|
|
symbol_rate = 50000;
|
|
}
|
|
break;
|
|
case CHANNEL_PAGE_2:
|
|
// 868 MHz O-QPSK
|
|
if (channel == 0) {
|
|
symbol_rate = 25000;
|
|
// 915 MHz O-QPSK
|
|
} else {
|
|
symbol_rate = 62500;
|
|
}
|
|
break;
|
|
case CHANNEL_PAGE_3:
|
|
// 2450 CSS
|
|
symbol_rate = 167000;
|
|
break;
|
|
case CHANNEL_PAGE_6:
|
|
// 950 MHz BPSK
|
|
if (channel <= 9) {
|
|
symbol_rate = 20000;
|
|
// 950 MHz GFSK
|
|
} else {
|
|
symbol_rate = 100000;
|
|
}
|
|
break;
|
|
default:
|
|
symbol_rate = 62500;
|
|
break;
|
|
}
|
|
|
|
return symbol_rate;
|
|
}
|
|
|
|
static void mac_mlme_calc_scan_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t channel)
|
|
{
|
|
rf_mac_setup->mlme_ED_counter = 1;
|
|
|
|
if (rf_mac_setup->scan_duration) {
|
|
rf_mac_setup->mlme_ED_counter <<= rf_mac_setup->scan_duration;
|
|
}
|
|
|
|
rf_mac_setup->mlme_ED_counter++;
|
|
|
|
if (rf_mac_setup->scan_type == MAC_ED_SCAN_TYPE) {
|
|
// Gets symbol rate for channel that is scanned
|
|
uint32_t symbol_rate = mac_mlme_channel_symbol_rate(
|
|
rf_mac_setup->mac_channel_list.channel_page, channel);
|
|
|
|
// Energy scan duration is aBaseSuperframeDuration * (2^n + 1)
|
|
// aBaseSuperframeDuration is 960 symbols e.g for 2.4Ghz O-QPSK with 62.5 ksymbols/s -> 15,36ms.
|
|
// ED scan timer timeout is 4.8ms
|
|
uint16_t frame_duration = (uint32_t) 960 * 100000 / symbol_rate;
|
|
rf_mac_setup->mlme_ED_counter = (uint32_t) rf_mac_setup->mlme_ED_counter * frame_duration / 480;
|
|
}
|
|
}
|
|
|
|
static void mac_mlme_start_request(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mac_pre_build_frame_t *buf;
|
|
platform_enter_critical();
|
|
|
|
mac_mlme_rf_disable(rf_mac_setup);
|
|
buf = rf_mac_setup->active_pd_data_request;
|
|
rf_mac_setup->active_pd_data_request = NULL;
|
|
mac_mlme_mac_radio_enable(rf_mac_setup);
|
|
rf_mac_setup->macUpState = true;
|
|
if (buf) {
|
|
// Active packet is pushed back to queue and statistics will be cleared. They need to be updated here.
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_ATT, rf_mac_setup->mac_tx_status.cca_cnt);
|
|
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_RETRY, rf_mac_setup->mac_tx_status.retry);
|
|
mcps_sap_pd_req_queue_write(rf_mac_setup, buf);
|
|
}
|
|
platform_exit_critical();
|
|
}
|
|
|
|
uint8_t mac_mlme_beacon_req_tx(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
|
|
mac_pre_build_frame_t *buf = mcps_sap_prebuild_frame_buffer_get(0);
|
|
|
|
if (buf) {
|
|
buf->fcf_dsn.DstAddrMode = MAC_ADDR_MODE_16_BIT;
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_NONE;
|
|
buf->fcf_dsn.frametype = FC_CMD_FRAME;
|
|
buf->DstPANId = 0xffff;
|
|
buf->DstAddr[0] = 0xff;
|
|
buf->DstAddr[1] = 0xff;
|
|
buf->mac_command_id = MAC_BEACON_REQ;
|
|
buf->mac_header_length_with_security = 7;
|
|
buf->mac_payload = &buf->mac_command_id;
|
|
buf->mac_payload_length = 1;
|
|
buf->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
|
|
buf->fcf_dsn.DstPanPresents = true;
|
|
buf->fcf_dsn.SrcPanPresents = false;
|
|
|
|
mcps_sap_pd_req_queue_write(rf_ptr, buf);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mac_mlme_scan_init(uint8_t channel, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
mac_mlme_calc_scan_duration(rf_mac_setup, channel);
|
|
|
|
switch (rf_mac_setup->scan_type) {
|
|
/* ED Scan */
|
|
case MAC_ED_SCAN_TYPE:
|
|
//tr_debug("Energy Scan");
|
|
rf_mac_setup->max_ED = 0;
|
|
mac_mlme_energy_scan_start(rf_mac_setup, channel);
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_ED_ANALYZE;
|
|
eventOS_callback_timer_start(rf_mac_setup->mlme_timer_id, 96);
|
|
break;
|
|
case MAC_PASSIVE_SCAN:
|
|
case MAC_ACTIVE_SCAN: /*Active*/
|
|
tr_debug("Scan channel %u", channel);
|
|
rf_mac_setup->mac_channel = channel;
|
|
rf_mac_setup->macCapRxOnIdle = true;
|
|
mac_mlme_start_request(rf_mac_setup);
|
|
if (rf_mac_setup->scan_type == MAC_ACTIVE_SCAN) {
|
|
mac_pre_build_frame_t *active_buf = rf_mac_setup->active_pd_data_request;
|
|
/* If there is active data request, it must be Beacon request which were failed to send on previous channel.
|
|
* Do not push new Beacon request to queue as the MAC will try to send the current active data request anyway.
|
|
*/
|
|
if (!active_buf || (active_buf && active_buf->fcf_dsn.frametype != FC_CMD_FRAME)) {
|
|
mac_mlme_beacon_req_tx(rf_mac_setup);
|
|
}
|
|
}
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_SCAN;
|
|
rf_mac_setup->mlme_tick_count = rf_mac_setup->mlme_ED_counter;
|
|
//tr_debug("mlme_tick_count: %x", rf_mac_setup->mlme_tick_count);
|
|
eventOS_callback_timer_start(rf_mac_setup->mlme_timer_id, 300);
|
|
break;
|
|
case MAC_ORPHAN_SCAN: /*Orphan*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void mac_mlme_scan_start(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
uint8_t channel;
|
|
|
|
channel = (uint8_t) mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list, true);
|
|
mac_mlme_scan_init(channel, rf_mac_setup);
|
|
}
|
|
|
|
static bool mac_channel_list_validate(const channel_list_s *list, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (rf_mac_setup->dev_driver->phy_driver->link_type == PHY_LINK_15_4_2_4GHZ_TYPE &&
|
|
list->channel_page == 0) {
|
|
//Accept only Channels channels 11-26
|
|
if (list->channel_mask[0] & 0x7fff800) {
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (rf_mac_setup->dev_driver->phy_driver->link_type == PHY_LINK_15_4_SUBGHZ_TYPE &&
|
|
(list->channel_page == 0 || list->channel_page == 1 || list->channel_page == 2)) {
|
|
if (list->channel_mask[0] & 0x000007ff) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} else {
|
|
for (int i = 0; i < 8; i++) {
|
|
if (list->channel_mask[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int mac_mlme_generate_scan_confirmation(mlme_scan_conf_t *conf, const mlme_scan_t *msg, uint8_t status)
|
|
{
|
|
memset(conf, 0, sizeof(mlme_scan_conf_t));
|
|
conf->status = status;
|
|
if (!msg) {
|
|
return -1;
|
|
}
|
|
conf->ScanType = msg->ScanType;
|
|
conf->ChannelPage = msg->ChannelPage;
|
|
if (msg->ScanType == MAC_ACTIVE_SCAN) {
|
|
/*If the scan is successful, this value will be modified properly in mlme_analyze_next_channel()
|
|
and assigned in mlme_scan_operation()*/
|
|
conf->UnscannedChannels.channel_mask[0] = msg->ScanChannels.channel_mask[0];
|
|
} else if (msg->ScanType == MAC_ED_SCAN_TYPE) {
|
|
conf->ED_values = ns_dyn_mem_temporary_alloc(MLME_MAC_RES_SIZE_MAX);
|
|
if (!conf->ED_values) {
|
|
tr_debug("Could not allocate memory for ED values");
|
|
conf->status = MLME_SUCCESS;
|
|
return -2;
|
|
}
|
|
memset(conf->ED_values, 0, MLME_MAC_RES_SIZE_MAX);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mac_mlme_scan_request(const mlme_scan_t *msg, protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (rf_mac_setup->mac_mlme_scan_resp) {
|
|
mlme_scan_conf_t conf;
|
|
mac_mlme_generate_scan_confirmation(&conf, msg, MLME_SCAN_IN_PROGRESS);
|
|
mac_mlme_scan_confirm_handler(rf_mac_setup, &conf);
|
|
ns_dyn_mem_free(conf.ED_values);
|
|
return;
|
|
}
|
|
|
|
mlme_scan_conf_t *resp = ns_dyn_mem_temporary_alloc(sizeof(mlme_scan_conf_t));
|
|
if (!resp) {
|
|
mlme_scan_conf_t conf;
|
|
tr_error("Mac Scan request fail, no memory");
|
|
mac_mlme_generate_scan_confirmation(&conf, NULL, MLME_SUCCESS);
|
|
mac_mlme_scan_confirm_handler(rf_mac_setup, &conf);
|
|
ns_dyn_mem_free(conf.ED_values);
|
|
return;
|
|
}
|
|
|
|
rf_mac_setup->mac_mlme_scan_resp = resp;
|
|
//Validate channel list
|
|
tr_debug("chan page %u, mask %"PRIx32, msg->ScanChannels.channel_page, msg->ScanChannels.channel_mask[0]);
|
|
if (!mac_channel_list_validate(&msg->ScanChannels, rf_mac_setup)) {
|
|
tr_debug("Unsupported channel list");
|
|
mac_mlme_generate_scan_confirmation(resp, msg, MLME_INVALID_PARAMETER);
|
|
mac_generic_event_trig(MAC_MLME_SCAN_CONFIRM_HANDLER, rf_mac_setup, false);
|
|
return;
|
|
}
|
|
|
|
if (mac_mlme_generate_scan_confirmation(resp, msg, MLME_SUCCESS) != 0) {
|
|
return;
|
|
}
|
|
|
|
tr_debug("MAC: Start MLME scan");
|
|
|
|
if (mac_mlme_rf_disable(rf_mac_setup) == 0) {
|
|
rf_mac_setup->macCapRxOnIdle = false;
|
|
if (msg->ScanType == MAC_ACTIVE_SCAN) {
|
|
rf_mac_setup->macUpState = true;
|
|
}
|
|
} else {
|
|
tr_error("Failed to disable RF");
|
|
mac_generic_event_trig(MAC_MLME_SCAN_CONFIRM_HANDLER, rf_mac_setup, false);
|
|
return;
|
|
}
|
|
|
|
rf_mac_setup->scan_type = msg->ScanType;
|
|
rf_mac_setup->scan_duration = msg->ScanDuration;
|
|
rf_mac_setup->mac_channel_list = msg->ScanChannels;
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_SCAN;
|
|
rf_mac_setup->scan_active = true;
|
|
mac_mlme_scan_start(rf_mac_setup);
|
|
}
|
|
|
|
int8_t mac_mlme_start_req(const mlme_start_t *s, struct protocol_interface_rf_mac_setup *rf_mac_setup)
|
|
{
|
|
if (!s || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return -1;
|
|
}
|
|
|
|
tr_debug("MAC: Start network %u channel %x panid", s->LogicalChannel, s->PANId);
|
|
mac_mlme_set_panid(rf_mac_setup, s->PANId);
|
|
|
|
// Synchronize FHSS
|
|
if (rf_mac_setup->fhss_api) {
|
|
rf_mac_setup->mac_channel = rf_mac_setup->fhss_api->synch_state_set(rf_mac_setup->fhss_api, FHSS_SYNCHRONIZED, s->PANId);
|
|
} else {
|
|
rf_mac_setup->mac_channel = s->LogicalChannel;
|
|
}
|
|
|
|
mac_mlme_start_request(rf_mac_setup);
|
|
if (s->PANCoordinator) {
|
|
//tr_debug("Cordinator");
|
|
rf_mac_setup->macCapCordinator = true;
|
|
rf_mac_setup->macCapRxOnIdle = true;
|
|
} else {
|
|
rf_mac_setup->macCapCordinator = false;
|
|
}
|
|
|
|
if (s->BatteryLifeExtension) {
|
|
rf_mac_setup->macCapBatteryPowered = true;
|
|
} else {
|
|
rf_mac_setup->macCapBatteryPowered = false;
|
|
}
|
|
mlme_start_conf_t conf;
|
|
conf.status = MLME_SUCCESS;
|
|
mac_mlme_start_confirm_handler(rf_mac_setup, &conf);
|
|
return 0;
|
|
}
|
|
|
|
int8_t mac_mlme_reset(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_reset_t *reset)
|
|
{
|
|
if (!reset || !rf_mac_setup) {
|
|
return -1;
|
|
}
|
|
|
|
// Stop FHSS
|
|
if (rf_mac_setup->fhss_api) {
|
|
rf_mac_setup->fhss_api->synch_state_set(rf_mac_setup->fhss_api, FHSS_UNSYNCHRONIZED, 0);
|
|
}
|
|
|
|
mac_mlme_timers_disable(rf_mac_setup);
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
mac_mlme_set_active_state(rf_mac_setup, false);
|
|
mac_mlme_free_scan_temporary_data(rf_mac_setup);
|
|
mac_mcps_buffer_queue_free(rf_mac_setup);
|
|
rf_mac_setup->macProminousMode = false;
|
|
rf_mac_setup->macWaitingData = false;
|
|
rf_mac_setup->macDataPollReq = false;
|
|
rf_mac_setup->macRxDataAtPoll = false;
|
|
//Clean MAC
|
|
if (reset->SetDefaultPIB) {
|
|
tr_debug("RESET MAC PIB");
|
|
rf_mac_setup->mac_short_address = 0xffff;
|
|
rf_mac_setup->pan_id = 0xffff;
|
|
rf_mac_setup->macCapRxOnIdle = true;
|
|
rf_mac_setup->mac_security_enabled = false;
|
|
rf_mac_setup->macCapCordinator = false;
|
|
rf_mac_setup->mac_mlme_retry_max = MAC_DEFAULT_MAX_FRAME_RETRIES;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int8_t mac_mlme_boolean_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, bool value)
|
|
{
|
|
switch (attribute) {
|
|
case macSecurityEnabled:
|
|
rf_mac_setup->mac_security_enabled = value;
|
|
break;
|
|
|
|
case macRxOnWhenIdle:
|
|
rf_mac_setup->macCapRxOnIdle = value;
|
|
break;
|
|
|
|
case macPromiscuousMode:
|
|
rf_mac_setup->macProminousMode = value;
|
|
break;
|
|
|
|
case macGTSPermit:
|
|
rf_mac_setup->macGTSPermit = value;
|
|
break;
|
|
|
|
case macAssociationPermit:
|
|
rf_mac_setup->macCapAssocationPermit = value;
|
|
break;
|
|
case macThreadForceLongAddressForBeacon:
|
|
rf_mac_setup->beaconSrcAddressModeLong = value;
|
|
break;
|
|
|
|
case macAssociatedPANCoord:
|
|
|
|
break;
|
|
|
|
case macTimestampSupported:
|
|
|
|
break;
|
|
|
|
case macBattLifeExt:
|
|
|
|
break;
|
|
|
|
case macAutoRequest:
|
|
|
|
break;
|
|
|
|
case macLoadBalancingAcceptAnyBeacon:
|
|
rf_mac_setup->macAcceptAnyBeacon = value;
|
|
if (rf_mac_setup->dev_driver->phy_driver->extension) {
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_ACCEPT_ANY_BEACON, (uint8_t *)&value);
|
|
}
|
|
break;
|
|
|
|
case macEdfeForceStop:
|
|
return mac_data_edfe_force_stop(rf_mac_setup);
|
|
|
|
case macAcceptByPassUnknowDevice:
|
|
rf_mac_setup->mac_security_bypass_unknow_device = value;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_16bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, uint16_t value)
|
|
{
|
|
switch (attribute) {
|
|
case macCoordShortAddress:
|
|
rf_mac_setup->coord_short_address = value;
|
|
break;
|
|
case macPANId:
|
|
mac_mlme_set_panid(rf_mac_setup, value);
|
|
break;
|
|
|
|
case macShortAddress:
|
|
mac_mlme_set_mac16(rf_mac_setup, value);
|
|
break;
|
|
|
|
case macSyncSymbolOffset:
|
|
//TODO: change this to return real error
|
|
//This is read only
|
|
break;
|
|
|
|
case macTransactionPersistenceTime:
|
|
//TODO: check this also
|
|
break;
|
|
case macDeviceDescriptionPanIDUpdate:
|
|
mac_sec_mib_device_description_pan_update(rf_mac_setup, value);
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_8bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, uint8_t value)
|
|
{
|
|
switch (attribute) {
|
|
case phyCurrentChannel:
|
|
mac_mlme_rf_channel_set(rf_mac_setup, value);
|
|
break;
|
|
case macBeaconPayloadLength:
|
|
if (rf_mac_setup->max_beacon_payload_length < value) {
|
|
return -1;
|
|
}
|
|
|
|
rf_mac_setup->mac_beacon_payload_size = value;
|
|
break;
|
|
case macAutoRequestKeyIndex:
|
|
rf_mac_setup->mac_auto_request.KeyIndex = value;
|
|
break;
|
|
|
|
case macAutoRequestKeyIdMode:
|
|
rf_mac_setup->mac_auto_request.KeyIdMode = value;
|
|
break;
|
|
|
|
case macAutoRequestSecurityLevel:
|
|
rf_mac_setup->mac_auto_request.SecurityLevel = value;
|
|
break;
|
|
case macMaxFrameRetries:
|
|
if (value > 7) {
|
|
return -1;
|
|
}
|
|
rf_mac_setup->mac_mlme_retry_max = value;
|
|
break;
|
|
|
|
case macMinBE:
|
|
if (value < rf_mac_setup->macMaxBE) {
|
|
rf_mac_setup->macMinBE = value;
|
|
}
|
|
break;
|
|
|
|
case macMaxBE:
|
|
if (value > 8 || value < 3) {
|
|
return -1;
|
|
}
|
|
rf_mac_setup->macMaxBE = value;
|
|
break;
|
|
|
|
case macMaxCSMABackoffs:
|
|
if (value > 8) {
|
|
return -1;
|
|
}
|
|
rf_mac_setup->macMaxCSMABackoffs = value;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_32bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, uint8_t index, uint32_t value)
|
|
{
|
|
|
|
switch (attribute) {
|
|
case macFrameCounter:
|
|
if (rf_mac_setup->secFrameCounterPerKey) {
|
|
mlme_key_descriptor_t *key_desc = mac_sec_key_description_get_by_attribute(rf_mac_setup, index);
|
|
if (!key_desc) {
|
|
return -1;
|
|
}
|
|
mac_sec_mib_key_outgoing_frame_counter_set(rf_mac_setup, key_desc, value);
|
|
} else {
|
|
mac_sec_mib_key_outgoing_frame_counter_set(rf_mac_setup, NULL, value);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mac_extended_mac_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *mac64)
|
|
{
|
|
if (!mac64 || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
phy_device_driver_s *dev_driver = rf_mac_setup->dev_driver->phy_driver;
|
|
memcpy(rf_mac_setup->mac64, mac64, 8); //This should be random
|
|
if (dev_driver->address_write) {
|
|
dev_driver->address_write(PHY_MAC_64BIT, rf_mac_setup->mac64);
|
|
}
|
|
}
|
|
|
|
static uint32_t mac_calc_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t symbols)
|
|
{
|
|
uint32_t AckWaitDuration = 0;
|
|
if (rf_mac_setup->rf_csma_extension_supported) {
|
|
AckWaitDuration = symbols * rf_mac_setup->symbol_time_us;
|
|
}
|
|
return AckWaitDuration;
|
|
}
|
|
|
|
static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
uint16_t symbols = common_read_16_bit_inverse((uint8_t *)set_req->value_pointer);
|
|
uint32_t ack_wait_time_us = mac_calc_ack_wait_duration(rf_mac_setup, symbols);
|
|
if (ack_wait_time_us < 50) {
|
|
return -1;
|
|
}
|
|
// MAC timer uses 50us resolution
|
|
rf_mac_setup->mac_ack_wait_duration = ack_wait_time_us / 50;
|
|
tr_debug("Set macAckWaitDuration: %uus", rf_mac_setup->mac_ack_wait_duration * 50);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
|
|
if (set_req->value_size != sizeof(mlme_device_descriptor_t)) {
|
|
return -1;
|
|
}
|
|
return mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup);
|
|
}
|
|
|
|
static int8_t mac_mlme_key_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
if (set_req->value_size != sizeof(mlme_key_descriptor_entry_t)) {
|
|
return -1;
|
|
}
|
|
|
|
return mac_sec_mib_key_description_set(set_req->attr_index, (mlme_key_descriptor_entry_t *) set_req->value_pointer, rf_mac_setup);
|
|
}
|
|
|
|
static int8_t mac_mlme_default_key_source_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
if (set_req->value_size != 8) {
|
|
return -1;
|
|
}
|
|
if (set_req->attr == macDefaultKeySource) {
|
|
memcpy(rf_mac_setup->mac_default_key_source, (uint8_t *)set_req->value_pointer, 8);
|
|
} else {
|
|
memcpy(rf_mac_setup->mac_auto_request.Keysource, (uint8_t *)set_req->value_pointer, 8);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_beacon_payload_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
if (set_req->value_size > rf_mac_setup->max_beacon_payload_length) {
|
|
return -1;
|
|
}
|
|
|
|
memcpy(rf_mac_setup->mac_beacon_payload, set_req->value_pointer, set_req->value_size);
|
|
memset(rf_mac_setup->mac_beacon_payload + set_req->value_size, 0, rf_mac_setup->max_beacon_payload_length - set_req->value_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int8_t mac_mlme_handle_set_values(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
if (set_req->value_size == 1) {
|
|
const bool *pbool = set_req->value_pointer;
|
|
//Check first boolean
|
|
if (mac_mlme_boolean_set(rf_mac_setup, set_req->attr, *pbool) == 0) {
|
|
return 0;
|
|
}
|
|
const uint8_t *pu8 = set_req->value_pointer;
|
|
return mac_mlme_8bit_set(rf_mac_setup, set_req->attr, *pu8);
|
|
|
|
} else if (set_req->value_size == 2) {
|
|
const uint16_t *pu16 = set_req->value_pointer;
|
|
return mac_mlme_16bit_set(rf_mac_setup, set_req->attr, *pu16);
|
|
} else if (set_req->value_size == 4) {
|
|
const uint32_t *pu32 = set_req->value_pointer;
|
|
return mac_mlme_32bit_set(rf_mac_setup, set_req->attr, set_req->attr_index, *pu32);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int8_t mac_mlme_set_multi_csma_parameters(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
mlme_multi_csma_ca_param_t multi_csma_params;
|
|
memcpy(&multi_csma_params, set_req->value_pointer, sizeof(mlme_multi_csma_ca_param_t));
|
|
rf_mac_setup->multi_cca_interval = multi_csma_params.multi_cca_interval;
|
|
rf_mac_setup->number_of_csma_ca_periods = multi_csma_params.number_of_csma_ca_periods;
|
|
tr_debug("Multi CSMA-CA, interval: %u, periods %u", rf_mac_setup->multi_cca_interval, rf_mac_setup->number_of_csma_ca_periods);
|
|
return 0;
|
|
}
|
|
|
|
int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
|
{
|
|
if (!set_req || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return -1;
|
|
}
|
|
uint8_t *pu8 = NULL;
|
|
switch (set_req->attr) {
|
|
case macAckWaitDuration:
|
|
return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req);
|
|
case macDeviceTable:
|
|
return mac_mlme_device_description_set(rf_mac_setup, set_req);
|
|
case macKeyTable:
|
|
return mac_mlme_key_description_set(rf_mac_setup, set_req);
|
|
case macDefaultKeySource:
|
|
case macAutoRequestKeySource:
|
|
return mac_mlme_default_key_source_set(rf_mac_setup, set_req);
|
|
case macBeaconPayload:
|
|
return mac_mlme_beacon_payload_set(rf_mac_setup, set_req);
|
|
case macLoadBalancingBeaconTx:
|
|
return mac_mlme_beacon_tx(rf_mac_setup);
|
|
case macCoordExtendedAddress:
|
|
if (set_req->value_size == 8) {
|
|
memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8);
|
|
}
|
|
return 0;
|
|
case macSetDataWhitening:
|
|
pu8 = (uint8_t *) set_req->value_pointer;
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_DATA_WHITENING, pu8);
|
|
tr_debug("%s data whitening", *pu8 == (bool) true ? "Enable" : "Disable");
|
|
return 0;
|
|
case macCCAThresholdStart:
|
|
pu8 = (uint8_t *) set_req->value_pointer;
|
|
mac_cca_thr_init(rf_mac_setup, *pu8, *((int8_t *)pu8 + 1), *((int8_t *)pu8 + 2), *((int8_t *)pu8 + 3));
|
|
return 0;
|
|
case mac802_15_4Mode:
|
|
pu8 = (uint8_t *) set_req->value_pointer;
|
|
if (rf_mac_setup->current_mac_mode == *pu8) {
|
|
return -1;
|
|
}
|
|
rf_mac_setup->current_mac_mode = *pu8;
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_802_15_4_MODE, pu8);
|
|
uint16_t new_mtu_size = MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE;
|
|
if (*pu8 == IEEE_802_15_4G_2012) {
|
|
new_mtu_size = MAC_IEEE_802_15_4G_MAX_PHY_PACKET_SIZE;
|
|
}
|
|
mac_api_t *mac_api = get_sw_mac_api(rf_mac_setup);
|
|
if (rf_mac_setup->dev_driver->phy_driver->phy_MTU > new_mtu_size) {
|
|
mac_api->phyMTU = rf_mac_setup->phy_mtu_size = new_mtu_size;
|
|
} else {
|
|
mac_api->phyMTU = rf_mac_setup->phy_mtu_size = rf_mac_setup->dev_driver->phy_driver->phy_MTU;
|
|
}
|
|
if (mac_mlme_allocate_tx_buffers(rf_mac_setup, rf_mac_setup->dev_driver, rf_mac_setup->phy_mtu_size)) {
|
|
tr_err("Failed to reallocate TX buffers");
|
|
return -1;
|
|
}
|
|
tr_debug("Set MAC mode to %s, MTU size: %u", *pu8 == IEEE_802_15_4G_2012 ? "IEEE 802.15.4G-2012" : "IEEE 802.15.4-2011", rf_mac_setup->phy_mtu_size);
|
|
return 0;
|
|
case macTXPower:
|
|
pu8 = (uint8_t *) set_req->value_pointer;
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_TX_POWER, pu8);
|
|
tr_debug("Set TX output power to %u%%", *pu8);
|
|
return 0;
|
|
case macCCAThreshold:
|
|
pu8 = (uint8_t *) set_req->value_pointer;
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CCA_THRESHOLD, pu8);
|
|
tr_debug("Set CCA threshold to %u%%", *pu8);
|
|
return 0;
|
|
case macMultiCSMAParameters:
|
|
return mac_mlme_set_multi_csma_parameters(rf_mac_setup, set_req);
|
|
case macRfConfiguration:
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) set_req->value_pointer);
|
|
mac_mlme_set_symbol_rate(rf_mac_setup);
|
|
phy_rf_channel_configuration_s *config_params = (phy_rf_channel_configuration_s *)set_req->value_pointer;
|
|
rf_mac_setup->datarate = config_params->datarate;
|
|
tr_info("RF config update:");
|
|
tr_info("Frequency(ch0): %"PRIu32"Hz", config_params->channel_0_center_frequency);
|
|
tr_info("Channel spacing: %"PRIu32"Hz", config_params->channel_spacing);
|
|
tr_info("Datarate: %"PRIu32"bps", config_params->datarate);
|
|
tr_info("Number of channels: %u", config_params->number_of_channels);
|
|
tr_info("Modulation: %u", config_params->modulation);
|
|
tr_info("Modulation index: %u", config_params->modulation_index);
|
|
return 0;
|
|
default:
|
|
return mac_mlme_handle_set_values(rf_mac_setup, set_req);
|
|
}
|
|
}
|
|
|
|
int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_get_conf_t *get_req)
|
|
{
|
|
if (!get_req || !rf_mac_setup) {
|
|
return -1;
|
|
}
|
|
mac_cca_threshold_s *cca_thr_table = NULL;
|
|
switch (get_req->attr) {
|
|
case macDeviceTable:
|
|
get_req->value_pointer = mac_sec_mib_device_description_get_attribute_index(rf_mac_setup, get_req->attr_index);
|
|
if (get_req->value_pointer) {
|
|
get_req->value_size = sizeof(mlme_device_descriptor_t);
|
|
} else {
|
|
get_req->status = MLME_INVALID_INDEX;
|
|
}
|
|
break;
|
|
|
|
case macMaxFrameRetries:
|
|
get_req->value_pointer = &rf_mac_setup->mac_mlme_retry_max;
|
|
get_req->value_size = 1;
|
|
break;
|
|
|
|
case macFrameCounter:
|
|
if (rf_mac_setup->secFrameCounterPerKey) {
|
|
mlme_key_descriptor_t *key_desc = mac_sec_key_description_get_by_attribute(rf_mac_setup, get_req->attr_index);
|
|
if (!key_desc) {
|
|
return -1;
|
|
}
|
|
get_req->value_pointer = &key_desc->KeyFrameCounter;
|
|
} else {
|
|
get_req->value_pointer = &rf_mac_setup->security_frame_counter;
|
|
}
|
|
|
|
get_req->value_size = 4;
|
|
break;
|
|
|
|
case macCCAThreshold:
|
|
cca_thr_table = mac_get_cca_threshold_table(rf_mac_setup);
|
|
get_req->value_size = cca_thr_table->number_of_channels;
|
|
get_req->value_pointer = cca_thr_table->ch_thresholds;
|
|
break;
|
|
|
|
default:
|
|
get_req->status = MLME_UNSUPPORTED_ATTRIBUTE;
|
|
break;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mlme_scan_operation(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
uint16_t channel;
|
|
mlme_scan_conf_t *resp = rf_mac_setup->mac_mlme_scan_resp;
|
|
|
|
if (rf_mac_setup->scan_type == MAC_ED_SCAN_TYPE) {
|
|
resp->ED_values[resp->ResultListSize] = rf_mac_setup->max_ED;
|
|
resp->ResultListSize++;
|
|
}
|
|
|
|
channel = mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list, true);
|
|
if (channel > 0xff || rf_mac_setup->mac_mlme_scan_resp->ResultListSize == MLME_MAC_RES_SIZE_MAX) {
|
|
resp->status = MLME_SUCCESS;
|
|
platform_enter_critical();
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
if (resp->ResultListSize == 0 && rf_mac_setup->scan_type == MAC_ACTIVE_SCAN) {
|
|
resp->status = MLME_NO_BEACON;
|
|
} else if (resp->ResultListSize == MLME_MAC_RES_SIZE_MAX) {
|
|
resp->status = MLME_LIMIT_REACHED;
|
|
}
|
|
resp->UnscannedChannels.channel_mask[0] = rf_mac_setup->mac_channel_list.channel_mask[0];
|
|
platform_exit_critical();
|
|
//Scan Confirmation
|
|
mac_generic_event_trig(MAC_MLME_SCAN_CONFIRM_HANDLER, rf_mac_setup, false);
|
|
rf_mac_setup->scan_active = false;
|
|
} else {
|
|
mac_mlme_scan_init((uint8_t) channel, rf_mac_setup);
|
|
}
|
|
}
|
|
|
|
void mac_frame_src_address_set_from_interface(uint8_t SrcAddrMode, protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *addressPtr)
|
|
{
|
|
if (!rf_ptr) {
|
|
return;
|
|
}
|
|
if (SrcAddrMode == MAC_ADDR_MODE_16_BIT) {
|
|
mac_mlme_write_mac16(rf_ptr, addressPtr);
|
|
} else if (SrcAddrMode == MAC_ADDR_MODE_64_BIT) {
|
|
mac_mlme_write_mac64(rf_ptr, addressPtr);
|
|
}
|
|
}
|
|
|
|
void mac_mlme_active_scan_response_timer_start(void *interface)
|
|
{
|
|
if (interface) {
|
|
protocol_interface_rf_mac_setup_s *rf_mac_setup = (protocol_interface_rf_mac_setup_s *)interface;
|
|
if (rf_mac_setup) {
|
|
if (rf_mac_setup->mac_mlme_event == ARM_NWK_MAC_MLME_SCAN) {
|
|
eventOS_callback_timer_stop(rf_mac_setup->mlme_timer_id);
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_SCAN;
|
|
rf_mac_setup->mlme_tick_count = rf_mac_setup->mlme_ED_counter;
|
|
|
|
eventOS_callback_timer_start(rf_mac_setup->mlme_timer_id, 300);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mac_mlme_timers_disable(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
platform_enter_critical();
|
|
if (rf_ptr->mac_mlme_event != ARM_NWK_MAC_MLME_IDLE) {
|
|
eventOS_callback_timer_stop(rf_ptr->mlme_timer_id);
|
|
rf_ptr->mac_mlme_event = ARM_NWK_MAC_MLME_IDLE;
|
|
}
|
|
timer_mac_stop(rf_ptr);
|
|
platform_exit_critical();
|
|
}
|
|
|
|
void mac_mlme_event_cb(void *mac_ptr)
|
|
{
|
|
protocol_interface_rf_mac_setup_s *rf_mac_setup = (protocol_interface_rf_mac_setup_s *) mac_ptr;
|
|
if (!rf_mac_setup) {
|
|
return;
|
|
}
|
|
arm_nwk_mlme_event_type_e event_type;
|
|
event_type = rf_mac_setup->mac_mlme_event;
|
|
rf_mac_setup->mac_mlme_event = ARM_NWK_MAC_MLME_IDLE;
|
|
switch (event_type) {
|
|
case ARM_NWK_MAC_MLME_SCAN:
|
|
mlme_scan_operation(rf_mac_setup);
|
|
break;
|
|
|
|
case ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL:
|
|
tr_debug("Data poll data wait TO");
|
|
mac_mlme_poll_process_confirm(rf_mac_setup, MLME_NO_DATA);
|
|
break;
|
|
|
|
case ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL_AFTER_DATA:
|
|
mac_mlme_poll_process_confirm(rf_mac_setup, MLME_SUCCESS);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void mac_mcps_timer_cb(int8_t timer_id, uint16_t slots)
|
|
{
|
|
|
|
protocol_interface_rf_mac_setup_s *rf_ptr = get_sw_mac_ptr_by_timer(timer_id, ARM_MCPS_TIMER);
|
|
if (!rf_ptr || !rf_ptr->dev_driver || !rf_ptr->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
rf_ptr->mac_mcps_timer_event.event_data = slots;
|
|
eventOS_event_send(&rf_ptr->mac_mcps_timer_event);
|
|
|
|
}
|
|
|
|
|
|
static void mac_mlme_timer_cb(int8_t timer_id, uint16_t slots)
|
|
{
|
|
protocol_interface_rf_mac_setup_s *rf_ptr = get_sw_mac_ptr_by_timer(timer_id, ARM_NWK_MLME_TIMER);
|
|
if (!rf_ptr || !rf_ptr->dev_driver || !rf_ptr->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
|
|
if (rf_ptr->mlme_tick_count == 0) {
|
|
if (rf_ptr->mac_mlme_event != ARM_NWK_MAC_MLME_IDLE) {
|
|
if (rf_ptr->mac_mlme_event == ARM_NWK_MAC_MLME_ED_ANALYZE) {
|
|
if (rf_ptr->mlme_ED_counter > 1) {
|
|
uint8_t ed = 0;
|
|
phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver;
|
|
rf_ptr->mlme_ED_counter--;
|
|
if (dev_driver->extension) {
|
|
dev_driver->extension(PHY_EXTENSION_READ_CHANNEL_ENERGY, &ed);
|
|
}
|
|
if (ed > rf_ptr->max_ED) {
|
|
rf_ptr->max_ED = ed;
|
|
}
|
|
|
|
/*96 * 50us = 4.8ms*/
|
|
rf_ptr->mlme_tick_count = 0;
|
|
rf_ptr->mac_mlme_event = ARM_NWK_MAC_MLME_ED_ANALYZE;
|
|
eventOS_callback_timer_start(timer_id, slots);
|
|
} else {
|
|
mac_mlme_rf_disable(rf_ptr);
|
|
rf_ptr->mac_mlme_event = ARM_NWK_MAC_MLME_SCAN;
|
|
mac_generic_event_trig(MAC_MLME_EVENT_HANDLER, rf_ptr, false);
|
|
}
|
|
} else {
|
|
mac_generic_event_trig(MAC_MLME_EVENT_HANDLER, rf_ptr, true);
|
|
}
|
|
}
|
|
} else {
|
|
rf_ptr->mlme_tick_count--;
|
|
eventOS_callback_timer_start(timer_id, slots);
|
|
}
|
|
}
|
|
|
|
static void mac_mlme_free_scan_temporary_data(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
rf_mac_setup->scan_active = false;
|
|
if (rf_mac_setup->mac_mlme_scan_resp) {
|
|
mlme_scan_conf_t *r = rf_mac_setup->mac_mlme_scan_resp;
|
|
if (r->ED_values) {
|
|
ns_dyn_mem_free(r->ED_values);
|
|
r->ED_values = NULL;
|
|
}
|
|
uint8_t i = 0;
|
|
while (i < r->ResultListSize) {
|
|
if (r->PAN_values[i]) {
|
|
ns_dyn_mem_free(r->PAN_values[i]);
|
|
}
|
|
i++;
|
|
}
|
|
ns_dyn_mem_free(rf_mac_setup->mac_mlme_scan_resp);
|
|
rf_mac_setup->mac_mlme_scan_resp = NULL;
|
|
}
|
|
}
|
|
|
|
void mac_mlme_set_active_state(protocol_interface_rf_mac_setup_s *entry, bool new_state)
|
|
{
|
|
if (entry) {
|
|
entry->macUpState = new_state;
|
|
}
|
|
}
|
|
|
|
void mac_mlme_data_base_deallocate(struct protocol_interface_rf_mac_setup *rf_mac)
|
|
{
|
|
if (rf_mac) {
|
|
if (rf_mac->dev_driver) {
|
|
rf_mac->dev_driver->phy_sap_identifier = NULL;
|
|
rf_mac->dev_driver->phy_sap_upper_cb = NULL;
|
|
}
|
|
|
|
eventOS_callback_timer_unregister(rf_mac->mlme_timer_id);
|
|
eventOS_callback_timer_unregister(rf_mac->mac_timer_id);
|
|
eventOS_callback_timer_unregister(rf_mac->mac_mcps_timer);
|
|
|
|
ns_dyn_mem_free(rf_mac->dev_driver_tx_buffer.buf);
|
|
ns_dyn_mem_free(rf_mac->dev_driver_tx_buffer.enhanced_ack_buf);
|
|
ns_dyn_mem_free(rf_mac->mac_beacon_payload);
|
|
|
|
mac_sec_mib_deinit(rf_mac);
|
|
mac_cca_thr_deinit(rf_mac);
|
|
ns_dyn_mem_free(rf_mac);
|
|
}
|
|
}
|
|
|
|
static uint8_t mac_backoff_ticks_calc(phy_device_driver_s *phy_driver)
|
|
{
|
|
//Calculate 20 symbol time which is typically 10 bytes
|
|
const phy_device_channel_page_s *phy_channel_pages = phy_driver->phy_channel_pages;
|
|
uint32_t datarate = dev_get_phy_datarate(phy_driver, phy_channel_pages->channel_page);
|
|
if (datarate == 0) {
|
|
datarate = 250000;
|
|
}
|
|
//How many 10us ticks backoff period is, assuming 4 bits per symbol (O-QPSK)
|
|
unsigned int ticks = (2000000 / (datarate / 4));
|
|
if (ticks > 255) {
|
|
ticks = 255;
|
|
tr_warn("Backoff period too slow");
|
|
}
|
|
return (uint8_t) ticks;
|
|
}
|
|
|
|
static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (rf_mac_setup->rf_csma_extension_supported) {
|
|
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, (uint8_t *) &rf_mac_setup->symbol_rate);
|
|
rf_mac_setup->symbol_time_us = 1000000 / rf_mac_setup->symbol_rate;
|
|
tr_debug("SW-MAC driver support rf extension %"PRIu32" symbol/seconds %"PRIu32" us symbol time length", rf_mac_setup->symbol_rate, rf_mac_setup->symbol_time_us);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int mac_mlme_allocate_tx_buffers(protocol_interface_rf_mac_setup_s *rf_mac_setup, arm_device_driver_list_s *dev_driver, uint16_t mtu_size)
|
|
{
|
|
ns_dyn_mem_free(rf_mac_setup->dev_driver_tx_buffer.buf);
|
|
ns_dyn_mem_free(rf_mac_setup->mac_beacon_payload);
|
|
uint16_t total_length = 0;
|
|
//Allocate tx buffer by given MTU + header + tail
|
|
total_length = mtu_size;
|
|
total_length += (dev_driver->phy_driver->phy_header_length + dev_driver->phy_driver->phy_tail_length);
|
|
rf_mac_setup->dev_driver_tx_buffer.buf = ns_dyn_mem_alloc(total_length);
|
|
if (!rf_mac_setup->dev_driver_tx_buffer.buf) {
|
|
return -1;
|
|
}
|
|
//allocate Beacon Payload buffer
|
|
rf_mac_setup->max_beacon_payload_length = mtu_size - MAC_IEEE_802_15_4_MAX_BEACON_OVERHEAD;
|
|
rf_mac_setup->mac_beacon_payload = ns_dyn_mem_alloc(rf_mac_setup->max_beacon_payload_length);
|
|
if (!rf_mac_setup->mac_beacon_payload) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, arm_device_driver_list_s *dev_driver, mac_description_storage_size_t *storage_sizes, uint16_t mtu_size)
|
|
{
|
|
//allocate security
|
|
if (!dev_driver || !mac64 || !dev_driver->phy_driver || !storage_sizes) {
|
|
return NULL;
|
|
}
|
|
|
|
protocol_interface_rf_mac_setup_s *entry = ns_dyn_mem_alloc(sizeof(protocol_interface_rf_mac_setup_s));
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
//Init everything for 0, NULL or false
|
|
memset(entry, 0, sizeof(protocol_interface_rf_mac_setup_s));
|
|
entry->ifs_timer_id = -1;
|
|
entry->cca_timer_id = -1;
|
|
entry->mlme_timer_id = -1;
|
|
entry->mac_timer_id = -1;
|
|
entry->bc_timer_id = -1;
|
|
entry->mac_interface_id = -1;
|
|
entry->dev_driver = dev_driver;
|
|
entry->aUnitBackoffPeriod = 20; //This can be different in some Platform 20 comes from 12-symbol turnaround and 8 symbol CCA read
|
|
entry->number_of_csma_ca_periods = MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS;
|
|
entry->multi_cca_interval = MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL;
|
|
entry->mac_channel_list.channel_page = CHANNEL_PAGE_UNDEFINED;
|
|
|
|
if (mac_sec_mib_init(entry, storage_sizes) != 0) {
|
|
mac_mlme_data_base_deallocate(entry);
|
|
return NULL;
|
|
}
|
|
|
|
if (!dev_driver->phy_driver->phy_MTU) {
|
|
mac_mlme_data_base_deallocate(entry);
|
|
return NULL;
|
|
}
|
|
entry->phy_mtu_size = mtu_size;
|
|
|
|
if (mac_mlme_allocate_tx_buffers(entry, dev_driver, mtu_size)) {
|
|
mac_mlme_data_base_deallocate(entry);
|
|
return NULL;
|
|
}
|
|
|
|
entry->mac_tasklet_id = mac_mcps_sap_tasklet_init();
|
|
if (entry->mac_tasklet_id < 0) {
|
|
mac_mlme_data_base_deallocate(entry);
|
|
return NULL;
|
|
}
|
|
|
|
entry->mlme_timer_id = eventOS_callback_timer_register(mac_mlme_timer_cb);
|
|
entry->mac_timer_id = eventOS_callback_timer_register(timer_mac_interrupt);
|
|
entry->mac_mcps_timer = eventOS_callback_timer_register(mac_mcps_timer_cb);
|
|
if (entry->mlme_timer_id == -1 || entry->mac_timer_id == -1 || entry->mac_mcps_timer == -1) {
|
|
mac_mlme_data_base_deallocate(entry);
|
|
return NULL;
|
|
}
|
|
entry->macCapRxOnIdle = true;
|
|
entry->macCapSecrutityCapability = true;
|
|
entry->pan_id = entry->mac_short_address = 0xffff;
|
|
mac_extended_mac_set(entry, mac64);
|
|
entry->mac_ack_wait_duration = MAC_ACK_WAIT_DURATION;
|
|
entry->mac_mlme_retry_max = MAC_DEFAULT_MAX_FRAME_RETRIES;
|
|
memset(entry->mac_default_key_source, 0xff, 8);
|
|
memset(entry->mac_auto_request.Keysource, 0xff, 8);
|
|
memset(entry->mac_beacon_payload, 0, entry->max_beacon_payload_length);
|
|
entry->mac_auto_request.SecurityLevel = 6;
|
|
entry->mac_auto_request.KeyIndex = 0xff;
|
|
mac_pd_sap_rf_low_level_function_set(entry, entry->dev_driver);
|
|
entry->mac_sequence = randLIB_get_8bit();
|
|
entry->mac_bea_sequence = randLIB_get_8bit();
|
|
entry->fhss_api = NULL;
|
|
entry->macMinBE = 3;
|
|
entry->macMaxBE = 5;
|
|
entry->macMaxCSMABackoffs = MAC_CCA_MAX;
|
|
entry->mac_mcps_timer_event.priority = ARM_LIB_LOW_PRIORITY_EVENT;
|
|
entry->mac_mcps_timer_event.event_type = MAC_MCPS_INDIRECT_TIMER_CB;
|
|
entry->mac_mcps_timer_event.data_ptr = entry;
|
|
entry->mac_mcps_timer_event.receiver = entry->mac_tasklet_id;
|
|
entry->mac_mcps_timer_event.sender = 0;
|
|
entry->mac_mcps_timer_event.event_id = 0;
|
|
bool rf_support = false;
|
|
dev_driver->phy_driver->extension(PHY_EXTENSION_DYNAMIC_RF_SUPPORTED, (uint8_t *)&rf_support);
|
|
entry->rf_csma_extension_supported = rf_support;
|
|
dev_driver->phy_driver->extension(PHY_EXTENSION_FILTERING_SUPPORT, (uint8_t *)&entry->mac_frame_filters);
|
|
if (entry->mac_frame_filters & (1 << MAC_FRAME_VERSION_2)) {
|
|
tr_debug("PHY supports 802.15.4-2015 frame filtering");
|
|
}
|
|
mac_mlme_set_symbol_rate(entry);
|
|
|
|
//How many 10us ticks backoff period is for waiting 20symbols which is typically 10 bytes time
|
|
entry->backoff_period_in_10us = mac_backoff_ticks_calc(dev_driver->phy_driver);
|
|
return entry;
|
|
}
|
|
|
|
uint8_t mac_mlme_set_new_sqn(protocol_interface_rf_mac_setup_s *rf_setup)
|
|
{
|
|
uint8_t ret_val = 0;
|
|
|
|
if (rf_setup) {
|
|
rf_setup->mac_sequence++;
|
|
ret_val = rf_setup->mac_sequence;
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
uint8_t mac_mlme_set_new_beacon_sqn(protocol_interface_rf_mac_setup_s *rf_setup)
|
|
{
|
|
uint8_t ret_val = 0;
|
|
|
|
if (rf_setup) {
|
|
rf_setup->mac_bea_sequence++;
|
|
ret_val = rf_setup->mac_bea_sequence;
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
static int8_t mac_mlme_set_panid(struct protocol_interface_rf_mac_setup *rf_setup, uint16_t pan_id)
|
|
{
|
|
phy_device_driver_s *dev_driver = rf_setup->dev_driver->phy_driver;
|
|
if (!dev_driver->address_write) {
|
|
if (dev_driver->link_type == PHY_LINK_TUN) {
|
|
rf_setup->pan_id = pan_id;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint8_t temp_8[2];
|
|
rf_setup->pan_id = pan_id;
|
|
common_write_16_bit(pan_id, temp_8);
|
|
|
|
return dev_driver->address_write(PHY_MAC_PANID, temp_8);
|
|
}
|
|
|
|
static void mac_mle_write_mac16_to_phy(phy_device_driver_s *dev_driver, uint16_t mac16)
|
|
{
|
|
uint8_t temp[2];
|
|
common_write_16_bit(mac16, temp);
|
|
if (dev_driver->address_write) {
|
|
dev_driver->address_write(PHY_MAC_16BIT, temp);
|
|
}
|
|
}
|
|
|
|
static int8_t mac_mlme_set_mac16(struct protocol_interface_rf_mac_setup *rf_setup, uint16_t mac16)
|
|
{
|
|
int8_t ret_val = -1;
|
|
if (rf_setup) {
|
|
|
|
rf_setup->mac_short_address = mac16;
|
|
//SET RF 16-bit
|
|
if (mac16 > 0xfffd) {
|
|
rf_setup->shortAdressValid = false;
|
|
} else {
|
|
rf_setup->shortAdressValid = true;
|
|
}
|
|
mac_mle_write_mac16_to_phy(rf_setup->dev_driver->phy_driver, mac16);
|
|
ret_val = 0;
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
static void mac_mlme_write_mac64(protocol_interface_rf_mac_setup_s *rf_setup, uint8_t *addrPtr)
|
|
{
|
|
memcpy(addrPtr, rf_setup->mac64, 8);
|
|
}
|
|
|
|
static void mac_mlme_write_mac16(protocol_interface_rf_mac_setup_s *rf_setup, uint8_t *addrPtr)
|
|
{
|
|
common_write_16_bit(rf_setup->mac_short_address, addrPtr);
|
|
}
|
|
|
|
uint16_t mac_mlme_get_panid(protocol_interface_rf_mac_setup_s *rf_setup)
|
|
{
|
|
uint16_t panId = 0xffff;
|
|
if (rf_setup) {
|
|
panId = rf_setup->pan_id;
|
|
}
|
|
return panId;
|
|
}
|
|
|
|
static bool add_or_update_beacon(mlme_scan_conf_t *conf, mlme_beacon_ind_t *data, fhss_api_t *fhss_api)
|
|
{
|
|
bool found = false;
|
|
bool update_beacon = false;
|
|
for (int i = 0; i < conf->ResultListSize; i++) {
|
|
mlme_pan_descriptor_t *cur_desc = conf->PAN_values[i];
|
|
if (!cur_desc) { //Not an active or passive scan
|
|
break;
|
|
}
|
|
/* When FHSS is enabled, logical channel check is not valid
|
|
* as the Beacon can be sent on any enabled channel */
|
|
if (fhss_api || (cur_desc->LogicalChannel == data->PANDescriptor.LogicalChannel)) {
|
|
if (cur_desc->CoordPANId == data->PANDescriptor.CoordPANId) {
|
|
if (cur_desc->LinkQuality < data->PANDescriptor.LinkQuality) {
|
|
cur_desc->CoordAddrMode = data->PANDescriptor.CoordAddrMode;
|
|
memcpy(cur_desc->CoordAddress, data->PANDescriptor.CoordAddress, 8);
|
|
cur_desc->LinkQuality = data->PANDescriptor.LinkQuality;
|
|
update_beacon = true;
|
|
}
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
if (!found && conf->ResultListSize != MLME_MAC_RES_SIZE_MAX) {
|
|
mlme_pan_descriptor_t *desc = ns_dyn_mem_temporary_alloc(sizeof(mlme_pan_descriptor_t));
|
|
if (!desc) {
|
|
return false;
|
|
}
|
|
memset(desc, 0, sizeof(mlme_pan_descriptor_t));
|
|
mlme_pan_descriptor_t *dat = &data->PANDescriptor;
|
|
|
|
desc->CoordAddrMode = dat->CoordAddrMode;
|
|
desc->CoordPANId = dat->CoordPANId;
|
|
memcpy(desc->CoordAddress, dat->CoordAddress, 8);
|
|
desc->LogicalChannel = dat->LogicalChannel;
|
|
desc->ChannelPage = dat->ChannelPage;
|
|
memcpy(desc->SuperframeSpec, dat->SuperframeSpec, 2);
|
|
desc->GTSPermit = dat->GTSPermit;
|
|
desc->LinkQuality = dat->LinkQuality;
|
|
desc->Timestamp = dat->Timestamp;
|
|
desc->SecurityFailure = dat->SecurityFailure;
|
|
|
|
desc->Key.SecurityLevel = dat->Key.SecurityLevel;
|
|
desc->Key.KeyIdMode = dat->Key.KeyIdMode;
|
|
desc->Key.KeyIndex = dat->Key.KeyIndex;
|
|
memcpy(desc->Key.Keysource, dat->Key.Keysource, 8);
|
|
|
|
conf->PAN_values[conf->ResultListSize] = desc;
|
|
conf->ResultListSize++;
|
|
update_beacon = true;
|
|
}
|
|
return update_beacon;
|
|
}
|
|
|
|
int mac_mlme_beacon_notify(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_beacon_ind_t *data)
|
|
{
|
|
bool update_beacon = true;
|
|
bool contains_fhss_synch_info = false;
|
|
if (!rf_mac_setup || !data) {
|
|
return -1;
|
|
}
|
|
|
|
/* Cut FHSS synchronization info from Beacon payload length.
|
|
* Synchronization info is stored later in this function but
|
|
* should not be delivered to upper layer as a part of Beacon payload.
|
|
*/
|
|
if (rf_mac_setup->fhss_api) {
|
|
if (data->beacon_data_length > FHSS_SYNCH_INFO_START) {
|
|
data->beacon_data_length -= FHSS_SYNCH_INFO_LENGTH;
|
|
contains_fhss_synch_info = true;
|
|
} else {
|
|
// Received single channel Beacon when FHSS enabled.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
mac_api_t *mac = get_sw_mac_api(rf_mac_setup);
|
|
if (mac && mac->mlme_ind_cb) {
|
|
mac->mlme_ind_cb(mac, MLME_BEACON_NOTIFY, data);
|
|
}
|
|
|
|
if (rf_mac_setup->mac_mlme_scan_resp) {
|
|
mlme_scan_conf_t *conf = rf_mac_setup->mac_mlme_scan_resp;
|
|
update_beacon = add_or_update_beacon(conf, data, rf_mac_setup->fhss_api);
|
|
}
|
|
if (rf_mac_setup->fhss_api && (update_beacon == true)) {
|
|
if (contains_fhss_synch_info == true) {
|
|
// Assume synchronization info is found from the end of the Beacon payload
|
|
uint8_t *synch_info_start = data->beacon_data + data->beacon_data_length;
|
|
rf_mac_setup->fhss_api->receive_frame(rf_mac_setup->fhss_api, data->PANDescriptor.CoordPANId, data->PANDescriptor.CoordAddress,
|
|
data->PANDescriptor.Timestamp, synch_info_start, FHSS_SYNCH_FRAME);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int8_t mac_mlme_virtual_confirmation_handle(int8_t driver_id, const uint8_t *data_ptr, uint16_t length)
|
|
{
|
|
(void) length;
|
|
protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_driver_id(driver_id);
|
|
if (!mac_setup) {
|
|
return -1;
|
|
}
|
|
mlme_primitive primitive = (mlme_primitive) * data_ptr;
|
|
if (primitive == MLME_SCAN) {
|
|
mlme_scan_conf_t *resp = ns_dyn_mem_temporary_alloc(sizeof(mlme_scan_conf_t));
|
|
if (!resp) {
|
|
return -1;
|
|
}
|
|
memset(resp, 0, sizeof(mlme_scan_conf_t));
|
|
resp->ScanType = MAC_ACTIVE_SCAN;
|
|
mac_setup->mac_mlme_scan_resp = resp;
|
|
mac_mlme_scan_confirmation_handle(mac_setup);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mac_mlme_start_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_start_conf_t *conf)
|
|
{
|
|
if (rf_ptr->tun_extension_rf_driver) {
|
|
virtual_data_req_t start_conf;
|
|
uint8_t buf_temp[2];
|
|
uint8_t payload_buf[2];
|
|
// Add some random data as empty payload is not allowed
|
|
payload_buf[0] = 0;
|
|
payload_buf[1] = 0;
|
|
|
|
memset(&start_conf, 0, sizeof(virtual_data_req_t));
|
|
buf_temp[0] = NAP_MLME_CONFIRM;
|
|
buf_temp[1] = MLME_START;
|
|
start_conf.parameters = buf_temp;
|
|
start_conf.parameter_length = sizeof(buf_temp);
|
|
start_conf.msdu = payload_buf;
|
|
start_conf.msduLength = sizeof(payload_buf);
|
|
|
|
rf_ptr->tun_extension_rf_driver->phy_driver->arm_net_virtual_tx_cb(&start_conf, rf_ptr->tun_extension_rf_driver->id);
|
|
} else if (get_sw_mac_api(rf_ptr)) {
|
|
if (get_sw_mac_api(rf_ptr)->mlme_conf_cb) {
|
|
get_sw_mac_api(rf_ptr)->mlme_conf_cb(get_sw_mac_api(rf_ptr), MLME_START, conf);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mac_mlme_scan_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_scan_conf_t *conf)
|
|
{
|
|
if (rf_ptr->tun_extension_rf_driver) {
|
|
virtual_data_req_t scan_conf;
|
|
uint8_t buf_temp[2];
|
|
uint8_t payload_buf[2];
|
|
// Add some random data as empty payload is not allowed
|
|
payload_buf[0] = 0;
|
|
payload_buf[1] = 0;
|
|
|
|
memset(&scan_conf, 0, sizeof(virtual_data_req_t));
|
|
buf_temp[0] = NAP_MLME_CONFIRM;
|
|
buf_temp[1] = MLME_SCAN;
|
|
scan_conf.parameters = buf_temp;
|
|
scan_conf.parameter_length = sizeof(buf_temp);
|
|
scan_conf.msdu = payload_buf;
|
|
scan_conf.msduLength = sizeof(payload_buf);
|
|
|
|
rf_ptr->tun_extension_rf_driver->phy_driver->arm_net_virtual_tx_cb(&scan_conf, rf_ptr->tun_extension_rf_driver->id);
|
|
} else if (get_sw_mac_api(rf_ptr)) {
|
|
if (get_sw_mac_api(rf_ptr)->mlme_conf_cb) {
|
|
get_sw_mac_api(rf_ptr)->mlme_conf_cb(get_sw_mac_api(rf_ptr), MLME_SCAN, conf);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_mlme_scan_confirmation_handle(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
if (!rf_ptr) {
|
|
return;
|
|
}
|
|
mlme_scan_conf_t *r = rf_ptr->mac_mlme_scan_resp;
|
|
|
|
if (r) {
|
|
mac_mlme_scan_confirm_handler(rf_ptr, r);
|
|
}
|
|
mac_mlme_free_scan_temporary_data(rf_ptr);
|
|
}
|
|
|
|
void mac_mlme_mac_radio_disabled(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (!rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
platform_enter_critical();
|
|
timer_mac_stop(rf_mac_setup);
|
|
mac_mlme_rf_disable(rf_mac_setup);
|
|
platform_exit_critical();
|
|
}
|
|
|
|
void mac_mlme_mac_radio_enable(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
if (!rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
platform_enter_critical();
|
|
mac_mlme_rf_receiver_enable(rf_mac_setup);
|
|
platform_exit_critical();
|
|
}
|
|
|
|
static int8_t mac_mlme_rf_disable(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|
{
|
|
int8_t ret_val = 0;
|
|
phy_device_driver_s *dev_driver = rf_mac_setup->dev_driver->phy_driver;
|
|
if (!dev_driver->state_control) {
|
|
if (dev_driver->link_type == PHY_LINK_TUN) {
|
|
rf_mac_setup->macRfRadioOn = false;
|
|
rf_mac_setup->macRfRadioTxActive = false;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
if (rf_mac_setup->macRfRadioOn) {
|
|
ret_val = dev_driver->state_control(PHY_INTERFACE_DOWN, 0);
|
|
rf_mac_setup->macRfRadioOn = false;
|
|
rf_mac_setup->macRfRadioTxActive = false;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
static int8_t mac_mlme_rf_receiver_enable(struct protocol_interface_rf_mac_setup *rf_mac_setup)
|
|
{
|
|
int8_t retval;
|
|
|
|
phy_device_driver_s *dev_driver = rf_mac_setup->dev_driver->phy_driver;
|
|
if (!dev_driver->state_control) {
|
|
if (dev_driver->link_type == PHY_LINK_TUN) {
|
|
rf_mac_setup->macRfRadioOn = true;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (rf_mac_setup->macRfRadioOn) {
|
|
return 0;
|
|
}
|
|
|
|
if (rf_mac_setup->macProminousMode) {
|
|
tr_debug("Sniffer mode");
|
|
retval = dev_driver->state_control(PHY_INTERFACE_SNIFFER_STATE, rf_mac_setup->mac_channel);
|
|
} else {
|
|
retval = dev_driver->state_control(PHY_INTERFACE_UP, rf_mac_setup->mac_channel);
|
|
}
|
|
rf_mac_setup->macRfRadioOn = true;
|
|
//tr_debug("Enable radio with channel %u", rf_mac_setup->mac_channel);
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* Initialize MAC channel selection sequence
|
|
*
|
|
* TODO: initialize channel select sequence
|
|
* in coordinator mode
|
|
*
|
|
* \param new_channel channel to set
|
|
*
|
|
* \return 0 success
|
|
* \return -1 HW error
|
|
*/
|
|
static int8_t mac_mlme_rf_channel_set(struct protocol_interface_rf_mac_setup *rf_setup, uint8_t new_channel)
|
|
{
|
|
if (new_channel == rf_setup->mac_channel) {
|
|
return 0;
|
|
}
|
|
mac_pre_build_frame_t *buf;
|
|
|
|
//Disable allways
|
|
mac_mlme_mac_radio_disabled(rf_setup);
|
|
buf = rf_setup->active_pd_data_request;
|
|
rf_setup->active_pd_data_request = NULL;
|
|
//Set Channel
|
|
rf_setup->mac_channel = new_channel;
|
|
//Enable Radio
|
|
mac_mlme_mac_radio_enable(rf_setup);
|
|
if (buf) {
|
|
mcps_sap_pd_req_queue_write(rf_setup, buf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* MAC channel change
|
|
*
|
|
* \param new_channel channel to set
|
|
*
|
|
* \return 0 success
|
|
* \return -1 error
|
|
*/
|
|
int8_t mac_mlme_rf_channel_change(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t new_channel)
|
|
{
|
|
if (!rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return -1;
|
|
}
|
|
|
|
if (!rf_mac_setup->dev_driver->phy_driver->extension) {
|
|
if (rf_mac_setup->dev_driver->phy_driver->link_type == PHY_LINK_TUN) {
|
|
rf_mac_setup->mac_channel = new_channel;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
if (new_channel == rf_mac_setup->mac_channel) {
|
|
return 0;
|
|
}
|
|
|
|
platform_enter_critical();
|
|
if (rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL, &new_channel) == 0) {
|
|
rf_mac_setup->mac_channel = new_channel;
|
|
}
|
|
platform_exit_critical();
|
|
return 0;
|
|
}
|
|
|
|
void mac_mlme_poll_process_confirm(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t status)
|
|
{
|
|
if (!rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
|
return;
|
|
}
|
|
|
|
//Free active Data buffer
|
|
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;
|
|
}
|
|
//Disable timer
|
|
rf_mac_setup->macWaitingData = false;
|
|
rf_mac_setup->macDataPollReq = false;
|
|
rf_mac_setup->macRxDataAtPoll = false;
|
|
|
|
if (!rf_mac_setup->macCapRxOnIdle) {
|
|
//Disable Radio If we are RX off at idle device
|
|
//tr_debug("disbale by aceptance data");
|
|
if (!rf_mac_setup->macRfRadioTxActive) {
|
|
//Disable radio if no active TX and radio is enabled
|
|
//tr_debug("RF disable");
|
|
mac_mlme_mac_radio_disabled(rf_mac_setup);
|
|
}
|
|
}
|
|
|
|
mac_api_t *mac_api = get_sw_mac_api(rf_mac_setup);
|
|
if (mac_api) {
|
|
mlme_poll_conf_t confirm;
|
|
confirm.status = status;
|
|
mac_api->mlme_conf_cb(mac_api, MLME_POLL, &confirm);
|
|
}
|
|
//Trig Packet from queue
|
|
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
|
|
|
|
}
|
|
|
|
void mac_mlme_poll_req(protocol_interface_rf_mac_setup_s *cur, const mlme_poll_t *poll_req)
|
|
{
|
|
if (!cur || !poll_req) {
|
|
return;
|
|
}
|
|
if (cur->macDataPollReq) {
|
|
tr_debug("Poll Active do not start new");
|
|
return;
|
|
}
|
|
mac_pre_build_frame_t *buf = mcps_sap_prebuild_frame_buffer_get(0);
|
|
if (!buf) {
|
|
tr_debug("No mem for data Req");
|
|
//Confirmation call here
|
|
return;
|
|
}
|
|
|
|
buf->fcf_dsn.frametype = FC_CMD_FRAME;
|
|
buf->WaitResponse = true;
|
|
buf->fcf_dsn.ackRequested = true;
|
|
buf->fcf_dsn.intraPan = true;
|
|
|
|
buf->DstPANId = poll_req->CoordPANId;
|
|
buf->SrcPANId = poll_req->CoordPANId;
|
|
buf->fcf_dsn.DstAddrMode = poll_req->CoordAddrMode;
|
|
memcpy(buf->DstAddr, poll_req->CoordAddress, 8);
|
|
|
|
buf->mac_command_id = MAC_DATA_REQ;
|
|
buf->mac_payload = &buf->mac_command_id;
|
|
buf->mac_payload_length = 1;
|
|
buf->mac_header_length_with_security = 3;
|
|
|
|
mac_header_security_parameter_set(&buf->aux_header, &poll_req->Key);
|
|
|
|
if (buf->aux_header.securityLevel) {
|
|
buf->fcf_dsn.securityEnabled = true;
|
|
buf->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
|
|
|
|
}
|
|
cur->macDataPollReq = true;
|
|
cur->macWaitingData = true;
|
|
cur->macRxDataAtPoll = false;
|
|
|
|
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);
|
|
|
|
if (cur->mac_short_address > 0xfffd) {
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_64_BIT;
|
|
} else {
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_16_BIT;
|
|
}
|
|
mac_frame_src_address_set_from_interface(buf->fcf_dsn.SrcAddrMode, cur, buf->SrcAddr);
|
|
//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);
|
|
buf->mac_header_length_with_security += mac_header_address_length(&buf->fcf_dsn);
|
|
buf->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
|
|
mcps_sap_pd_req_queue_write(cur, buf);
|
|
}
|
|
|
|
static bool mac_mlme_beacon_at_queue(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
mac_pre_build_frame_t *buf = rf_ptr->active_pd_data_request;
|
|
if (buf && buf->fcf_dsn.frametype == FC_BEACON_FRAME) {
|
|
return true;
|
|
}
|
|
|
|
buf = rf_ptr->pd_data_request_queue_to_go;
|
|
|
|
while (buf) {
|
|
if (buf->fcf_dsn.frametype == FC_BEACON_FRAME) {
|
|
return true;
|
|
}
|
|
buf = buf->next;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int8_t mac_mlme_beacon_tx(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|
{
|
|
if (!rf_ptr || !rf_ptr->macCapCordinator) {
|
|
return -1;
|
|
}
|
|
|
|
//Verify if beacon is already generated to queue
|
|
if (mac_mlme_beacon_at_queue(rf_ptr)) {
|
|
return -2;
|
|
}
|
|
|
|
uint16_t length = 4;
|
|
length += rf_ptr->mac_beacon_payload_size;
|
|
// Add more space for FHSS synchronization info
|
|
if (rf_ptr->fhss_api) {
|
|
length += FHSS_SYNCH_INFO_LENGTH;
|
|
}
|
|
/* if (rf_ptr->beacon_join_priority_tx_cb_ptr) {
|
|
length += 2;
|
|
}*/
|
|
|
|
mac_pre_build_frame_t *buf = mcps_sap_prebuild_frame_buffer_get(length);
|
|
if (!buf) {
|
|
return -1;
|
|
}
|
|
uint8_t sf_2 = 0x0f;
|
|
|
|
buf->fcf_dsn.frametype = FC_BEACON_FRAME;
|
|
buf->fcf_dsn.DstAddrMode = MAC_ADDR_MODE_NONE;
|
|
|
|
if (rf_ptr->beaconSrcAddressModeLong) {
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_64_BIT;
|
|
buf->mac_header_length_with_security = 13;
|
|
} else {
|
|
if (rf_ptr->shortAdressValid) {
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_16_BIT;
|
|
buf->mac_header_length_with_security = 7;
|
|
} else {
|
|
buf->fcf_dsn.SrcAddrMode = MAC_ADDR_MODE_64_BIT;
|
|
buf->mac_header_length_with_security = 13;
|
|
}
|
|
}
|
|
buf->SrcPANId = mac_mlme_get_panid(rf_ptr);
|
|
mac_frame_src_address_set_from_interface(buf->fcf_dsn.SrcAddrMode, rf_ptr, buf->SrcAddr);
|
|
buf->fcf_dsn.DstPanPresents = false;
|
|
buf->fcf_dsn.SrcPanPresents = true;
|
|
|
|
uint8_t *ptr = buf->mac_payload;
|
|
|
|
*ptr++ = 0xff;//Superframe disabled
|
|
|
|
if (rf_ptr->macCapCordinator) {
|
|
sf_2 |= 0x40; //Cord
|
|
}
|
|
|
|
if (rf_ptr->macCapBatteryPowered) {
|
|
sf_2 |= 0x10; //Battery
|
|
}
|
|
|
|
if (rf_ptr->macCapAssocationPermit) {
|
|
sf_2 |= 0x80; //Permit
|
|
}
|
|
*ptr++ = sf_2; //Superframe desc MSB
|
|
ptr = common_write_16_bit(0, ptr); //NO GTS Support
|
|
|
|
if (rf_ptr->mac_beacon_payload_size) {
|
|
memcpy(ptr, rf_ptr->mac_beacon_payload, rf_ptr->mac_beacon_payload_size);
|
|
|
|
/*if (rf_ptr->beacon_join_priority_tx_cb_ptr) {
|
|
uint8_t beacon_join_priority = rf_ptr->beacon_join_priority_tx_cb_ptr(rf_ptr->mac_interface_id);
|
|
ptr[PLAIN_BEACON_PAYLOAD_SIZE] = BEACON_OPTION_JOIN_PRIORITY_TYPE_LEN;
|
|
ptr[PLAIN_BEACON_PAYLOAD_SIZE + 1] = beacon_join_priority;
|
|
ptr += BEACON_OPTION_JOIN_PRIORITY_LEN;
|
|
}*/
|
|
}
|
|
buf->priority = MAC_PD_DATA_HIGH_PRIOTITY;
|
|
mcps_sap_pd_req_queue_write(rf_ptr, buf);
|
|
sw_mac_stats_update(rf_ptr, STAT_MAC_BEA_TX_COUNT, 0);
|
|
return 0;
|
|
}
|
|
|