/* * Copyright (c) 2016-2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "nsconfig.h" #include #include "NWK_INTERFACE/Include/protocol.h" #include "mlme.h" #include "mac_helper.h" #include "mac_common_defines.h" #include "nsdynmemLIB.h" #include "net_nwk_scan.h" #include "ns_trace.h" #include "common_functions.h" #include "mac_api.h" #define TRACE_GROUP "MACh" static const uint8_t mac_helper_default_key_source[8] = {0xff, 0, 0, 0, 0, 0, 0, 0}; uint16_t test_6lowpan_fragmentation_mtu_size_override = 0; static uint8_t mac_helper_header_security_aux_header_length(uint8_t keyIdmode); static uint8_t mac_helper_security_mic_length_get(uint8_t security_level); static void mac_helper_keytable_pairwise_descriptor_set(struct mac_api_s *api, const uint8_t *key, const uint8_t *mac64, uint8_t attribute_id); static int8_t mac_helper_pib_8bit_set(protocol_interface_info_entry_t *interface, mlme_attr_t attribute, uint8_t value) { switch (attribute) { case macAutoRequestKeyIdMode: interface->mac_parameters->mac_key_id_mode = value; break; case macAutoRequestKeyIndex: interface->mac_parameters->mac_default_key_index = value; break; case macAutoRequestSecurityLevel: default: interface->mac_parameters->mac_security_level = value; break; } if (interface->mac_api && interface->mac_api->mlme_req) { mlme_set_t set_req; set_req.attr = attribute; set_req.attr_index = 0; set_req.value_pointer = &value; set_req.value_size = 1; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } return 0; } void mac_create_scan_request(mac_scan_type_t type, channel_list_s *chanlist, uint8_t scan_duration, mlme_scan_t *request) { if (!chanlist || !request) { return; } memset(request, 0, sizeof(mlme_scan_t)); request->ScanType = type; request->ScanChannels = *chanlist; request->ScanDuration = scan_duration; } nwk_pan_descriptor_t *mac_helper_select_best_lqi(nwk_pan_descriptor_t *list) { nwk_pan_descriptor_t *best = list; //Analyze Best Result while (list) { tr_debug("LinkQuality: %i, LogicalCh: %i", list->pan_descriptor->LinkQuality, list->pan_descriptor->LogicalChannel); if (best->pan_descriptor->LinkQuality < list->pan_descriptor->LinkQuality) { best = list; } list = list->next; } return best; } void mac_helper_drop_selected_from_the_scanresult(nwk_scan_params_t *scanParams, nwk_pan_descriptor_t *selected) { if (!scanParams || !selected) { return; } nwk_pan_descriptor_t *cur; nwk_pan_descriptor_t *prev = 0; cur = scanParams->nwk_response_info; while (cur) { if (cur == selected) { tr_debug("Clean Selected out from the list"); if (prev) { prev->next = cur->next; } else { scanParams->nwk_response_info = cur->next; } scanParams->nwk_scan_res_size--; cur = 0; } if (cur) { prev = cur; cur = cur->next; } } } void mac_helper_free_scan_confirm(nwk_scan_params_t *params) { if (!params) { return; } if (params->nwk_scan_res_size) { nwk_pan_descriptor_t *cur = params->nwk_response_info; nwk_pan_descriptor_t *tmp; tr_debug("Scanned Results"); while (cur) { tmp = cur; cur = cur->next; tr_debug("Free NWK Structure"); mac_helper_free_pan_descriptions(tmp); } params->nwk_response_info = 0; params->nwk_scan_res_size = 0; } params->nwk_cur_active = mac_helper_free_pan_descriptions(params->nwk_cur_active); } nwk_pan_descriptor_t *mac_helper_free_pan_descriptions(nwk_pan_descriptor_t *nwk_cur_active) { if (nwk_cur_active) { ns_dyn_mem_free(nwk_cur_active->pan_descriptor); ns_dyn_mem_free(nwk_cur_active->beacon_payload); ns_dyn_mem_free(nwk_cur_active); } return NULL; } int8_t mac_helper_nwk_id_filter_set(const uint8_t *nw_id, nwk_filter_params_s *filter) { if (!filter) { return -1; } int8_t ret_val = 0; if (nw_id) { if (filter->beacon_nwk_id_filter == 0) { filter->beacon_nwk_id_filter = ns_dyn_mem_alloc(16); } if (filter->beacon_nwk_id_filter) { memcpy(filter->beacon_nwk_id_filter, nw_id, 16); } else { ret_val = -1; } } else { ns_dyn_mem_free(filter->beacon_nwk_id_filter); filter->beacon_nwk_id_filter = 0; } return ret_val; } void mac_helper_panid_set(protocol_interface_info_entry_t *interface, uint16_t panId) { interface->mac_parameters->pan_id = panId; mlme_set_t set_req; set_req.attr = macPANId; set_req.attr_index = 0; set_req.value_pointer = &panId; set_req.value_size = 2; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } void mac_helper_mac16_address_set(protocol_interface_info_entry_t *interface, uint16_t mac16) { interface->mac_parameters->mac_short_address = mac16; if (mac16 < 0xfffe) { interface->mac_parameters->shortAdressValid = true; } else { interface->mac_parameters->shortAdressValid = false; } mlme_set_t set_req; set_req.attr = macShortAddress; set_req.attr_index = 0; set_req.value_pointer = &mac16; set_req.value_size = 2; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } uint16_t mac_helper_mac16_address_get(const protocol_interface_info_entry_t *interface) { uint16_t shortAddress = 0xfffe; if (interface) { shortAddress = interface->mac_parameters->mac_short_address; } return shortAddress; } uint16_t mac_helper_panid_get(const protocol_interface_info_entry_t *interface) { uint16_t panId = 0xffff; if (interface) { panId = interface->mac_parameters->pan_id; } return panId; } void mac_helper_default_key_index_set(protocol_interface_info_entry_t *interface, uint8_t keyIndex) { interface->mac_parameters->mac_default_key_index = keyIndex; } uint8_t mac_helper_default_key_index_get(protocol_interface_info_entry_t *interface) { return interface->mac_parameters->mac_default_key_index; } void mac_helper_set_default_key_source(protocol_interface_info_entry_t *interface) { mlme_set_t set_req; set_req.attr_index = 0; set_req.value_pointer = (void *)mac_helper_default_key_source; set_req.value_size = 8; //Set first default key source set_req.attr = macDefaultKeySource; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); //Set first default key source set_req.attr = macAutoRequestKeySource; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } void mac_helper_default_security_level_set(protocol_interface_info_entry_t *interface, uint8_t securityLevel) { bool security_enabled; if (securityLevel) { security_enabled = true; } else { security_enabled = false; } mac_helper_pib_8bit_set(interface, macAutoRequestSecurityLevel, securityLevel); mac_helper_pib_boolean_set(interface, macSecurityEnabled, security_enabled); } uint8_t mac_helper_default_security_level_get(protocol_interface_info_entry_t *interface) { return interface->mac_parameters->mac_security_level; } void mac_helper_default_security_key_id_mode_set(protocol_interface_info_entry_t *interface, uint8_t keyIdMode) { mac_helper_pib_8bit_set(interface, macAutoRequestKeyIdMode, keyIdMode); } uint8_t mac_helper_default_security_key_id_mode_get(protocol_interface_info_entry_t *interface) { return interface->mac_parameters->mac_key_id_mode; } static void mac_helper_key_lookup_set(mlme_key_id_lookup_descriptor_t *lookup, uint8_t id) { memcpy(lookup->LookupData, mac_helper_default_key_source, 8); lookup->LookupData[8] = id; lookup->LookupDataSize = 1; } static void mac_helper_keytable_descriptor_set(struct mac_api_s *api, const uint8_t *key, uint8_t id, uint8_t attribute_id) { mlme_set_t set_req; mlme_key_id_lookup_descriptor_t lookup_description; mlme_key_descriptor_entry_t key_description; if (key) { mac_helper_key_lookup_set(&lookup_description, id); memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); memcpy(key_description.Key, key, 16); key_description.KeyIdLookupList = &lookup_description; key_description.KeyIdLookupListEntries = 1; } else { memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); } set_req.attr = macKeyTable; set_req.attr_index = attribute_id; set_req.value_pointer = &key_description; set_req.value_size = sizeof(mlme_key_descriptor_entry_t); api->mlme_req(api, MLME_SET, &set_req); } static void mac_helper_keytable_pairwise_descriptor_set(struct mac_api_s *api, const uint8_t *key, const uint8_t *mac64, uint8_t attribute_id) { mlme_set_t set_req; mlme_key_id_lookup_descriptor_t lookup_description; mlme_key_descriptor_entry_t key_description; if (key) { memcpy(lookup_description.LookupData, mac64, 8); lookup_description.LookupData[8] = 0; lookup_description.LookupDataSize = 1; tr_debug("Key add %u index %s", attribute_id, trace_array(lookup_description.LookupData, 9)); memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); memcpy(key_description.Key, key, 16); key_description.KeyIdLookupList = &lookup_description; key_description.KeyIdLookupListEntries = 1; } else { memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); } set_req.attr = macKeyTable; set_req.attr_index = attribute_id; set_req.value_pointer = &key_description; set_req.value_size = sizeof(mlme_key_descriptor_entry_t); api->mlme_req(api, MLME_SET, &set_req); } int8_t mac_helper_security_default_key_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode) { if (id == 0 || keyid_mode > 3) { return -1; } mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, id); mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_default_key_attribute_id); return 0; } int8_t mac_helper_security_default_recv_key_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode) { if (id == 0 || keyid_mode > 3) { return -1; } mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_default_key_attribute_id); return 0; } int8_t mac_helper_security_auto_request_key_index_set(protocol_interface_info_entry_t *interface, uint8_t key_attibute_index, uint8_t id) { if (id == 0) { return -1; } interface->mac_parameters->mac_default_key_attribute_id = key_attibute_index; mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, id); return 0; } int8_t mac_helper_security_pairwisekey_set(protocol_interface_info_entry_t *interface, const uint8_t *key, const uint8_t *mac_64, uint8_t key_attribute) { if (key && !mac_64) { return -1; } mac_helper_keytable_pairwise_descriptor_set(interface->mac_api, key, mac_64, key_attribute); return 0; } int8_t mac_helper_security_next_key_set(protocol_interface_info_entry_t *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode) { if (id == 0 || keyid_mode > 3) { return -1; } interface->mac_parameters->mac_next_key_index = id; mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_next_key_attribute_id); return 0; } int8_t mac_helper_security_prev_key_set(protocol_interface_info_entry_t *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode) { if (id == 0 || keyid_mode > 3) { return -1; } interface->mac_parameters->mac_prev_key_index = id; mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_prev_key_attribute_id); return 0; } int8_t mac_helper_security_key_to_descriptor_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t descriptor) { if (id == 0) { return -1; } mac_helper_keytable_descriptor_set(interface->mac_api, key, id, descriptor); return 0; } int8_t mac_helper_security_key_descriptor_clear(protocol_interface_info_entry_t *interface, uint8_t descriptor) { if (!interface->mac_api) { return -1; } mlme_set_t set_req; mlme_key_descriptor_entry_t key_description; memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); set_req.attr = macKeyTable; set_req.value_pointer = &key_description; set_req.value_size = sizeof(mlme_key_descriptor_entry_t); set_req.attr_index = descriptor; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); return 0; } void mac_helper_security_key_swap_next_to_default(protocol_interface_info_entry_t *interface) { //Free old prev key /* * Update key setup next way * * Current Key -> Prev key * Next Key -> Current key * Prev Key ->Overwrite by for next Purpose */ //Free current prev mac_helper_keytable_descriptor_set(interface->mac_api, NULL, 0, interface->mac_parameters->mac_prev_key_attribute_id); uint8_t prev_attribute = interface->mac_parameters->mac_prev_key_attribute_id; //save current pre for next purpose interface->mac_parameters->mac_prev_key_index = interface->mac_parameters->mac_default_key_index; interface->mac_parameters->mac_prev_key_attribute_id = interface->mac_parameters->mac_default_key_attribute_id; mac_helper_security_auto_request_key_index_set(interface, interface->mac_parameters->mac_next_key_attribute_id, interface->mac_parameters->mac_next_key_index); interface->mac_parameters->mac_next_key_index = 0; interface->mac_parameters->mac_next_key_attribute_id = prev_attribute; } void mac_helper_security_key_clean(protocol_interface_info_entry_t *interface) { if (interface->mac_api) { mlme_set_t set_req; mlme_key_descriptor_entry_t key_description; memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); set_req.attr = macKeyTable; set_req.value_pointer = &key_description; set_req.value_size = sizeof(mlme_key_descriptor_entry_t); set_req.attr_index = interface->mac_parameters->mac_prev_key_attribute_id; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); set_req.attr_index = interface->mac_parameters->mac_default_key_attribute_id; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); set_req.attr_index = interface->mac_parameters->mac_next_key_attribute_id; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } interface->mac_parameters->mac_prev_key_index = 0; interface->mac_parameters->mac_default_key_index = 0; interface->mac_parameters->mac_next_key_index = 0; } void mac_helper_coordinator_address_set(protocol_interface_info_entry_t *interface, addrtype_t adr_type, uint8_t *adr_ptr) { uint16_t short_addr; mlme_set_t set_req; set_req.attr_index = 0; if (adr_type == ADDR_802_15_4_SHORT) { memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 2); interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_16_BIT; short_addr = common_read_16_bit(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address); set_req.attr = macCoordShortAddress; set_req.value_pointer = &short_addr; set_req.value_size = 2; } else if (adr_type == ADDR_802_15_4_LONG) { memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 8); interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_64_BIT; set_req.attr = macCoordExtendedAddress; set_req.value_pointer = &interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address; set_req.value_size = 8; } if (interface->mac_api) { interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } } addrtype_t mac_helper_coordinator_address_get(protocol_interface_info_entry_t *interface, uint8_t *adr_ptr) { addrtype_t ret = ADDR_NONE; if (!interface) { return ret; } if (interface->mac_parameters->mac_cordinator_info.cord_adr_mode == MAC_ADDR_MODE_16_BIT) { memcpy(adr_ptr, interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, 2); ret = ADDR_802_15_4_SHORT; } else if (interface->mac_parameters->mac_cordinator_info.cord_adr_mode == MAC_ADDR_MODE_64_BIT) { memcpy(adr_ptr, interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, 8); ret = ADDR_802_15_4_LONG; } return ret; } #define MIN(a, b) (((a) <= (b)) ? (a) : (b)) static void mac_helper_beacon_payload_length_set_to_mac(protocol_interface_info_entry_t *interface, uint8_t len) { if (interface->mac_api) { mlme_set_t set_req; set_req.attr = macBeaconPayloadLength; set_req.attr_index = 0; set_req.value_pointer = &len; set_req.value_size = 1; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } } static void mac_helper_beacon_payload_set_to_mac(protocol_interface_info_entry_t *interface, const uint8_t *payload, uint8_t length) { if (interface->mac_api) { mlme_set_t set_req; set_req.attr = macBeaconPayload; set_req.attr_index = 0; set_req.value_pointer = payload; set_req.value_size = length; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } } // XXX: a ns_dyn_mem_realloc() would be nice to have uint8_t *mac_helper_beacon_payload_reallocate(protocol_interface_info_entry_t *interface, uint8_t len) { if (len == interface->mac_parameters->mac_beacon_payload_size) { // no change to size, return the existing buff //Set allways length to zero for safe beacon payload manipulate mac_helper_beacon_payload_length_set_to_mac(interface, 0); return interface->mac_parameters->mac_beacon_payload; } if (len == 0) { //SET MAC beacon payload to length to zero mac_helper_beacon_payload_length_set_to_mac(interface, 0); ns_dyn_mem_free(interface->mac_parameters->mac_beacon_payload); interface->mac_parameters->mac_beacon_payload = NULL; interface->mac_parameters->mac_beacon_payload_size = 0; return NULL; } tr_debug("mac_helper_beacon_payload_reallocate, old len: %d, new: %d", interface->mac_parameters->mac_beacon_payload_size, len); uint8_t *temp_buff = ns_dyn_mem_alloc(len); if (temp_buff == NULL) { // no need to proceed, could not allocate more space return NULL; } //SET MAC beacon payload to length to zero mac_helper_beacon_payload_length_set_to_mac(interface, 0); // copy data into new buffer before freeing old one if (interface->mac_parameters->mac_beacon_payload_size > 0) { const uint8_t min_len = MIN(len, interface->mac_parameters->mac_beacon_payload_size); memcpy(temp_buff, interface->mac_parameters->mac_beacon_payload, min_len); ns_dyn_mem_free(interface->mac_parameters->mac_beacon_payload); } //Set New Length and pointer to MAC interface->mac_parameters->mac_beacon_payload = temp_buff; interface->mac_parameters->mac_beacon_payload_size = len; return interface->mac_parameters->mac_beacon_payload; } int8_t mac_helper_beacon_payload_register(protocol_interface_info_entry_t *interface) { mac_helper_beacon_payload_set_to_mac(interface, interface->mac_parameters->mac_beacon_payload, interface->mac_parameters->mac_beacon_payload_size); mac_helper_beacon_payload_length_set_to_mac(interface, interface->mac_parameters->mac_beacon_payload_size); return 0; } uint8_t *mac_helper_beacon_payload_pointer_get(protocol_interface_info_entry_t *interface) { return interface->mac_parameters->mac_beacon_payload; } uint8_t mac_helper_beacon_payload_length_get(protocol_interface_info_entry_t *interface) { return interface->mac_parameters->mac_beacon_payload_size; } int8_t mac_helper_pib_boolean_set(protocol_interface_info_entry_t *interface, mlme_attr_t attribute, bool value) { switch (attribute) { case macSecurityEnabled: interface->mac_parameters->SecurityEnabled = value; break; case macRxOnWhenIdle: interface->mac_parameters->RxOnWhenIdle = value; break; case macPromiscuousMode: interface->mac_parameters->PromiscuousMode = value; break; case macGTSPermit: interface->mac_parameters->GTSPermit = value; break; case macAssociationPermit: interface->mac_parameters->AssociationPermit = value; break; case macAssociatedPANCoord: interface->mac_parameters->AssociatedPANCoord = value; break; case macTimestampSupported: interface->mac_parameters->TimestampSupported = value; break; case macBattLifeExt: interface->mac_parameters->BattLifeExt = value; break; case macAutoRequest: interface->mac_parameters->AutoRequest = value; break; case macThreadForceLongAddressForBeacon: break; default: return -1; } if (interface->mac_api && interface->mac_api->mlme_req) { mlme_set_t set_req; set_req.attr = attribute; set_req.attr_index = 0; set_req.value_pointer = &value; set_req.value_size = sizeof(bool); interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } return 0; } int8_t mac_helper_mac_channel_set(protocol_interface_info_entry_t *interface, uint8_t new_channel) { if (interface->mac_parameters->mac_channel != new_channel) { interface->mac_parameters->mac_channel = new_channel; if (interface->mac_api && interface->mac_api->mlme_req) { mlme_set_t set_req; set_req.attr = phyCurrentChannel; set_req.attr_index = 0; set_req.value_pointer = &new_channel; set_req.value_size = 1; interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); } } return 0; } static bool mac_helper_write_16bit(uint16_t temp16, uint8_t *addrPtr) { common_write_16_bit(temp16, addrPtr); return temp16 != 0xffff; } /* Write functions return "false" if they write an "odd" address, true if they * write a "normal" address. They still write odd addresses, as certain special * packets may want them, but this allows normal data paths to check and block * odd cases. * "Odd" is currently defined as PAN ID == 0xffff, or short address > 0xfffd. */ bool mac_helper_write_our_addr(protocol_interface_info_entry_t *interface, sockaddr_t *ptr) { bool normal = true; //Set First PANID normal &= mac_helper_write_16bit(interface->mac_parameters->pan_id, ptr->address); if (ptr->addr_type != ADDR_802_15_4_LONG && ptr->addr_type != ADDR_802_15_4_SHORT) { if (interface->mac_parameters->shortAdressValid) { ptr->addr_type = ADDR_802_15_4_SHORT; } else { ptr->addr_type = ADDR_802_15_4_LONG; } } if (ptr->addr_type == ADDR_802_15_4_SHORT) { normal &= mac_helper_write_16bit(interface->mac_parameters->mac_short_address, &ptr->address[2]); } else { memcpy(&ptr->address[2], interface->mac, 8); } return normal; } int8_t mac_helper_mac64_set(protocol_interface_info_entry_t *interface, const uint8_t *mac64) { memcpy(interface->mac, mac64, 8); if (interface->mac_api) { interface->mac_api->mac64_set(interface->mac_api, mac64); } return 0; } /* * Given a buffer, with address and security flags set, compute the maximum * MAC payload that could be put in that buffer. */ uint_fast16_t mac_helper_max_payload_size(protocol_interface_info_entry_t *cur, uint_fast16_t frame_overhead) { uint16_t max; if (test_6lowpan_fragmentation_mtu_size_override == 0) { max = cur->mac_api->phyMTU - frame_overhead; } else { max = test_6lowpan_fragmentation_mtu_size_override - frame_overhead; } /* But if we want IEEE 802.15.4-2003 compatibility (and it looks like a * standard PHY), limit ourselves to the 2003 maximum */ if (cur->mac_parameters->MacUnsusecured_2003_cab && max > MAC_IEEE_802_15_4_MAX_MAC_SAFE_PAYLOAD_SIZE && cur->mac_api->phyMTU == MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) { max = MAC_IEEE_802_15_4_MAX_MAC_SAFE_PAYLOAD_SIZE; } return max; } /* * Given a buffer, with address and security flags set, compute the MAC overhead * size once MAC header and footer are added. * May not be accurate if MAC_MAX_PHY_PACKET_SIZE isn't set, implying a * non-standard MAC. */ uint_fast8_t mac_helper_frame_overhead(protocol_interface_info_entry_t *cur, const buffer_t *buf) { uint_fast8_t length = 15; /*8bytes src address, 2 frame control, 1 sequence, 2 pan-id, 2 FCS*/ if (buf->src_sa.addr_type == ADDR_NONE) { if (cur->mac_parameters->shortAdressValid) { length -= 6; //Cut 6 bytes from src address } } else if (buf->src_sa.addr_type == ADDR_802_15_4_SHORT) { length -= 6; //Cut 6 bytes from src address } if (memcmp(buf->dst_sa.address, buf->src_sa.address, 2) == 0) { length -= 2; // Cut Pan-id } if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG) { length += 10; } else if (buf->dst_sa.addr_type == ADDR_802_15_4_SHORT || buf->dst_sa.addr_type == ADDR_BROADCAST) { length += 4; } if (cur->mac_parameters->mac_security_level && (!buf->options.ll_security_bypass_tx)) { length += mac_helper_header_security_aux_header_length(cur->mac_parameters->mac_key_id_mode); length += mac_helper_security_mic_length_get(cur->mac_parameters->mac_security_level); } return length; } static uint8_t mac_helper_security_mic_length_get(uint8_t security_level) { uint8_t mic_length; switch (security_level) { case SEC_MIC32: case SEC_ENC_MIC32: mic_length = 4; break; case SEC_MIC64: case SEC_ENC_MIC64: mic_length = 8; break; case SEC_MIC128: case SEC_ENC_MIC128: mic_length = 16; break; case SEC_NONE: case SEC_ENC: default: mic_length = 0; break; } return mic_length; } static uint8_t mac_helper_header_security_aux_header_length(uint8_t keyIdmode) { uint8_t header_length = 5; //Header + 32-bit counter switch (keyIdmode) { case MAC_KEY_ID_MODE_SRC8_IDX: header_length += 4; //64-bit key source first part /* fall through */ case MAC_KEY_ID_MODE_SRC4_IDX: header_length += 4; //32-bit key source inline /* fall through */ case MAC_KEY_ID_MODE_IDX: header_length += 1; break; default: break; } return header_length; } int8_t mac_helper_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api || !seq_ptr) { return -1; } return mac_helper_key_link_frame_counter_read(interface_id, seq_ptr, cur->mac_parameters->mac_default_key_attribute_id); } int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } return mac_helper_key_link_frame_counter_set(interface_id, seq_ptr, cur->mac_parameters->mac_default_key_attribute_id); } int8_t mac_helper_key_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr, uint8_t descriptor) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api || !seq_ptr) { return -1; } mlme_get_t get_req; get_req.attr = macFrameCounter; get_req.attr_index = descriptor; cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req); *seq_ptr = cur->mac_parameters->security_frame_counter; return 0; } int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr, uint8_t descriptor) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macFrameCounter; set_req.attr_index = descriptor; set_req.value_pointer = &seq_ptr; set_req.value_size = 4; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, uint8_t *mac64) { (void) mac64; if (!mac_api) { return; } mlme_device_descriptor_t device_desc; mlme_set_t set_req; memset(&device_desc, 0xff, sizeof(mlme_device_descriptor_t)); set_req.attr = macDeviceTable; set_req.attr_index = attribute_index; set_req.value_pointer = (void *)&device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); if (mac64) { tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); } mac_api->mlme_req(mac_api, MLME_SET, &set_req); } void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt) { memcpy(device_desc->ExtAddress, mac64, 8); device_desc->ShortAddress = mac16; device_desc->PANId = mac_helper_panid_get(cur); device_desc->Exempt = exempt; device_desc->FrameCounter = frame_counter; } void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur, uint8_t attribute_index, uint8_t keyID, bool force_set) { if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); return; } tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); mac_helper_devicetable_direct_set(cur->mac_api, device_desc, attribute_index); } void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index) { if (!mac_api) { return; } mlme_set_t set_req; set_req.attr = macDeviceTable; set_req.attr_index = attribute_index; set_req.value_pointer = (void *)device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); mac_api->mlme_req(mac_api, MLME_SET, &set_req); } int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macMaxFrameRetries; set_req.attr_index = 0; set_req.value_pointer = &mac_retry_set; set_req.value_size = 1; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } int8_t mac_helper_mac_mlme_max_csma_backoffs_set(int8_t interface_id, uint8_t csma_backoffs) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macMaxCSMABackoffs; set_req.attr_index = 0; set_req.value_pointer = &csma_backoffs; set_req.value_size = 1; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } int8_t mac_helper_mac_mlme_be_set(int8_t interface_id, uint8_t min_be, uint8_t max_be) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macMinBE; set_req.attr_index = 0; set_req.value_pointer = &min_be; set_req.value_size = 1; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); set_req.attr = macMaxBE; set_req.attr_index = 0; set_req.value_pointer = &max_be; set_req.value_size = 1; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } int8_t mac_helper_mac_mlme_data_request_restart_set(int8_t interface_id, mlme_request_restart_config_t *request_restart_config) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macRequestRestart; set_req.attr_index = 0; set_req.value_pointer = (void *)request_restart_config; set_req.value_size = sizeof(mlme_request_restart_config_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id) { protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } mlme_set_t set_req; set_req.attr = macDeviceDescriptionPanIDUpdate; set_req.attr_index = 0; set_req.value_pointer = &pan_id; set_req.value_size = sizeof(pan_id); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit) { protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->mac_api) { return -1; } uint8_t start_cca_thr[4] = {number_of_channels, default_dbm, high_limit, low_limit}; mlme_set_t set_req; set_req.attr = macCCAThresholdStart; set_req.value_pointer = &start_cca_thr; set_req.value_size = sizeof(start_cca_thr); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); /* Get CCA threshold table. Table is stored to interface structure */ mlme_get_t get_req; get_req.attr = macCCAThreshold; cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req); return 0; }