Squashed 'features/nanostack/sal-stack-nanostack/' changes from 9b3e144f5b..fb7413b846

fb7413b846 Merge branch 'release_internal' into release_external
a9f6e88978 Merge branch 'master' into release_internal
c536960fb0 DHCPv6 Server feature update
01e7e820d5 Merge pull request #2314 from ARMmbed/update_from_mbedos
c906c43a8a Fixed typo: 'lenght' in ns_crc.h
2bd05584fe Wi-sun border router DHCPv6 server address alocation update
63e4680ca3 Allow buffer_dyn to handle more data (#2311)
9b82abff03 Copy IE unicast channel function from WS info instead of FHSS configu… (#2310)
18247d546f Wi-sun RPL memory soft and hard limit update
c8560dbe01 Updated RPL default memory sof and hard limit to 2/4 from 1/2.
05aa54c464 Update MPL parameters to follow Specification
f728d55920 Support for handle CRC error which will automatically change a channel.
6b6f535828 Corrected EUI-64 address bit flip on supplicant
015f3fe60e Corrected bitfield definition
7717ef8c60 Improved initial EAPOL-key send stop logic on supplicant
4185734223 Improved EAPOL key update retry logic
8bda176445 Wi-sun boot fix
6283dfd643 DIO advertisment fix
1acec7cdcc Aro Registation and Dao update
6cde17ad9c Iotthd 3963 2 (#2301)
b9187daa62 Randomize fixed channel when making new parent selection
34d0339a4d Wi-sun address registartion update
5b3055904a Allow unicast TX to overlap with MC (#2298)
d40b1c7d01 MAC: Updated calling FHSS TX done (#2295)
aeb93a16ae Add support for bbr configuration that removes default route from DIO
9b941af4b5 Use default UC channel function in discovery, fixed BC schedule (#2284)
d65fcc6bf2 Fix Wi-SUN network name comparison (#2294)
f085132543 Made parent set size configuraple in RPL
fd11ffae1a Added HAVE_WS flag to FHSS api (#2296)
4f275005fb Implemented optimal packet size test api (#2292)
87ee16a22b Call channel change after filtered out packet
d196ffc4c5 Refactor Wi-SUN BBR stop function
35970d7ea9 Revert "Disabled temporarily tx slot check for testing purposes (#2287)" (#2289)
8cc0ff508b Disabled temporarily tx slot check for testing purposes (#2287)
e306dc5adb Removed extra ";"
5642a4fe74 Free TX failed list when FHSS deleted (#2285)
9fcf718d22 Updated FHSS optimal packet length to 300 bytes (#2282)
427743f718 ETX and Source route validation update
7b6bcca842 Added TX/RX bytes in PHY statistics (#2281)
a043f8dc30 Wi-sun FHSS Management update
2ff90e6c0f Configure TXRX slot length using given datarate (#2275)
a126cb750d ETX sampling rule update
d5cf8d52e2 Clean ARMC6/GCC compiler warnings (#2278)
807632dd94 DHCP server freed next free allocated id
fd6ce049a3 Thread Child ml16 update clear old address queue's and registered address.
99e6efac6c Neighbour remove operation update
5cd094cd1d Corrected GTK update initial EAPOL-key trickle timer
7606ee87a9 Wi-sun NS Aro registration blacklisting update
e3e5a00c55 Timed parent selection timer trigger update
71441212ea RPL DIO Multicast message update
588f202a51 Wi-Sun RPL bootstrap update
20289f675d Added periodic RPL version number increase
d8dd18d89b Added ignoring of incoming security messages and improved EAP-TLS startup
73506346ca Corrected initial EAPOL-key trickle retries
ac33518493 Wi-sun ETX and proping update
11c486f391 Implemented unregistering FHSS from MAC. FHSS deleted in ifdown call. (#2266)
eabca172af Wi-Sun Border router DHCPV server SLAAC mode enabled by default.
1d6ce9c0a4 DHCPv6 Server feature update
46aa46042d Fixed unit test's.
c65292e9eb Mac enhanced ACK pending update
11a1e1d2de Store TX start channel and black list if TX failed (#2261)
04946065e4 Adapatation layer unicast list entry free update
4481e8635a Updated trace level to info.
c9e3d8ef74 Interface down update
1f77ad6964 Updated trace levels (#2258)
1d82fd5a5d Wi-sun BBR route update fix
33c48eb647 Removed NUD messages from registered children
ec2ea92b71 Added RX and TX active times in PHY statistics (#2255)
49686ccb3c Wi-sun certification test setup update
1090430622 Trickle API update and Wi-SUN config sol state timeout update
38df5768c5 Wi-sun advertisment consistent update
81740b8b1d Wi-sun bootstarp update nad balck list trace level update
6919ba1301 Wi-sun New key index activate.
0aead9305a Wi-sun Probe functionality revert operation
4ff02f9770 Stop sending normal ACK if neighbour is Unknown.
c387fda238 NS Probe limiter accept only 2 probe at 16 seconds period.
a58c71b96b Trace level updates (#2247)
6867dd7b27 Suplicant EAP-TLS timeout is not incremented from retries
1f1c2a24fa Test purpose change.
1b99fe18df Added ETX to rpl_possible_better_candidate
3441594157 RPL parent candidate list update
96ffe92744 Adaptation layer to support multiple simultaneous unicast transmissions (#2243)
45f851997f On stop (ifdown) stores frame counters regardless of threshold
5c2fc55f0e Corrected frame counter handling on re-discovery
930741617f Added check to prevent installing new GTK to used index using GKH
385ae14284 WS bootstrap: print MAC address
2b1dfb90ed Slaac address can be recreated after root stop
74ff3cc503 Merge branch 'release_internal' into release_external
66bfd985fb Fixed trace printing warnings.
21d9c24acd DHCP server address allocated pointer init fix.
e659a01241 Fixed compile warning for may uninitialized usage.
cee8502783 Fixed trace printing warnings.
bc9f07bd49 DHCP server address allocated pointer init fix.
e3fddadccf Fixed compile warning for may uninitialized usage.
bf909d29d3 Modified bbr restart mechanism when dodagid was lost

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: fb7413b846f0052d72c506ebab2534bcafdfff60
pull/12485/head
Arto Kinnunen 2020-02-21 10:59:35 +02:00
parent 0b6ccc5816
commit 2792e61d87
95 changed files with 2328 additions and 831 deletions

View File

@ -122,9 +122,10 @@ typedef void fhss_data_tx_done(const fhss_api_t *api, bool waiting_ack, bool tx_
* @param api FHSS instance.
* @param handle Handle of the data request.
* @param frame_type Frame type of packet (Frames types are defined by FHSS api).
* @param channel Channel wanted to black list temporarily.
* @return true if frame has to be queued for retransmission, false otherwise.
*/
typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type);
typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel);
/**
* @brief Change synchronization state.

46
nanostack/fhss_test_api.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020, 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 fhss_test_api.h
* \brief
*/
#ifndef FHSS_TEST_API_H
#define FHSS_TEST_API_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Set optimal packet length
*
* \param fhss_api FHSS instance.
* \param packet_length Optimal packet length
*
* \return 0 Success
* \return -1 Failure
*/
int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length);
#ifdef __cplusplus
}
#endif
#endif // FHSS_TEST_API_H

View File

@ -161,7 +161,8 @@ typedef enum {
CHANNEL_PAGE_5 = 5, ///< Page 5
CHANNEL_PAGE_6 = 6, ///< Page 6
CHANNEL_PAGE_9 = 9, ///< Page 9
CHANNEL_PAGE_10 = 10 ///< Page 10
CHANNEL_PAGE_10 = 10, ///< Page 10
CHANNEL_PAGE_UNDEFINED ///< Undefined
} channel_page_e;
/** Modulation index */
@ -192,6 +193,10 @@ typedef struct phy_rf_statistics_s {
uint32_t crc_fails; ///< CRC failures
uint32_t tx_timeouts; ///< transmission timeouts
uint32_t rx_timeouts; ///< reception timeouts
uint64_t tx_active_time; ///< transmission active time
uint64_t rx_active_time; ///< reception active time
uint32_t tx_bytes; ///< transmitted bytes
uint32_t rx_bytes; ///< received bytes
} phy_rf_statistics_s;
/** Virtual data request */

View File

@ -67,6 +67,13 @@ extern int8_t ns_sw_mac_virtual_client_unregister(struct mac_api_s *api);
*/
extern int ns_sw_mac_fhss_register(struct mac_api_s *mac_api, struct fhss_api *fhss_api);
/**
* @brief Unregister FHSS API instance from given software MAC instance.
* @param mac_api MAC instance.
* @return 0 on success, -1 on fail.
*/
extern int ns_sw_mac_fhss_unregister(struct mac_api_s *mac_api);
/**
* @brief Request registered FHSS API instance from software MAC instance.
* @param mac_api MAC instance.

View File

@ -48,14 +48,10 @@ int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id);
/**
* Border router configuration options
*/
#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */
#define BBR_GUA_ROUTE 0x0002 /**< More specific route is added for GUA prefix */
#define BBR_BB_WAIT 0x0004 /**< Wait backbone availability before starting Wi-SUN network */
/*Deprecated configuration values */
#define BBR_GUA_C 0x0000 /**< Routable prefix is learned from the backbone */
#define BBR_GUA_SLAAC 0x0000 /**< Use SLAAC addressing in routable prefix */
#define BBR_GUA_WAIT 0x0000 /**< Wait backbone availability before startingRPL dodag */
#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */
#define BBR_GUA_ROUTE 0x0002 /**< More specific route is added for GUA prefix */
#define BBR_BB_WAIT 0x0004 /**< Wait backbone availability before starting Wi-SUN network */
#define BBR_DEFAULT_ROUTE 0x0008 /**< Add default route parameter to DIO */
/**
* Configure border router features.

View File

@ -1379,6 +1379,8 @@ static int8_t arm_6lowpan_bootstrap_down(protocol_interface_info_entry_t *cur)
}
cur->if_lowpan_security_params->mle_security_frame_counter = mle_service_security_get_frame_counter(cur->id);
mle_service_interface_receiver_handler_update(cur->id, mle_6lowpan_message_handler);
// Reset MAC for safe upper layer memory free
protocol_mac_reset(cur);
return nwk_6lowpan_down(cur);
}
#ifdef HAVE_6LOWPAN_ND
@ -1593,7 +1595,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr
{
protocol_interface_info_entry_t *cur_interface = user_data;
lowpan_adaptation_remove_free_indirect_table(cur_interface, entry_ptr);
lowpan_adaptation_neigh_remove_free_tx_tables(cur_interface, entry_ptr);
// Sleepy host
if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
mac_data_poll_protocol_poll_mode_decrement(cur_interface);

View File

@ -72,6 +72,15 @@
#include "6LoWPAN/Fragmentation/cipv6_fragmenter.h"
#include "libNET/src/net_load_balance_internal.h"
void protocol_mac_reset(protocol_interface_info_entry_t *cur)
{
if (cur->mac_api) {
mlme_reset_t reset;
reset.SetDefaultPIB = true;
cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset);
}
}
static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur)
@ -96,15 +105,11 @@ static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur)
}
if (cur->interface_mode == INTERFACE_UP) {
if (cur->mac_api) {
mlme_reset_t reset;
reset.SetDefaultPIB = true;
cur->mac_parameters->pan_id = 0xffff;
cur->mac_parameters->SecurityEnabled = false;
cur->mac_parameters->security_frame_counter = 0;
cur->mac_parameters->mac_security_level = 0;
cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset);
}
cur->mac_parameters->pan_id = 0xffff;
cur->mac_parameters->SecurityEnabled = false;
cur->mac_parameters->security_frame_counter = 0;
cur->mac_parameters->mac_security_level = 0;
protocol_mac_reset(cur);
cur->interface_mode = INTERFACE_IDLE;
net_load_balance_internal_state_activate(cur, false);
}

View File

@ -31,5 +31,7 @@ extern int8_t nwk_6lowpan_up(struct protocol_interface_info_entry *cur);
*/
extern int8_t nwk_6lowpan_down(struct protocol_interface_info_entry *cur);
extern void protocol_mac_reset(struct protocol_interface_info_entry *cur);
#endif /* PROTOCOL_6LOWPAN_INTERFACE_H_ */

View File

@ -887,6 +887,7 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p
void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, uint8_t *mac64)
{
(void) mac64;
if (!mac_api) {
return;
}

View File

@ -120,6 +120,7 @@ void mcps_data_indication_handler(const mac_api_t *api, const mcps_data_ind_t *d
void mcps_purge_confirm_handler(const mac_api_t *api, mcps_purge_conf_t *data)
{
(void)api;
(void)data;
tr_info("MCPS Data Purge confirm status %u, for handle %u", data->status, data->msduHandle);
}

View File

@ -856,9 +856,6 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac
mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh), ADDR_802_15_4_LONG);
if (entry) {
if (ws_info(cur_interface)) {
ws_common_etx_validate(cur_interface, entry);
}
if (!entry->ffd_device) {
rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime);
@ -931,11 +928,13 @@ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uin
}
/* TODO - check hard upper limit on registrations? */
if (ws_info(cur_interface) &&
!ws_common_allow_child_registration(cur_interface, aro_out->eui64)) {
aro_out->present = true;
aro_out->status = ARO_FULL;
return true;
if (ws_info(cur_interface)) {
aro_out->status = ws_common_allow_child_registration(cur_interface, aro_out->eui64);
if (aro_out->status != ARO_SUCCESS) {
aro_out->present = true;
return true;
}
}
/* We need to have entry in the Neighbour Cache */
@ -1757,6 +1756,8 @@ void nd_6lowpan_set_radv_params(protocol_interface_info_entry_t *cur_interface)
cur_interface->adv_retrans_timer = nd_params.ra_retrans_timer;
cur_interface->max_initial_rtr_adv_interval = nd_params.ra_interval_min;
cur_interface->max_initial_rtr_advertisements = nd_params.ra_transmits;
#else
(void) cur_interface;
#endif
}
#endif // HAVE_6LOWPAN_ND

View File

@ -137,7 +137,7 @@ static void thread_bootstrap_pbbr_update_done(struct protocol_interface_info_ent
static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
{
protocol_interface_info_entry_t *cur = user_data;
lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr);
lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr);
thread_reset_neighbour_info(cur, entry_ptr);
//Removes ETX neighbor

View File

@ -240,6 +240,8 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur)
tr_debug("SET thread Idle");
//stop polling
mac_data_poll_disable(cur);
// Reset MAC for safe upper layer memory free
protocol_mac_reset(cur);
//Clean mle table
thread_neighbor_list_clean(cur);
// store frame counters

View File

@ -699,7 +699,7 @@ int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t *
return -1;
}
return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous);
return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous, false);
#else
(void) interface_id;
(void) prefix_ptr;

View File

@ -285,7 +285,7 @@ static void thread_update_mle_entry(protocol_interface_info_entry_t *cur, mle_me
if (short_address != entry_temp->mac16) {
if (thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) {
thread_dynamic_storage_child_info_clear(cur->id, entry_temp);
protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16);
}
entry_temp->mac16 = short_address;
/* throw MLME_GET request, short address is changed automatically in get request callback */

View File

@ -64,6 +64,7 @@
#include "Common_Protocols/icmpv6_radv.h"
#include "MLE/mle.h"
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
#include "6LoWPAN/lowpan_adaptation_interface.h"
#include "6LoWPAN/MAC/mac_helper.h"
#define TRACE_GROUP "tsyn"
@ -192,15 +193,29 @@ void thread_dynamic_storage_child_info_store(protocol_interface_info_entry_t *cu
void thread_dynamic_storage_child_info_clear(int8_t interface_id, struct mac_neighbor_table_entry *child)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return;
}
thread_sync_child_info_t *child_info = thread_dynamic_storage_child_info_find(interface_id, child);
if (child_info) {
// Clear child information
memset(child_info, 0, sizeof(thread_sync_child_info_t));
tr_debug("Dynamic storage: cleared child; mac16=%04x", child->mac16);
return;
}
return;
uint8_t temp_address[2];
common_write_16_bit(child->mac16, temp_address);
//Release Old short address entries
lowpan_adaptation_free_messages_from_queues_by_address(cur, temp_address, ADDR_802_15_4_SHORT);
/* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache
* mapping to that address, it is no longer valid. We must have been their parent, and they must be
* finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not
* invalidate our IP->16-bit mapping.)
*/
protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16);
}
static thread_sync_child_info_t *thread_dynamic_storage_child_info_find(int8_t interface_id, mac_neighbor_table_entry_t *child)

View File

@ -969,13 +969,6 @@ int thread_router_bootstrap_reset_child_info(protocol_interface_info_entry_t *cu
tr_debug("Child free %x", child->mac16);
thread_dynamic_storage_child_info_clear(cur->id, child);
/* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache
* mapping to that address, it is no longer valid. We must have been their parent, and they must be
* finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not
* invalidate our IP->16-bit mapping.)
*/
protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16);
// If Child's RLOC16 appears in the Network Data send the RLOC16 to the Leader
if (thread_network_data_services_registered(&cur->thread_info->networkDataStorage, child->mac16)) {
tr_debug("Remove references to Child's RLOC16 from the Network Data");
@ -1824,7 +1817,6 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
// Was this previously our child? If yes, update.
if ((entry_temp->mac16 & THREAD_CHILD_MASK) && thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) {
thread_dynamic_storage_child_info_clear(cur->id, entry_temp);
protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16);
}
update_mac_mib = true;
entry_temp->mac16 = shortAddress; // short address refreshed

View File

@ -643,11 +643,10 @@ int thread_test_version_set(int8_t interface_id, uint8_t version)
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count)
{
#ifdef HAVE_THREAD
#if defined(HAVE_THREAD) && defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER)
(void)interface_id;
thread_bbr_commercial_status_override_set(dua_status, dua_count, ba_failure_count);
return 0;
#else
(void)interface_id;
(void)dua_status;

View File

@ -89,8 +89,8 @@ typedef struct {
fragmenter_tx_list_t indirect_tx_queue;
uint8_t *fragment_indirect_tx_buffer; //Used for write fragmentation header
uint16_t mtu_size;
fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process
fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process
fragmenter_tx_list_t activeUnicastList; //Unicast packets waiting data confirmation from MAC
buffer_list_t directTxQueue; //Waiting free tx process
uint16_t directTxQueue_size;
uint16_t indirect_big_packet_threshold;
@ -110,7 +110,7 @@ static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t inter
/* Interface direct message pending queue functions */
static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr, buffer_t *buf);
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur);
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr);
/* Data direction and message length validation */
static bool lowpan_adaptation_indirect_data_request(mac_neighbor_table_entry_t *mle_entry);
@ -126,7 +126,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf
/* Tx confirmation local functions */
static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf);
static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event);
static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status);
static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr);
@ -138,6 +138,8 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf
static fragmenter_tx_entry_t *lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr);
static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf);
static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm)
{
switch (confirm->status) {
@ -221,18 +223,14 @@ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_p
protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
}
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur)
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr)
{
/* Currently this function is called only when data confirm is received for previously sent packet.
* Data confirm has freed the corresponding "active buffer" and this function will look for new buffer to be set as active buffer.
*/
// Currently this function is called only when data confirm is received for previously sent packet.
if (!interface_ptr->directTxQueue_size) {
return NULL;
}
ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) {
bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
//Check that we not trig second active fragmentation process
if (fragmented_needed && interface_ptr->fragmenter_active) {
tr_debug("Do not trig Second active fragmentation");
} else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf)
|| (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) {
if (lowpan_buffer_tx_allowed(interface_ptr, buf)) {
ns_list_remove(&interface_ptr->directTxQueue, buf);
interface_ptr->directTxQueue_size--;
protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
@ -292,7 +290,7 @@ static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf)
static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
{
ns_list_foreach(fragmenter_tx_entry_t, entry, indirect_tx_queue) {
if (entry->buf->seq == handle) {
@ -310,9 +308,9 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int
uint8_t handle;
while (!valid_info) {
handle = interface_ptr->msduHandle++;
if (!lowpan_active_tx_handle_verify(handle, interface_ptr->active_unicast_tx_buf.buf)
if (!lowpan_listed_tx_handle_verify(handle, &interface_ptr->activeUnicastList)
&& !lowpan_active_tx_handle_verify(handle, interface_ptr->active_broadcast_tx_buf.buf)
&& !lowpan_indirect_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
&& !lowpan_listed_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
valid_info = true;
}
}
@ -320,7 +318,7 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int
}
static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry)
static void lowpan_list_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry)
{
ns_list_remove(list, entry);
if (entry->buf) {
@ -330,11 +328,15 @@ static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx
ns_dyn_mem_free(entry);
}
static void lowpan_indirect_queue_free(fragmenter_tx_list_t *list)
static void lowpan_list_free(fragmenter_tx_list_t *list, bool fragment_buf_free)
{
while (!ns_list_is_empty(list)) {
fragmenter_tx_entry_t *entry = ns_list_get_first(list);
lowpan_indirect_entry_free(list, entry);
if (!fragment_buf_free) {
//We can't free this pointer becuase it must be until interface is deleted
entry->fragmenter_buf = NULL;
}
lowpan_list_entry_free(list, entry);
}
}
@ -365,6 +367,7 @@ int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_si
ns_list_init(&interface_ptr->indirect_tx_queue);
ns_list_init(&interface_ptr->directTxQueue);
ns_list_init(&interface_ptr->activeUnicastList);
ns_list_add_to_end(&fragmenter_interface_list, interface_ptr);
@ -389,11 +392,11 @@ int8_t lowpan_adaptation_interface_free(int8_t interface_id)
ns_list_remove(&fragmenter_interface_list, interface_ptr);
//free active tx process
lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
lowpan_list_free(&interface_ptr->activeUnicastList, false);
lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
//Free Indirect entry
lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
buffer_free_list(&interface_ptr->directTxQueue);
@ -414,13 +417,13 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
}
//free active tx process
lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
lowpan_list_free(&interface_ptr->activeUnicastList, false);
lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
//Clean fragmented message flag
interface_ptr->fragmenter_active = false;
//Free Indirect entry
lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
lowpan_list_free(&interface_ptr->indirect_tx_queue, true);
buffer_free_list(&interface_ptr->directTxQueue);
@ -588,10 +591,15 @@ static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry
static fragmenter_tx_entry_t *lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast)
{
// For broadcast, the active TX queue is only 1 entry. For unicast, using a list.
fragmenter_tx_entry_t *tx_entry;
if (!indirect) {
if (is_unicast) {
tx_entry = &interface_ptr->active_unicast_tx_buf;
tx_entry = lowpan_indirect_entry_allocate(0);
if (!tx_entry) {
return NULL;
}
ns_list_add_to_end(&interface_ptr->activeUnicastList, tx_entry);
} else {
tx_entry = &interface_ptr->active_broadcast_tx_buf;
}
@ -936,6 +944,40 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf
}
}
static bool lowpan_adaptation_is_destination_tx_active(fragmenter_tx_list_t *list, buffer_t *buf)
{
ns_list_foreach(fragmenter_tx_entry_t, entry, list) {
if (entry->buf) {
if (!memcmp(&entry->buf->dst_sa.address[2], &buf->dst_sa.address[2], 8)) {
return true;
}
}
}
return false;
}
static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf)
{
bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
// Indirect allowed always
if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
return true;
}
// Do not accept any other TX when fragmented TX active. Prevents other frames to be sent in between two fragments.
if (interface_ptr->fragmenter_active) {
return false;
}
// Do not accept more than one active broadcast TX
if (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf) {
return false;
}
// Do not accept more than one active unicast TX per destination
if (is_unicast && lowpan_adaptation_is_destination_tx_active(&interface_ptr->activeUnicastList, buf)) {
return false;
}
return true;
}
int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf)
{
bool is_room_for_new_message;
@ -956,11 +998,10 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;
if (!indirect) {
if (((is_unicast && interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf)) || (fragmented_needed && interface_ptr->fragmenter_active)) {
lowpan_adaptation_tx_queue_write(interface_ptr, buf);
return 0; //Return here
}
if (!lowpan_buffer_tx_allowed(interface_ptr, buf)) {
lowpan_adaptation_tx_queue_write(interface_ptr, buf);
return 0;
}
//Allocate Handle
@ -1107,10 +1148,14 @@ static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr)
static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event)
{
buffer_t *buf = tx_ptr->buf;
tx_ptr->buf = NULL;
if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
//release from list and free entry
lowpan_indirect_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
lowpan_list_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
} else if (buf->link_specific.ieee802_15_4.requestAck) {
ns_list_remove(&interface_ptr->activeUnicastList, tx_ptr);
ns_dyn_mem_free(tx_ptr);
}
socket_tx_buffer_event_and_free(buf, socket_event);
@ -1131,18 +1176,19 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
//Check first
fragmenter_tx_entry_t *tx_ptr;
bool active_direct_confirm;
bool is_unicast = true;
if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_unicast_tx_buf.buf)) {
active_direct_confirm = true;
tx_ptr = &interface_ptr->active_unicast_tx_buf;
} else if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) {
if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) {
active_direct_confirm = true;
tx_ptr = &interface_ptr->active_broadcast_tx_buf;
is_unicast = false;
} else {
active_direct_confirm = false;
tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->activeUnicastList);
if (tx_ptr) {
active_direct_confirm = true;
} else {
tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
if (tx_ptr) {
active_direct_confirm = false;
}
}
}
if (!tx_ptr) {
@ -1214,7 +1260,7 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
}
#ifdef HAVE_RPL
if (confirm->status == MLME_TX_NO_ACK) {
if (confirm->status == MLME_TX_NO_ACK || confirm->status == MLME_UNAVAILABLE_KEY) {
if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) {
protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1);
}
@ -1232,14 +1278,15 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c
break;
}
if ((is_unicast && !interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && !interface_ptr->active_broadcast_tx_buf.buf)) {
//Read Buffer and trig next direct request
lowpan_adaptation_interface_tx(cur, lowpan_adaptation_tx_queue_read(interface_ptr, cur));
// When confirmation is for direct transmission, push all allowed buffers to MAC
if (active_direct_confirm == true) {
buffer_t *buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr);
while (buf_from_queue) {
lowpan_adaptation_interface_tx(cur, buf_from_queue);
buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr);
}
}
return 0;
}
static bool mac_data_is_broadcast_addr(const sockaddr_t *addr)
@ -1332,7 +1379,7 @@ bool lowpan_adaptation_tx_active(int8_t interface_id)
{
fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
if (!interface_ptr || (!interface_ptr->active_unicast_tx_buf.buf && !interface_ptr->active_broadcast_tx_buf.buf)) {
if (!interface_ptr || (!ns_list_count(&interface_ptr->activeUnicastList) && !interface_ptr->active_broadcast_tx_buf.buf)) {
return false;
}
return true;
@ -1399,19 +1446,19 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf
return true;
}
void lowpan_adaptation_remove_free_indirect_table(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr)
void lowpan_adaptation_neigh_remove_free_tx_tables(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr)
{
//Free first by defined short address
if (entry_ptr->mac16 < 0xfffe) {
uint8_t temp_address[2];
common_write_16_bit(entry_ptr->mac16, temp_address);
lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT);
lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT);
}
lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG);
lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG);
}
int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type)
int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type)
{
fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
@ -1427,9 +1474,18 @@ int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct pr
}
}
//Check next direct queue
ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->activeUnicastList) {
if (lowpan_tx_buffer_address_compare(&entry->buf->dst_sa, address_ptr, adr_type)) {
//Purge from mac
lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, entry);
}
}
return 0;
}
int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child)
{
fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);

View File

@ -51,9 +51,9 @@ struct buffer *lowpan_adaptation_reassembly(struct protocol_interface_info_entry
bool lowpan_adaptation_tx_active(int8_t interface_id);
void lowpan_adaptation_remove_free_indirect_table(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr);
void lowpan_adaptation_neigh_remove_free_tx_tables(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr);
int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type);
int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type);
int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child);

View File

@ -45,10 +45,10 @@
#define RPL_INSTANCE_ID 1
static uint8_t current_instance_id = RPL_INSTANCE_ID;
#ifdef HAVE_WS_BORDER_ROUTER
static uint8_t current_instance_id = RPL_INSTANCE_ID;
#define WS_ULA_LIFETIME 24*3600
#define WS_ROUTE_LIFETIME WS_ULA_LIFETIME
#define WS_DHCP_ADDRESS_LIFETIME 2*3600
@ -85,7 +85,27 @@ static rpl_dodag_conf_t rpl_conf = {
.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY
};
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase)
static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version)
{
// Set the next timeout value for version update
if (version < 128) {
//stable version for RPL so slow timer update is ok
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME;
} else {
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART;
}
}
static void ws_bbr_rpl_version_increase(protocol_interface_info_entry_t *cur)
{
if (!protocol_6lowpan_rpl_root_dodag) {
return;
}
ws_bbr_rpl_version_timer_start(cur, rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag));
}
void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase)
{
if (imin == 0 || doubling == 0) {
// use default values
@ -111,11 +131,11 @@ void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint1
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf);
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
ws_bbr_rpl_version_increase(cur);
}
}
static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id)
{
tr_info("RPL root start");
rpl_data_init_root();
@ -123,7 +143,6 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
}
protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, current_instance_id, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0));
@ -133,19 +152,20 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
}
// RPL memory limits set larger for Border router
rpl_control_set_memory_limits(64 * 1024, 0);
// Initial version number for RPL start is 240 from RPL RFC
ws_bbr_rpl_version_timer_start(cur, 240);
}
static void ws_bbr_rpl_root_stop(void)
{
tr_info("RPL root stop");
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
}
memset(current_local_prefix, 0, 8);
memset(current_global_prefix, 0, 8);
memset(current_dodag_id, 0, 16);
}
static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address)
@ -177,11 +197,24 @@ int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handl
static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix)
{
if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
if_address_entry_t *add_entry = NULL;
const uint8_t *address;
address = addr_select_with_prefix(cur, ula_prefix, 64, 0);
if (address) {
// Address already exists for this prefix find the entry
add_entry = addr_get_entry(cur, address);
}
if (!add_entry) {
add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
}
if (!add_entry) {
tr_err("ula create failed");
return NULL;
}
// Set the timeouts for this address and policy
icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0xffffffff, 0xffffffff);
addr_policy_table_add_entry(ula_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
return add_entry;
}
@ -307,9 +340,11 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8
return;
}
DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb);
DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true);
//Enable SLAAC mode to border router
DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false);
DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME);
//SEt max value for not limiting address allocation
DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE);
ws_dhcp_client_address_request(cur, global_id, ll);
}
@ -325,6 +360,31 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_
}
static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur)
{
tr_info("BBR routing stop");
if (memcmp(current_local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
ws_bbr_slaac_remove(cur, current_local_prefix);
memset(current_local_prefix, 0, 8);
}
if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) {
ws_bbr_dhcp_server_stop(cur, current_global_prefix);
if (backbone_interface_id >= 0) {
// Delete route to backbone if it exists
ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0, 0);
}
memset(current_global_prefix, 0, 8);
}
if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 8) != 0) {
ws_bbr_slaac_remove(cur, current_dodag_id);
memset(current_dodag_id, 0, 16);
}
ws_bbr_rpl_root_stop();
}
static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
{
@ -339,7 +399,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
if (!protocol_6lowpan_rpl_root_dodag) {
// Generate DODAGID
if (ws_bbr_static_dodagid_create(cur) == 0) {
ws_bbr_rpl_root_start(current_dodag_id);
ws_bbr_rpl_root_start(cur, current_dodag_id);
}
}
@ -354,9 +414,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
*/
if (protocol_interface_address_compare(current_dodag_id) != 0) {
//DODAGID is lost need to restart
tr_warn("DODAGID lost restart RPL");
memset(current_dodag_id, 0, 16);
ws_bbr_rpl_root_stop();
tr_warn("DODAGID lost restart BBR");
ws_bbr_routing_stop(cur);
return;
}
@ -366,7 +425,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
/*
* Add default route to RPL
*/
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false);
if (configuration & BBR_DEFAULT_ROUTE) {
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false);
}
/*
* Create static ULA configuration or modify if needed
@ -384,6 +445,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
if (memcmp(local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
if (!ws_bbr_slaac_generate(cur, local_prefix)) {
// Address creation failed
return;
}
@ -425,8 +487,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
if (configuration & BBR_GUA_ROUTE) {
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, true);
}
ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0);
if (backbone_interface_id >= 0) {
ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0);
}
ws_bbr_dhcp_server_stop(cur, current_global_prefix);
}
// TODO add global prefix
@ -435,9 +498,11 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
tr_info("RPL global prefix activate %s", trace_ipv6_prefix(global_prefix, 64));
// Add default route to RPL
// Enable default routing to backbone
if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) {
tr_err("global route add failed");
return;
if (backbone_interface_id >= 0) {
if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) {
tr_err("global route add failed");
return;
}
}
ws_bbr_dhcp_server_start(cur, global_prefix);
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false);
@ -450,7 +515,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
}
memcpy(current_global_prefix, global_prefix, 8);
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
ws_bbr_rpl_version_increase(cur);
nd_proxy_downstream_interface_register(cur->id, ws_border_router_proxy_validate, ws_border_router_proxy_state_update);
} else if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) {
/*
@ -511,7 +577,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
if (cur->ws_info->pan_version_timer > seconds) {
cur->ws_info->pan_version_timer -= seconds;
} else {
// Border router has timed out
// PAN version number update
tr_debug("Border router version number update");
cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config);
cur->ws_info->pan_information.pan_version++;
@ -522,9 +588,13 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
ws_common_network_size_configure(cur, cur->ws_info->pan_information.pan_size);
}
}
if (cur->ws_info->rpl_version_timer > seconds) {
cur->ws_info->rpl_version_timer -= seconds;
} else {
// RPL version update needed
ws_bbr_rpl_version_increase(cur);
}
}
}
uint16_t test_pan_size_override = 0xffff;
@ -607,15 +677,11 @@ void ws_bbr_stop(int8_t interface_id)
{
#ifdef HAVE_WS_BORDER_ROUTER
(void)interface_id;
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
ws_bbr_routing_stop(cur);
backbone_interface_id = -1;
if (!protocol_6lowpan_rpl_domain) {
return;
}
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
#else
@ -626,11 +692,12 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options)
{
#ifdef HAVE_WS_BORDER_ROUTER
(void)interface_id;
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (protocol_6lowpan_rpl_root_dodag &&
options != configuration) {
//Configuration changed delete previous setup
ws_bbr_rpl_root_stop();
ws_bbr_routing_stop(cur);
}
configuration = options;
return 0;

View File

@ -27,7 +27,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur);
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
@ -36,7 +36,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
#define ws_bbr_seconds_timer( cur, seconds)
#define ws_bbr_pan_size(cur) 0
#define ws_bbr_rpl_config( imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
#define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
#define ws_bbr_ready_to_start(cur) true
#endif //HAVE_WS_BORDER_ROUTER

View File

@ -97,7 +97,6 @@ static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data);
static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface);
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
@ -202,7 +201,7 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
{
if (cur->bootStrapId < 0) {
cur->bootStrapId = eventOS_event_handler_create(&ws_bootstrap_event_handler, WS_INIT_EVENT);
tr_debug("WS tasklet init");
tr_info("WS tasklet init");
}
if (cur->bootStrapId < 0) {
@ -321,12 +320,16 @@ static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighb
}
}
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor)
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor, bool nud_process)
{
//Send NS
uint8_t ll_target[16];
ws_bootsrap_create_ll_address(ll_target, neighbor->mac64);
tr_info("NUD generate NS %u", neighbor->index);
if (nud_process) {
tr_info("NUD generate NS %u", neighbor->index);
} else {
tr_info("Probe generate NS %u", neighbor->index);
}
buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL);
if (buffer) {
protocol_push(buffer);
@ -368,7 +371,7 @@ void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks)
} else {
//Random TX wait period is over
entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info);
entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info, entry->nud_process);
if (!entry->wait_response) {
if (entry->nud_process && entry->retry_count < 2) {
entry->timer = randLIB_get_random_in_range(1, 900);
@ -409,7 +412,8 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry
memcpy(cur->ws_info->hopping_schdule.channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8);
cur->ws_info->hopping_schdule.uc_fixed_channel = fhss_configuration->unicast_fixed_channel;
cur->ws_info->hopping_schdule.bc_fixed_channel = fhss_configuration->broadcast_fixed_channel;
cur->ws_info->hopping_schdule.uc_channel_function = fhss_configuration->ws_uc_channel_function;
// Read UC channel function from WS info because FHSS might be temporarily configured to fixed channel during discovery.
cur->ws_info->hopping_schdule.uc_channel_function = cur->ws_info->fhss_uc_channel_function;
cur->ws_info->hopping_schdule.bc_channel_function = fhss_configuration->ws_bc_channel_function;
cur->ws_info->hopping_schdule.fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval;
cur->ws_info->hopping_schdule.fhss_broadcast_interval = fhss_configuration->fhss_broadcast_interval;
@ -420,8 +424,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry
static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
{
fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
if (!fhss_api || (fhss_api && cur->ws_info->fhss_owner)) {
if (!fhss_api) {
// When FHSS doesn't exist yet, create one
fhss_ws_configuration_t fhss_configuration;
memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
@ -437,26 +440,11 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function;
fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval;
fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval;
fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
if (!fhss_api) {
fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
if (!fhss_api) {
tr_error("fhss create failed");
return -1;
}
ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
cur->ws_info->fhss_owner = true;
} else {
//Configuration set
ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
} else {
//Clear OWN HOP
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
}
return -1;
}
ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
} else {
// Read defaults from the configuration to help FHSS testing
const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api);
@ -519,7 +507,7 @@ static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, ui
}
}
static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
static int8_t ws_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery)
{
// Read configuration of existing FHSS and start using the default values for any network
fhss_ws_configuration_t fhss_configuration;
@ -528,8 +516,12 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) {
memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
}
fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL;
// Discovery is done using fixed channel
if (discovery) {
fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL;
} else {
fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function;
}
fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL;
fhss_configuration.fhss_broadcast_interval = 0;
uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
@ -641,8 +633,9 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr
mac64[0] |= 2; //Set Local Bit
mac64[0] &= ~1; //Clear multicast bit
tr_info("Generated random MAC %s", trace_array(mac64, 8));
tr_info("Generated random MAC address");
}
tr_info("MAC address: %s", trace_array(mac64, 8));
mac_helper_mac64_set(cur, mac64);
memcpy(cur->iid_eui64, mac64, 8);
@ -660,7 +653,6 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr
uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *addr_ptr)
{
uint16_t etx;
if (!addr_ptr || !interface) {
return 0;
}
@ -675,42 +667,11 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
ws_neighbor_class_entry_t *ws_neighbour = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, attribute_index);
etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, attribute_index);
if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (!ws_neighbour || !etx_entry) {
return 0xffff;
}
} else {
if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*||
!ws_neighbour->candidate_parent*/) {
// if RSL value is not good enough candidate parent flag is removed and device not accepted as parent
//tr_debug("ws_etx_read not valid params");
return 0xffff;
}
//If we are not following gbobal Broadcast synch
if (!interface->ws_info->pan_information.use_parent_bs) {
//We must know both information's here
if (!ws_neighbour->broadcast_shedule_info_stored ||
!ws_neighbour->broadcast_timing_info_stored) {
return 0xffff;
}
} else {
if (!ws_neighbour->broadcast_timing_info_stored) {
//Global shedule is stored already
tr_debug("ws_etx_read not valid NO BTI");
return 0xffff;
}
}
}
etx = etx_local_etx_read(interface->id, attribute_index);
if (etx == 0) {
if (!ws_neighbour || !etx_entry) {
return 0xffff;
}
//tr_debug("ws_etx_read etx:%d", etx);
return etx;
return etx_local_etx_read(interface->id, attribute_index);
}
bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry, bool unicast, uint8_t seq)
{
@ -759,6 +720,8 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
goto cleanup;
}
/* Wi-sun will trig event for stamechine this timer must be zero on init */
cur->bootsrap_state_machine_cnt = 0;
/* Disable SLLAO send/mandatory receive with the ARO */
cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true;
/* Omit sending of NA if ARO SUCCESS */
@ -803,8 +766,12 @@ static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur)
return -1;
}
tr_debug("Wi-SUN ifdown");
tr_info("Wi-SUN ifdown");
// Reset MAC for safe upper layer memory free
protocol_mac_reset(cur);
ns_sw_mac_fhss_unregister(cur->mac_api);
ns_fhss_delete(cur->ws_info->fhss_api);
cur->ws_info->fhss_api = NULL;
// Reset WS information
// ws_common_reset(cur)
ws_llc_reset(cur);
@ -862,19 +829,26 @@ void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur)
static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr)
{
ws_wp_network_name_t network_name;
if (!network_name_ptr || !ie_ext) {
return false;
}
ws_wp_network_name_t network_name;
if (!ws_wp_nested_network_name_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &network_name)) {
tr_warn("No network name IE");
return false;
}
if (network_name_ptr == NULL || strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) {
if (network_name.network_name_length != strlen(network_name_ptr)) {
return false;
}
if (strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) {
return false;
}
// names have equal length and same characters
return true;
}
@ -894,10 +868,15 @@ static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interf
* that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node.
*
*/
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
//Border router never set consistent that will guarantee that BR will send advertisment
return;
}
#ifdef WISUN_1_0_ERRATA_FIX
// All messages are considered as consistent only Solicit will cause inconsistent
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) {
//If same pan size information then set consistent value
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
}
#else
// Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements
if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) {
@ -1189,7 +1168,7 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter
if (ws_bootstrap_state_discovery(cur) &&
cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) {
cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
}
}
@ -1460,8 +1439,13 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message)
{
ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1);
(void)interface;
(void)asynch_message;
if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (asynch_message == WS_FT_PAN_CONF && interface->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ACTIVATE) {
interface->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
tr_info("Activate new default key %u", interface->ws_info->pending_key_index_info.index + 1);
mac_helper_security_auto_request_key_index_set(interface, interface->ws_info->pending_key_index_info.index, interface->ws_info->pending_key_index_info.index + 1);
}
}
}
uint32_t ws_time_from_last_unicast_traffic(uint32_t current_time_stamp, ws_neighbor_class_entry_t *ws_neighbor)
@ -1495,7 +1479,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
continue;
}
if (cur->nud_active || ws_neighbor->accelerated_etx_probe || ws_neighbor->negative_aro_send) {
if (cur->nud_active || ws_neighbor->negative_aro_send) {
//If NUD process is active do not trig
continue;
}
@ -1589,30 +1573,11 @@ static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_en
return true;
}
static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface)
{
uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false);
//TODO check bootstarap state for review
//if we have enough candidates at list do not accept new multicast neighbours
if (parent_candidate_size > interface->ws_info->rpl_parent_candidate_max) {
return false;
}
parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true);
//If we have already enough parent selected Candidates count is bigger than configured
if (parent_candidate_size >= interface->ws_info->rpl_selected_parent_max) {
return false;
}
return true;
}
static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
{
protocol_interface_info_entry_t *cur = user_data;
lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr);
lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr);
// Sleepy host
if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
mac_data_poll_protocol_poll_mode_decrement(cur);
@ -1634,6 +1599,8 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data)
{
uint32_t time_from_start = entry_ptr->link_lifetime - entry_ptr->lifetime;
uint8_t ll_address[16];
bool nud_proces = false;
bool activate_nud = false;
protocol_interface_info_entry_t *cur = user_data;
@ -1644,17 +1611,22 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
return false;
}
uint8_t ll_address[16];
ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) {
ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
if (ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) {
// This is our child with valid ARO registration Change link timeout to future we check at 2 minute intervals
entry_ptr->lifetime = entry_ptr->lifetime + 120;
if (entry_ptr->lifetime > entry_ptr->link_lifetime) {
entry_ptr->lifetime = entry_ptr->link_lifetime;
}
return false;
}
if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
if (!ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) {
//NUD Not needed for if neighbour is not child or parent candidate
return false;
}
//NUD Not needed for if neighbour is not parent candidate
return false;
}
if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) {
@ -1666,33 +1638,29 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
activate_nud = true;
}
}
} else if (etx_entry->etx_samples < WS_NEIGBOR_ETX_SAMPLE_MAX) {
nud_proces = activate_nud;
} else if (etx_entry->etx_samples < WS_NEIGHBOR_ETX_SAMPLE_MAX) {
//Take Random number for trig a prope.
//ETX Sample 0: random 1-8
//ETX Sample 1: random 2-16
//ETX Sample 2: random 4-32
if (etx_entry->etx_samples == 0 && ws_neighbor->accelerated_etx_probe) {
//Accept quick Probe for init ETX
ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
if (!rpl_control_probe_parent_candidate(cur, ll_address)) {
return false;
}
uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples;
uint32_t time_block = 1 << etx_entry->etx_samples;
if (time_from_start >= probe_period) {
//tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples);
activate_nud = true;
} else {
ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64);
if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
return false;
}
uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples;
uint32_t time_block = 1 << etx_entry->etx_samples;
if (time_from_start >= probe_period) {
//tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples);
} else if (time_from_start > time_block) {
uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1);
//Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5
if (switch_prob < 2) {
//tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples);
activate_nud = true;
} else if (time_from_start > time_block) {
uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1);
//Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5
if (switch_prob < 2) {
//tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples);
activate_nud = true;
}
}
}
}
@ -1706,14 +1674,9 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
return false;
}
entry->neighbor_info = entry_ptr;
if (ws_neighbor->accelerated_etx_probe) {
ws_neighbor->accelerated_etx_probe = false;
entry->timer = 1;
}
if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) {
entry->nud_process = true;
}
entry->nud_process = nud_proces;
return true;
}
@ -1746,12 +1709,13 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) {
return -1;
}
if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) {
if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT, WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT)) {
etx_storage_list_allocate(cur->id, 0);
return -1;
}
etx_max_update_set(WS_ETX_MAX_UPDATE);
etx_max_set(WS_ETX_MAX);
if (blacklist_init() != 0) {
tr_err("MLE blacklist init failed.");
@ -2148,7 +2112,22 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t
}
}
static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle)
static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance)
{
//Already many candidates
if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->rpl_parent_candidate_max) {
return false;
}
//Already enough selected candidates
if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->rpl_selected_parent_max) {
return false;
}
return true;
}
static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank)
{
protocol_interface_info_entry_t *cur = handle;
@ -2156,26 +2135,102 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl
return false;
}
uint8_t mac64[8];
if (blacklist_reject(ll_parent_address)) {
// Rejected by blacklist
return false;
}
uint8_t mac64[10];
//bool replace_ok = false;
//bool create_ok = false;
llc_neighbour_req_t neigh_buffer;
//Discover neigh ready here for possible ETX validate
memcpy(mac64, ll_parent_address + 8, 8);
mac64[0] ^= 2;
llc_neighbour_req_t neigh_buffer;
if (ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false)) {
ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false);
//Discover Multicast temporary entry for create neighbour table entry for new candidate
ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
if (!ws_rpl_candidate_soft_filtering(cur, instance)) {
if (!neigh_buffer.neighbor) {
//Do not accept any new in that Place
return false;
}
uint8_t replacing[16];
//Accept Know neighbour if it is enough good
if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) {
return false;
}
// +2 Is for PAN ID space
memcpy(mac64 + 2, replacing + 8, 8);
mac64[2] ^= 2;
if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) {
//Not proped yet because ETX is 0xffff
return false;
}
uint16_t etx = 0;
if (neigh_buffer.neighbor) {
etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index);
}
// Accept now only better one's when max candidates selected and max candidate list size is reached
return rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx);
}
//Neighbour allready
if (neigh_buffer.neighbor) {
return true;
}
if (!ws_rpl_dio_new_parent_accept(cur)) {
#if 0
if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) {
return false;
}
//Discover Multicast temporary entry
// +2 Is for PAN ID space
memcpy(mac64 + 2, replacing + 8, 8);
mac64[2] ^= 2;
if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) {
//Not proped yet because ETX is 0xffff
return false;
}
uint16_t etx = 0;
if (neigh_buffer.neighbor) {
etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index);
}
// Accept now only better one's when max candidates selected and max candidate list size is reached
if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) {
return false;
}
//TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection
//Mark That We can try remove replaced link
replace_ok = true;
neigh_create:
if (neigh_buffer.neighbor) {
//Use Already discovered entry
create_ok = true;
goto neigh_create_ok;
}
#endif
ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
if (!entry) {
//No Multicast Entry Available
return false;
}
//Create entry
bool create_ok = ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, true);
bool create_ok = ws_bootstrap_neighbor_info_request(cur, entry->mac64, &neigh_buffer, true);
if (create_ok) {
ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor;
//Copy fhss temporary data
@ -2186,7 +2241,15 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl
}
ws_llc_free_multicast_temp_entry(cur, entry);
#if 0
neigh_create_ok:
if (create_ok && replace_ok) {
//Try remove here when accepted new better one possible
tr_debug("Remove %s by %s", trace_ipv6(replacing), trace_ipv6(ll_parent_address));
rpl_control_neighbor_delete_from_instance(cur, instance, replacing);
}
#endif
return create_ok;
}
@ -2198,13 +2261,18 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur)
addr_add_router_groups(cur);
rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream);
rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback_t, cur);
rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback, cur);
// If i am router I Do this
rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf);
rpl_control_process_routes(protocol_6lowpan_rpl_domain, false); // Wi-SUN assumes that no default route needed
rpl_control_request_parent_link_confirmation(true);
rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT);
rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES);
rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT);
rpl_control_set_mrhof_parent_set_size(WS_MAX_PARENT_SET_COUNT);
if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
rpl_control_set_memory_limits(WS_NODE_RPL_SOFT_MEM_LIMIT, WS_NODE_RPL_HARD_MEM_LIMIT);
}
cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event
}
@ -2222,7 +2290,7 @@ static void ws_bootstrap_network_discovery_configure(protocol_interface_info_ent
cur->ws_info->network_pan_id = 0xffff;
ws_common_regulatory_domain_config(cur);
ws_fhss_discovery_configure(cur);
ws_fhss_configure(cur, true);
//Set Network names, Pan information configure, hopping schedule & GTKHash
ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name));
@ -2294,7 +2362,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c);
cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
}
// Start authentication
@ -2324,7 +2392,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index)
{
// Set send key
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (cur->mac_parameters->mac_default_key_index != 0 && cur->mac_parameters->mac_default_key_index != index + 1) {
tr_info("New Pending key Request %u", index + 1);
cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ADVERTISMENT;
cur->ws_info->pending_key_index_info.index = index;
return;
}
}
mac_helper_security_auto_request_key_index_set(cur, index, index + 1);
}
@ -2355,7 +2432,7 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_
// Go back for network scanning
ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN);
cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, cur->ws_info->trickle_params_pan_discovery.Imin >> 1);
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
} else {
tr_debug("authentication failed");
// What else to do to start over again...
@ -2377,6 +2454,8 @@ static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry
ws_bootstrap_ip_stack_reset(cur);
cur->ws_info->pas_requests = 0;
//Calculate max time for config learn state
cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX);
// Reset advertisement solicit trickle to start discovering network
cur->ws_info->trickle_pcs_running = true;
trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery);
@ -2387,8 +2466,11 @@ static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur)
tr_debug("Start RPL learn");
// routers wait until RPL root is contacted
ws_bootstrap_state_change(cur, ER_RPL_SCAN);
// Set timeout for check to 30 -60 seconds
cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT);
//For Large network and medium shuold do passive scan
if (cur->ws_info->network_size_config == NETWORK_SIZE_LARGE || cur->ws_info->network_size_config == NETWORK_SIZE_MEDIUM) {
// Set timeout for check to 30 -60 seconds
cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT);
}
}
/*
@ -2494,13 +2576,11 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr
uint16_t etx = etx_local_etx_read(cur->id, mac_neighbor->index);
if (etx == 0) {
etx = 0xffff;
etx = WS_ETX_MAX; //SET maxium value here if ETX is unknown
} else {
//Scale to 128 based ETX (local read retur 0x100 - 0xffff
etx = etx >> 1;
}
if (etx > 0x800) {
// Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0.
etx = 0x800;
}
etx = etx >> 1;
return ws_neighbor->routing_cost + etx;
}
@ -2574,7 +2654,13 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur)
async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur);
async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
async_req.security.KeyIndex = mac_helper_default_key_index_get(cur);
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && cur->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ADVERTISMENT) {
async_req.security.KeyIndex = cur->ws_info->pending_key_index_info.index + 1;
cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ACTIVATE;
} else {
async_req.security.KeyIndex = mac_helper_default_key_index_get(cur);
}
ws_llc_asynch_request(cur, &async_req);
}
@ -2594,6 +2680,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
break;
case WS_DISCOVERY_START:
tr_info("Discovery start");
//Clear Pending Key Index State
cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
cur->mac_parameters->mac_default_key_index = 0;
// All trickle timers stopped to allow entry from any state
cur->ws_info->trickle_pa_running = false;
cur->ws_info->trickle_pc_running = false;
@ -2601,7 +2692,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
cur->ws_info->trickle_pcs_running = false;
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
tr_debug("Border router start network");
tr_info("Border router start network");
if (!ws_bbr_ready_to_start(cur)) {
// Wi-SUN not started yet we wait for Border router permission
@ -2722,12 +2813,17 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
tr_debug("analyze network discovery result");
select_best_candidate:
selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur);
if (!selected_parent_ptr) {
// Configure LLC for network discovery
ws_bootstrap_network_discovery_configure(cur);
// randomize new channel and start MAC
ws_bootstrap_fhss_activate(cur);
// Next check will be after one trickle
cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
return;
}
tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id);
@ -2740,7 +2836,10 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
ws_bootstrap_fhss_activate(cur);
llc_neighbour_req_t neighbor_info;
if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) {
return;
//Remove Neighbour and set Link setup back
ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr);
ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr);
goto select_best_candidate;
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp);
@ -2848,7 +2947,7 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
cur->ws_info->trickle_pc_running = false;
cur->ws_info->trickle_pas_running = false;
cur->ws_info->trickle_pcs_running = false;
ws_fhss_configure(cur, false);
ws_bootstrap_start_authentication(cur);
break;
case ER_RPL_SCAN:
@ -2873,20 +2972,34 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t
tr_info("Send PAN advertisement Solicit");
ws_bootstrap_pan_advert_solicit(cur);
}
if (cur->ws_info->trickle_pcs_running &&
trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
// send PAN Configuration solicit
if (cur->ws_info->pas_requests >= PCS_MAX) {
// if MAX PCS sent restart discovery
if (cur->ws_info->trickle_pcs_running) {
//Update MAX config sol timeout timer
if (cur->ws_info->pan_config_sol_max_timeout > ticks) {
cur->ws_info->pan_config_sol_max_timeout -= ticks;
} else {
//Config sol state timeout
cur->ws_info->pan_config_sol_max_timeout = 0;
}
if (trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
if (cur->ws_info->pas_requests < PCS_MAX) {
// send PAN Configuration solicit
tr_info("Send PAN configuration Solicit");
ws_bootstrap_pan_config_solicit(cur);
}
//Update counter every time reason that we detect PCS_MAX higher state
cur->ws_info->pas_requests++;
}
if (cur->ws_info->pas_requests > PCS_MAX || cur->ws_info->pan_config_sol_max_timeout == 0) {
// if MAX PCS sent or max waited timeout restart discovery
// Trickle is reseted when entering to discovery from state 3
tr_info("PAN configuration Solicit timeout");
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
ws_bootstrap_event_discovery_start(cur);
return;
}
tr_info("Send PAN configuration Solicit");
cur->ws_info->pas_requests++;
ws_bootstrap_pan_config_solicit(cur);
}
if (cur->ws_info->trickle_pa_running &&
trickle_timer(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery, ticks)) {
@ -2943,23 +3056,4 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface)
}
}
void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh)
{
ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neigh->index);
//Enable Faster ETX probing
ws_neighbor->accelerated_etx_probe = true;
//Move Neighbor to first to for accelerate Process
mac_neighbor_table_t *table_class = mac_neighbor_info(interface);
ns_list_remove(&table_class->neighbour_list, neigh);
ns_list_add_to_start(&table_class->neighbour_list, neigh);
//Try to Generate Active NUD Immediately
if (!ws_neighbor_entry_nud_notify(neigh, interface)) {
return;//Return if NUD active is full
}
table_class->active_nud_process++;
neigh->nud_active = true;
//Push NS to send
ws_nud_active_timer(interface, 0);
}
#endif //HAVE_WS

View File

@ -76,8 +76,6 @@ bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur);
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info);
void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_neighbor_table_entry_t *neigh);
#else
#define ws_bootstrap_init(interface_id, bootstrap_mode) (-1)
@ -87,7 +85,6 @@ void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_
#define ws_bootstrap_aro_failure(cur, ll_address)
#define ws_primary_parent_update(interface, neighbor)
#define ws_secondary_parent_update(interface)
#define ws_bootstrap_etx_accelerate(cur, neigh) ((void) 0)
#endif //HAVE_WS

View File

@ -22,6 +22,7 @@
#include "randLIB.h"
#include <ns_list.h>
#include <nsdynmemLIB.h>
#include "Common_Protocols/icmpv6.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_common.h"
@ -316,6 +317,9 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
cur->ws_info->fhss_bc_dwell_interval = WS_FHSS_BC_DWELL_INTERVAL;
cur->ws_info->fhss_uc_channel_function = WS_DH1CF;
cur->ws_info->fhss_bc_channel_function = WS_DH1CF;
cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
for (uint8_t n = 0; n < 8; n++) {
cur->ws_info->fhss_channel_mask[n] = 0xffffffff;
}
@ -335,11 +339,11 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// doublings:3 (128s)
// redundancy; 0 Disabled
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
ws_bbr_rpl_config(14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_bbr_rpl_config(cur, 14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
} else if (cur->ws_info->network_size_config == NETWORK_SIZE_CERTIFICATE) {
ws_bbr_rpl_config(0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE);
ws_bbr_rpl_config(cur, 0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE);
} else {
ws_bbr_rpl_config(0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_bbr_rpl_config(cur, 0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
}
ws_pae_controller_timing_adjust(1); // Fast and reactive network
} else if (network_size < 300) {
@ -349,7 +353,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// imin: 15 (32s)
// doublings:5 (960s)
// redundancy; 10
ws_bbr_rpl_config(15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_pae_controller_timing_adjust(9); // medium limited network
} else {
// Configure the Wi-SUN discovery trickle parameters
@ -358,7 +362,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// imin: 19 (524s, 9 min)
// doublings:1 (1048s, 17 min)
// redundancy; 10 May need some tuning still
ws_bbr_rpl_config(19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_bbr_rpl_config(cur, 19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_pae_controller_timing_adjust(24); // Very slow and high latency network
}
return;
@ -387,12 +391,10 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
}
}
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full)
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
{
tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
if (cache_full) {
blacklist_update(ll_address, false);
}
blacklist_update(ll_address, false);
ws_bootstrap_aro_failure(cur, ll_address);
}
@ -404,7 +406,7 @@ void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
{
uint8_t child_count = 0;
uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT;
@ -417,13 +419,13 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
//Validate Is EUI64 already allocated for any address
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) {
tr_info("Child registration from old child");
return true;
return ARO_SUCCESS;
}
//Verify that we have Selected Parent
if (interface->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && !rpl_control_parent_candidate_list_size(interface, true)) {
tr_info("Do not accept new ARO child: no selected parent");
return false;
return ARO_TOPOLOGICALLY_INCORRECT;
}
@ -435,10 +437,10 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
}
if (child_count >= max_child_count) {
tr_warn("Child registration not allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size);
return false;
return ARO_FULL;
}
tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size);
return true;
return ARO_SUCCESS;
}
bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
@ -447,23 +449,13 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con
if (!neighbour) {
return false;
}
ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbour->index);
ws_neighbor->negative_aro_send = true;
neighbour->lifetime = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; //Remove anyway if Packet is freed before MAC push
return true;
}
void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh)
{
etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, neigh->index);
if (neigh->nud_active || !neigh->trusted_device || !etx_entry || etx_entry->etx_samples) {
return; //Do not trig Second NS if Active NUD already, not trusted or ETX samples already done
}
ws_bootstrap_etx_accelerate(interface, neigh);
}
uint32_t ws_common_version_lifetime_get(uint8_t config)
{
uint32_t lifetime;

View File

@ -60,6 +60,15 @@ typedef struct ws_nud_table_entry {
ns_list_link_t link;
} ws_nud_table_entry_t;
#define NO_PENDING_PROCESS 0
#define PENDING_KEY_INDEX_ADVERTISMENT 1
#define PENDING_KEY_INDEX_ACTIVATE 2
typedef struct {
unsigned state: 2;
uint8_t index;
} ws_pending_key_index_t;
typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t;
typedef struct ws_info_s {
@ -79,15 +88,17 @@ typedef struct ws_info_s {
parent_info_t parent_info[WS_PARENT_LIST_SIZE];
parent_info_list_t parent_list_free;
parent_info_list_t parent_list_reserved;
uint32_t pan_version_timer; /**< border router version udate timeout */
uint16_t rpl_version_timer; /**< RPL version update timeout */
uint32_t pan_version_timer; /**< border router version update timeout */
uint32_t pan_version_timeout_timer; /**< routers will fallback to previous state after this */
uint32_t pan_config_sol_max_timeout;
uint8_t gtkhash[32];
bool configuration_learned: 1;
bool trickle_pas_running: 1;
bool trickle_pa_running: 1;
bool trickle_pcs_running: 1;
bool trickle_pc_running: 1;
bool fhss_owner: 1;
ws_pending_key_index_t pending_key_index_info;
// default fhss parameters for this device
uint8_t fhss_uc_dwell_interval;
uint8_t fhss_bc_dwell_interval;
@ -126,13 +137,11 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks);
void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full);
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh);
uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64);
@ -146,11 +155,10 @@ uint32_t ws_common_version_timeout_get(uint8_t config);
#define ws_info(cur) ((ws_info_t *) NULL)
#define ws_common_seconds_timer(cur, seconds)
#define ws_common_neighbor_update(cur, ll_address) ((void) 0)
#define ws_common_aro_failure(cur, ll_address, cache_full)
#define ws_common_aro_failure(cur, ll_address)
#define ws_common_neighbor_remove(cur, ll_address)
#define ws_common_fast_timer(cur, ticks) ((void) 0)
#define ws_common_allow_child_registration(cur, eui64) (false)
#define ws_common_etx_validate(interface, neigh) ((void) 0)
#define ws_common_allow_child_registration(cur, eui64) (2)
#define ws_common_negative_aro_mark(interface, eui64)(false)
#endif //HAVE_WS

View File

@ -190,7 +190,8 @@ typedef struct ws_bs_ie {
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
#define WS_NEIGBOR_ETX_SAMPLE_MAX 3
#define WS_NEIGHBOR_ETX_SAMPLE_MAX 3
#define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX
#define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5
#define WS_PROBE_INIT_BASE_SECONDS 8
@ -204,6 +205,7 @@ typedef struct ws_bs_ie {
#define WS_ETX_MIN_SAMPLE_COUNT 4
#define WS_ETX_MAX_UPDATE 1024
#define WS_ETX_MAX 1024
#define WS_ETX_MIN_WAIT_TIME 60
@ -211,7 +213,7 @@ typedef struct ws_bs_ie {
#define WS_RPL_SELECTED_PARENT_MAX 2
#define WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX 8
#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 3
#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 4
/**
* Wi-sun spesific non-preferred prefix policy label

View File

@ -46,7 +46,10 @@
#define PAN_VERSION_MEDIUM_NETWORK_LIFETIME 15*60
#define PAN_VERSION_LARGE_NETWORK_LIFETIME 30*60 //30min
#define RPL_VERSION_LIFETIME 5*3600
// RPL version number update intervall
// after restart version numbers are increased faster and then slowed down when network is stable
#define RPL_VERSION_LIFETIME 12*3600
#define RPL_VERSION_LIFETIME_RESTART 3600
/* Border router connection lost timeout
*
@ -100,7 +103,7 @@ extern uint8_t DEVICE_MIN_SENS;
#define DATA_MESSAGE_IMIN (10 * 1000)
#define DATA_MESSAGE_TIMER_EXPIRATIONS 3
#define DATA_MESSAGE_IMAX (DATA_MESSAGE_IMIN)
#define DATA_MESSAGE_IMAX (80 * 1000)
#define MPL_SEED_SET_ENTRY_TIMEOUT (DATA_MESSAGE_IMAX * 24 * 4 / 1000) // 10 seconds per hop making this 240 seconds
/* DHCP client timeout configuration values
@ -145,7 +148,11 @@ extern uint8_t DEVICE_MIN_SENS;
*/
#define WS_MAX_DAO_RETRIES 3 // With 40s, 80s, 160s, 320s, 640s
#define WS_MAX_DAO_INITIAL_TIMEOUT 400 // With 40s initial value exponentially increasing
#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 10 // Define 10 multicast advertisment when learn config or learn config update
#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 0xff // Advertisment config at every MC DIO
#define WS_MAX_PARENT_SET_COUNT 2 // maximum amount of parents selected by node
#define WS_NODE_RPL_SOFT_MEM_LIMIT 4*1024 // Limit when RPL start purge unused data
#define WS_NODE_RPL_HARD_MEM_LIMIT 6*1024 // Limit when RPL memory allocation start limit allocation
/*
* Candidate parent list parameters

View File

@ -560,7 +560,7 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) {
if (!multicast || ws_utt.message_type == WS_FT_EAPOL) {
tr_debug("Drop message no neighbor");
//tr_debug("Drop message no neighbor");
return;
} else {
//Allocate temporary entry

View File

@ -220,20 +220,32 @@ int ws_management_fhss_timing_configure(
if (!cur || !ws_info(cur)) {
return -1;
}
if (fhss_uc_dwell_interval > 0) {
if (fhss_uc_dwell_interval && fhss_uc_dwell_interval < 15) {
return -2;
}
if (fhss_bc_dwell_interval && fhss_bc_dwell_interval < 15) {
return -2;
}
bool updated_configure = false;
if (fhss_uc_dwell_interval > 0 && cur->ws_info->fhss_uc_dwell_interval != fhss_uc_dwell_interval) {
cur->ws_info->fhss_uc_dwell_interval = fhss_uc_dwell_interval;
updated_configure = true;
}
if (fhss_broadcast_interval > 0) {
if (fhss_broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != fhss_broadcast_interval) {
cur->ws_info->fhss_bc_interval = fhss_broadcast_interval;
updated_configure = true;
}
if (fhss_bc_dwell_interval > 0) {
if (fhss_bc_dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != fhss_bc_dwell_interval) {
cur->ws_info->fhss_bc_dwell_interval = fhss_bc_dwell_interval;
updated_configure = true;
}
// if settings change reset_restart for the settings needed
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
if (updated_configure && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
// bootstrap active need to restart
ws_bootstrap_restart(interface_id);
}
@ -259,23 +271,38 @@ int ws_management_fhss_unicast_channel_function_configure(
return -2;
}
if (dwell_interval && dwell_interval < 15) {
return -2;
}
if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
fixed_channel = 0;
tr_warn("Fixed channel not configured. Set to 0");
}
bool updated_config = false;
if (cur->ws_info->fhss_uc_channel_function != channel_function) {
cur->ws_info->fhss_uc_channel_function = channel_function;
updated_config = true;
}
cur->ws_info->fhss_uc_channel_function = channel_function;
if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) {
cur->ws_info->fhss_uc_fixed_channel = fixed_channel;
if (cur->ws_info->fhss_uc_fixed_channel != fixed_channel) {
cur->ws_info->fhss_uc_fixed_channel = fixed_channel;
updated_config = true;
}
} else {
cur->ws_info->fhss_uc_fixed_channel = 0xffff;
}
cur->ws_info->fhss_uc_dwell_interval = dwell_interval;
if (dwell_interval && cur->ws_info->fhss_uc_dwell_interval != dwell_interval) {
cur->ws_info->fhss_uc_dwell_interval = dwell_interval;
updated_config = true;
}
// if settings change reset_restart for the settings needed
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
// bootstrap active need to restart
ws_bootstrap_restart(interface_id);
}
@ -303,23 +330,43 @@ int ws_management_fhss_broadcast_channel_function_configure(
return -2;
}
if (dwell_interval && dwell_interval < 15) {
return -2;
}
if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
fixed_channel = 0;
tr_warn("Fixed channel not configured. Set to 0");
}
cur->ws_info->fhss_bc_channel_function = channel_function;
bool updated_config = false;
if (cur->ws_info->fhss_bc_channel_function != channel_function) {
cur->ws_info->fhss_bc_channel_function = channel_function;
updated_config = true;
}
if (cur->ws_info->fhss_bc_channel_function == WS_FIXED_CHANNEL) {
cur->ws_info->fhss_bc_fixed_channel = fixed_channel;
if (cur->ws_info->fhss_bc_fixed_channel != fixed_channel) {
cur->ws_info->fhss_bc_fixed_channel = fixed_channel;
updated_config = true;
}
} else {
cur->ws_info->fhss_bc_fixed_channel = 0xffff;
}
cur->ws_info->fhss_bc_dwell_interval = dwell_interval;
cur->ws_info->fhss_bc_interval = broadcast_interval;
if (dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != dwell_interval) {
cur->ws_info->fhss_bc_dwell_interval = dwell_interval;
updated_config = true;
}
if (broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != broadcast_interval) {
cur->ws_info->fhss_bc_interval = broadcast_interval;
updated_config = true;
}
// if settings change reset_restart for the settings needed
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
// bootstrap active need to restart
ws_bootstrap_restart(interface_id);
}

View File

@ -32,7 +32,6 @@ typedef struct ws_neighbor_class_entry {
bool broadcast_timing_info_stored: 1;
bool broadcast_shedule_info_stored: 1;
bool synch_done : 1;
bool accelerated_etx_probe : 1;
bool negative_aro_send : 1;
bool unicast_data_rx : 1;
} ws_neighbor_class_entry_t;

View File

@ -70,6 +70,9 @@
nanostack monitor */
#define SUPPLICANT_NUMBER_TO_PURGE 5
// Short GTK lifetime value, for GTK install check
#define SHORT_GTK_LIFETIME 10 * 3600 // 10 hours
typedef struct {
ns_list_link_t link; /**< Link */
kmp_service_t *kmp_service; /**< KMP service */
@ -113,7 +116,7 @@ static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e resu
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry);
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry);
static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp);
@ -666,7 +669,9 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index);
sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0);
} else {
randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
do {
randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
} while (sec_prot_keys_gtk_valid_check(gtk_value) < 0);
}
// Gets latest installed key lifetime and adds GTK expire offset to it
@ -910,7 +915,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
supp_entry->retry_ticks = 0;
// Get next protocol based on what keys supplicant has
kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry);
kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry);
if (next_type == KMP_TYPE_NONE) {
// All done
@ -969,7 +974,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys);
}
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry)
{
kmp_type_e next_type = KMP_TYPE_NONE;
sec_prot_keys_t *sec_keys = &supp_entry->sec_keys;
@ -999,9 +1004,22 @@ static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
if (gtk_index >= 0) {
if (next_type == KMP_TYPE_NONE && gtk_index >= 0) {
// Update just GTK
next_type = IEEE_802_11_GKH;
tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
/* Check if the PTK has been already used to install GTK to specific index and if it
* has been, trigger 4WH to update also the PTK. This prevents writing multiple
* GTK keys to same index using same PTK.
*/
if (pae_auth->timer_settings->gtk_expire_offset > SHORT_GTK_LIFETIME &&
sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_keys, gtk_index)) {
// start 4WH towards supplicant
next_type = IEEE_802_11_4WH;
sec_keys->ptk_mismatch = true;
tr_info("PAE start 4WH due to GTK index re-use, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
} else {
// Update just GTK
next_type = IEEE_802_11_GKH;
tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
}
}
tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8));

View File

@ -232,7 +232,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
#else
#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, timer_settings) 1
#define ws_pae_auth_timing_adjust(timing) 1
#define ws_pae_auth_timing_adjust(timing)
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
#define ws_pae_auth_delete NULL
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;}

View File

@ -88,6 +88,7 @@ typedef struct {
bool gtks_set : 1; /**< GTKs are set */
bool gtkhash_set : 1; /**< GTK hashes are set */
bool key_index_set : 1; /**< NW key index is set */
bool frame_counter_read : 1; /**< Frame counters has been read */
} pae_controller_t;
typedef struct {
@ -108,6 +109,7 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key);
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index);
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name);
static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold);
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
static void ws_pae_controller_data_init(pae_controller_t *controller);
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller);
@ -363,12 +365,16 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
// Install the new network key derived from GTK and network name (GAK) to MAC
controller->nw_key_set(interface_ptr, i, i, gak);
tr_info("NW: %s", controller->network_name);
tr_info("NW: %s", trace_array((uint8_t *)controller->network_name, 20));
tr_info("GTK: %s", trace_array(gtk, 16));
tr_info("GAK: %s", trace_array(gak, 16));
nw_key[i].installed = true;
ret = 0;
#ifdef EXTRA_DEBUG_INFO
tr_info("NW name: %s", controller->network_name);
size_t nw_name_len = strlen(controller->network_name);
tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len));
tr_info("GTK: %s", trace_array(gtk, 16));
tr_info("GAK: %s", trace_array(gak, 16));
#endif
} else {
tr_error("GAK generation failed network name: %s", controller->network_name);
continue;
@ -380,9 +386,11 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
// Read current counter from MAC
uint32_t curr_frame_counter;
controller->nw_frame_counter_read(controller->interface_ptr, &curr_frame_counter, i);
// If stored frame counter is greater than MAC counter
if (controller->frame_counters.counter[i].frame_counter > curr_frame_counter) {
tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i, controller->frame_counters.counter[i].frame_counter, curr_frame_counter);
tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i,
controller->frame_counters.counter[i].frame_counter, curr_frame_counter);
curr_frame_counter = controller->frame_counters.counter[i].frame_counter;
// Updates MAC frame counter
controller->nw_frame_counter_set(controller->interface_ptr, curr_frame_counter, i);
@ -474,6 +482,16 @@ void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface
return;
}
/* Stores frame counters if incremented by threshold and removes network keys from PAE
controller and MAC */
ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, true);
}
static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold)
{
/* Checks if frame counters needs to be stored when keys are removed */
ws_pae_controller_frame_counter_store(controller, use_threshold);
tr_info("NW keys remove");
nw_key_t *nw_key = controller->nw_key;
@ -589,6 +607,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
controller->gtks_set = false;
controller->gtkhash_set = false;
controller->key_index_set = false;
controller->frame_counter_read = false;
controller->gtk_index = -1;
controller->network_name = NULL;
controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
@ -602,6 +621,11 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
{
if (controller->frame_counter_read) {
return;
}
controller->frame_counter_read = true;
// Read frame counters
if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) {
bool updated = false;
@ -610,6 +634,8 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
if (controller->frame_counters.counter[index].set) {
// Increments frame counters
controller->frame_counters.counter[index].frame_counter += FRAME_COUNTER_INCREMENT;
controller->frame_counters.counter[index].stored_frame_counter =
controller->frame_counters.counter[index].frame_counter;
tr_info("Read frame counter: index %i value %"PRIu32"", index, controller->frame_counters.counter[index].frame_counter);
@ -620,7 +646,6 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
// Writes incremented frame counters
ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters);
ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
//ws_pae_controller_frame_counter_write(controller, &controller->frame_counters);
}
}
}
@ -630,6 +655,7 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte
for (uint8_t index = 0; index < GTK_NUM; index++) {
memset(frame_counters->counter[index].gtk, 0, GTK_LEN);
frame_counters->counter[index].frame_counter = 0;
frame_counters->counter[index].stored_frame_counter = 0;
frame_counters->counter[index].set = false;
}
}
@ -653,7 +679,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update;
controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update;
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set);
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get);
ws_pae_controller_frame_counter_read(controller);
@ -689,11 +715,8 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
return -1;
}
// Stores frame counter
ws_pae_controller_frame_counter_store(controller, false);
// Removes network keys from PAE controller and MAC
ws_pae_controller_nw_keys_remove(interface_ptr);
// Stores frame counters and removes network keys from PAE controller and MAC
ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false);
// If PAE has been initialized, deletes it
if (controller->pae_delete) {
@ -1180,7 +1203,7 @@ int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interf
memcpy(controller->gtkhash, gtkhash, 32);
if (controller->pae_gtk_hash_update) {
return controller->pae_gtk_hash_update(interface_ptr, gtkhash);
return controller->pae_gtk_hash_update(interface_ptr, controller->gtkhash);
}
return 0;
@ -1241,18 +1264,25 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool
// If frame counter for the network key has already been stored
if (entry->frame_counters.counter[i].set &&
memcmp(entry->nw_key[i].gtk, entry->frame_counters.counter[i].gtk, GTK_LEN) == 0) {
if (curr_frame_counter > entry->frame_counters.counter[i].frame_counter) {
entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
}
uint32_t frame_counter = entry->frame_counters.counter[i].frame_counter;
// If threshold check is disabled or frame counter has advanced for the threshold value, stores the new value
if (!use_threshold ||
curr_frame_counter > entry->frame_counters.counter[i].frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
frame_counter > entry->frame_counters.counter[i].stored_frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
entry->frame_counters.counter[i].stored_frame_counter = frame_counter;
update_needed = true;
tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, frame_counter);
}
} else {
// For new or modified network keys, stores the frame counter value
entry->frame_counters.counter[i].set = true;
memcpy(entry->frame_counters.counter[i].gtk, entry->nw_key[i].gtk, GTK_LEN);
entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
entry->frame_counters.counter[i].stored_frame_counter = curr_frame_counter;
update_needed = true;
tr_debug("Stored new frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
}

View File

@ -291,6 +291,20 @@ void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks)
entry->ticks = ticks;
}
void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks)
{
entry->ticks += ticks;
}
bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry)
{
if (entry->ticks == 0) {
return false;
}
return true;
}
void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry)
{
if (entry->active) {

View File

@ -272,6 +272,25 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry);
*/
void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks);
/**
* ws_pae_lib_supp_timer_ticks_add adds supplicant timer ticks
*
* \param entry supplicant entry
* \param ticks ticks
*
*/
void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks);
/**
* ws_pae_lib_supp_timer_is_running checks whether supplicant timer is running
*
* \param entry supplicant entry
*
* \return TRUE timer is running, FALSE timer is not running
*
*/
bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry);
/**
* ws_pae_lib_supp_list_to_active move supplicant to active supplicants list
*

View File

@ -57,7 +57,7 @@ nvm_tlv_entry_t *ws_pae_buffer_allocate(void)
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
{
int len;
tlv_entry->tag = PAE_NVM_NW_INFO_TAG;
tlv_entry->len = PAE_NVM_NW_INFO_LEN;
@ -66,7 +66,13 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
tlv = common_write_16_bit(pan_id, tlv);
memset(tlv, 0, 33);
strncpy((char *)tlv, nw_name, 32);
// use strnlen & memset instead of strncpy to avoid gcc warning:
// call to __builtin___strncpy_chk will always overflow destination buffer [-Werror]
len = strlen(nw_name);
if (len > 32) {
len = 32;
}
memcpy((char *)tlv, nw_name, len);
tlv += 33;
for (uint8_t i = 0; i < GTK_NUM; i++) {

View File

@ -66,6 +66,9 @@
// Wait for re-authentication after GTK update
#define WAIT_FOR_REAUTHENTICATION_TICKS 120 * 10 // 120 seconds
// Ticks added to wait for authenticator timer when authentication protocol is started (e.g. EAP-TLS)
#define START_AUTHENTICATION_TICKS 5 * 10 // 10 seconds
// How many times in maximum stored keys are used for authentication
#define STORED_KEYS_MAXIMUM_USE_COUNT 1
@ -88,9 +91,11 @@ typedef struct {
ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */
ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */
ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get; /**< Get pointer to GTK hash storage callback */
supp_entry_t entry; /**< Supplicant data */
kmp_addr_t target_addr; /**< EAPOL target (parent) address */
uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */
uint16_t initial_key_retry_timer; /**< Timer to trigger initial EAPOL-Key 1st retry */
trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */
trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */
sec_prot_gtk_keys_t gtks; /**< GTKs */
@ -98,6 +103,7 @@ typedef struct {
sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */
timer_settings_t *timer_settings; /**< Timer settings */
uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */
uint8_t initial_key_retry_cnt; /**< initial EAPOL-Key retry counter */
bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */
bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */
bool timer_running : 1; /**< Timer is running */
@ -106,14 +112,34 @@ typedef struct {
bool entry_address_active: 1;
} pae_supp_t;
// How many times sending of initial EAPOL-key is retried
#define INITIAL_KEY_RETRY_COUNT 2
#define TRICKLE_IMIN_180_SECS 180
// How many times sending of initial EAPOL-key is initiated on key update
#define KEY_UPDATE_RETRY_COUNT 3
#define LIFETIME_MISMATCH_RETRY_COUNT 1 /* No retries */
// How long the wait is before the first initial EAPOL-key retry
#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120
#define NONE_INITIAL_KEY_RETRY_TIMER 0
// Default trickle values for sending of initial EAPOL-key
#define DEFAULT_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */
#define DEFAULT_TRICKLE_IMAX_SECS 720
// Very slow network values for sending of initial EAPOL-key
#define VERY_SLOW_NW_TRICKLE_IMIN_SECS 600 /* 10 to 60 minutes */
#define VERY_SLOW_NW_TRICKLE_IMAX_SECS 3600
// Trickle timer on how long to wait response after last retry before failing authentication
#define LAST_INTERVAL_TRICKLE_IMIN_SECS 240 /* 4 minutes */
#define LAST_INTERVAL_TRICKLE_IMAX_SECS 240
static trickle_params_t initial_eapol_key_trickle_params = {
.Imin = TRICKLE_IMIN_180_SECS, /* 180 second; ticks are 1 second */
.Imax = TRICKLE_IMIN_180_SECS << 1, /* 360 second */
.k = 0, /* infinity - no consistency checking */
.TimerExpirations = 3
.Imin = DEFAULT_TRICKLE_IMIN_SECS, /* 360 second; ticks are 1 second */
.Imax = DEFAULT_TRICKLE_IMAX_SECS, /* 720 second */
.k = 0, /* infinity - no consistency checking */
.TimerExpirations = 2
};
static void ws_pae_supp_free(pae_supp_t *pae_supp);
@ -126,6 +152,10 @@ static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp);
static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr);
static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data);
static void ws_pae_supp_tasklet_handler(arm_event_s *event);
static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp);
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp);
static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations);
static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp);
static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
static int8_t ws_pae_supp_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp);
static int8_t ws_pae_supp_timer_start(pae_supp_t *pae_supp);
@ -138,6 +168,7 @@ static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp);
static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp);
static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
@ -156,6 +187,7 @@ static const char *KEYS_FILE = KEYS_FILE_NAME;
static int8_t tasklet_id = -1;
static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link);
static uint8_t timing_value = 0; // Timing value set based e.g. on network size
static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address)
{
@ -291,6 +323,23 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
return 0;
}
static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp)
{
uint8_t *gtkhash = pae_supp->gtk_hash_ptr_get(pae_supp->interface_ptr);
if (!gtkhash) {
return -1;
}
// Check GTK hashes and initiate EAPOL procedure if mismatch is detected */
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash);
if (mismatch != GTK_NO_MISMATCH) {
return -1;
}
tr_info("GTKs match to GTK hash");
return 0;
}
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
@ -307,30 +356,21 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
trace_array(&gtkhash[16], 8),
trace_array(&gtkhash[24], 8));
// Mismatch, initiate EAPOL
if (!pae_supp->auth_trickle_running) {
uint8_t timer_expirations = 3;
/* Mismatch, initiate EAPOL (if authentication not already ongoing or if not on
wait time for the authenticator to answer) */
if (!pae_supp->auth_trickle_running || pae_supp->initial_key_retry_cnt == 0) {
uint8_t timer_expirations = KEY_UPDATE_RETRY_COUNT;
// For GTK lifetime mismatch send only once
if (mismatch == GTK_LIFETIME_MISMATCH) {
timer_expirations = 1;
timer_expirations = LIFETIME_MISMATCH_RETRY_COUNT;
}
pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
pae_supp->auth_trickle_params.k = 0;
pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
// Starts trickle
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
pae_supp->auth_trickle_running = true;
// Start trickle timer
ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, timer_expirations);
// Starts supplicant timer
ws_pae_supp_timer_start(pae_supp);
tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->timer_settings->gtk_request_imin, pae_supp->timer_settings->gtk_request_imax, pae_supp->timer_settings->gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
} else {
// If trickle is already running, set inconsistent heard to speed up the trickle
trickle_inconsistent_heard(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
}
}
@ -565,7 +605,7 @@ static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_i
sec_keys_nw_info->updated = false;
}
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set)
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
@ -575,6 +615,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_supp->auth_completed = completed;
pae_supp->nw_key_insert = nw_key_insert;
pae_supp->nw_key_index_set = nw_key_index_set;
pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get;
}
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
@ -596,9 +637,12 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
pae_supp->auth_completed = NULL;
pae_supp->nw_key_insert = NULL;
pae_supp->nw_key_index_set = NULL;
pae_supp->gtk_hash_ptr_get = NULL;
pae_supp->initial_key_timer = 0;
pae_supp->initial_key_retry_timer = 0;
pae_supp->nw_keys_used_cnt = 0;
pae_supp->timer_settings = timer_settings;
pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
pae_supp->auth_trickle_running = false;
pae_supp->auth_requested = false;
pae_supp->timer_running = false;
@ -702,6 +746,7 @@ int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr)
int8_t ws_pae_supp_timing_adjust(uint8_t timing)
{
timing_value = timing;
supp_fwh_sec_prot_timing_adjust(timing);
supp_eap_sec_prot_timing_adjust(timing);
return 0;
@ -801,7 +846,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout);
// Checks whether timer needs to be active
if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) {
if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) {
tr_debug("PAE idle");
// If not already completed, restart bootstrap
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
@ -811,20 +856,69 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
}
}
static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp)
{
/* When either bootstrap initial authentication or re-authentication is ongoing */
if (pae_supp->initial_key_timer || pae_supp->auth_trickle_running ||
ws_pae_lib_supp_timer_is_running(&pae_supp->entry)) {
return true;
}
return false;
}
void ws_pae_supp_slow_timer(uint16_t seconds)
{
ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) {
// Checks whether initial EAPOL-Key message needs to be re-send or new GTK request to be sent
if (pae_supp->auth_trickle_running) {
if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
tr_info("EAPOL-Key send failed");
if (pae_supp->initial_key_retry_timer > 0) {
if (pae_supp->initial_key_retry_timer > seconds) {
pae_supp->initial_key_retry_timer -= seconds;
} else {
pae_supp->initial_key_retry_timer = 0;
tr_info("initial key retry timer expired");
}
} else {
// Checks if trickle timer expires
if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
if (pae_supp->initial_key_retry_cnt > 0) {
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
tr_info("EAPOL-Key send failed");
}
}
/* Wait time for the authenticator to answer the last re-transmit expires;
fails authentication */
if (pae_supp->initial_key_retry_cnt == 0) {
bool retry = false;
// If making key update and GTKs do not match to GTK hash
if (!pae_supp->auth_requested && ws_pae_supp_gtk_hash_mismatch_check(pae_supp) < 0) {
tr_info("GTKs do not match to GTK hash");
retry = true;
}
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
if (retry) {
// Start trickle timer to try re-authentication
ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT);
}
} else {
if (pae_supp->initial_key_retry_cnt > 0) {
pae_supp->initial_key_retry_cnt--;
}
if (pae_supp->initial_key_retry_cnt == 0) {
// Starts wait time for the authenticator to answer
tr_info("Initial EAPOL-Key wait for last re-transmit answer");
ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp);
}
}
}
// Sanity check, should be running until authentication failure
if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) {
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
}
}
// Maximum number of trickle expires, authentication fails
if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) {
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
}
}
@ -846,16 +940,76 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
tr_info("EAPOL-Key send failed");
}
// Starts trickle
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
pae_supp->auth_trickle_running = true;
// Start trickle timer
ws_pae_supp_initial_trickle_timer_start(pae_supp);
}
}
}
}
static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp)
{
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
// Very fast, medium and slow network
if (timing_value < 25) {
/* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes,
* one re-transmit interval, last re-transmit interval transmit time and a wait time
* for the authenticator to answer the last re-transmit.
*
* Interval I [6,12] minutes. Sequence:
*
* fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes
*
* There are two retries. Minimum time that sequence takes before authentication failure
* is 16 minutes and maximum is 30 minutes.
*/
pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes
} else {
/* Extremely slow network
*
* Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence:
* I + last I transmit time t + wait for answer [2,4] minutes
* There are two retries. Minimum time that sequence takes before authentication failure
* is 22 minutes and maximum is 124 minutes.
*/
pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS;
pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS;
pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds
}
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
pae_supp->auth_trickle_running = true;
pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
}
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp)
{
// Starts trickle last to wait response after last retry before failing authentication
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS;
pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS;
pae_supp->auth_trickle_params.TimerExpirations = 1;
// Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes)
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
}
static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations)
{
// Starts trickle for the key update
pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
pae_supp->auth_trickle_params.k = 0;
pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds
pae_supp->auth_trickle_running = true;
pae_supp->initial_key_retry_cnt = timer_expirations;
}
static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
{
pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service);
@ -947,7 +1101,7 @@ static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *int
const uint8_t *parent_ll_addr = rpl_control_preferred_parent_addr(instance, false);
if (parent_ll_addr) {
memcpy(eui_64, &parent_ll_addr[8], 8);
eui_64[0] |= 0x02;
eui_64[0] ^= 0x02;
return 0;
}
}
@ -1014,14 +1168,13 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
return NULL;
}
if (!pae_supp->entry_address_active) {
// If target address is not set or authentication is not ongoing
if (!pae_supp->entry_address_active || !ws_pae_supp_authentication_ongoing(pae_supp)) {
tr_info("Incoming KMP rejected, auth not ongoing, type: %i ", type);
// Does no longer wait for authentication, ignores message
return NULL;
}
// No longer runs trickle timer for re-sending initial EAPOL-key
pae_supp->auth_trickle_running = false;
// Updates parent address
kmp_address_copy(&pae_supp->entry.addr, addr);
@ -1040,6 +1193,9 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
// Create new instance
kmp = ws_pae_supp_kmp_create_and_start(service, type, pae_supp);
// Adds ticks to wait for authenticator to continue timer
ws_pae_lib_supp_timer_ticks_add(&pae_supp->entry, START_AUTHENTICATION_TICKS);
// For EAP-TLS create also TLS in addition to EAP-TLS
if (type == IEEE_802_1X_MKA) {
if (ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, TLS_PROT) != NULL) {
@ -1112,6 +1268,15 @@ static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ
(void) addr;
(void) type;
kmp_service_t *service = kmp_api_service_get(kmp);
pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service);
if (!pae_supp) {
return;
}
// Incoming KMP protocol has started, no longer runs trickle timer for re-sending EAPOL-key message
pae_supp->auth_trickle_running = false;
// For now, accept every KMP-CREATE.indication
kmp_api_create_response(kmp, KMP_RESULT_OK);
}
@ -1148,7 +1313,6 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8));
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK);
}
}
static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp)

View File

@ -236,6 +236,16 @@ typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interfa
*/
typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_supp_gtk_hash_ptr_get get pointer to GTK hash storage callback
*
* \param interface_ptr interface
*
* \return pointer to GTK has storage or NULL
*
*/
typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_supp_cb_register register PEA supplicant callbacks
*
@ -245,7 +255,7 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf
* \param nw_key_index_set network send key index callback
*
*/
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set);
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get);
#else

View File

@ -356,7 +356,7 @@ static void icmpv6_na_wisun_aro_handler(protocol_interface_info_entry_t *cur_int
(void)life_time;
if (nd_status != ARO_SUCCESS) {
ws_common_aro_failure(cur_interface, src_addr, true);
ws_common_aro_failure(cur_interface, src_addr);
}
}
@ -1389,7 +1389,7 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status)
}
rpl_control_address_register_done(buf->interface, ll_address, status);
if (status != SOCKET_TX_DONE) {
ws_common_aro_failure(buf->interface, ll_address, false);
ws_common_aro_failure(buf->interface, ll_address);
}
}
@ -1697,7 +1697,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
memcpy(ptr, aro->eui64, 8);
ptr += 8;
}
if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) {
if (ws_info(cur) && aro && (aro->status != ARO_SUCCESS && aro->status != ARO_TOPOLOGICALLY_INCORRECT)) {
/*If Aro failed we will kill the neigbour after we have succeeded in sending message*/
if (!ws_common_negative_aro_mark(cur, aro->eui64)) {
tr_debug("Neighbour removed for negative response send");
@ -1713,7 +1713,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP);
buf->interface = cur;
tr_debug("Build NA");
tr_info("Build NA");
return (buf);
}

View File

@ -117,6 +117,7 @@ typedef enum slaac_src {
#define ARO_SUCCESS 0
#define ARO_DUPLICATE 1
#define ARO_FULL 2
#define ARO_TOPOLOGICALLY_INCORRECT 8
extern void icmpv6_init(void);
extern struct buffer *icmpv6_down(struct buffer *buf);

View File

@ -325,6 +325,9 @@ void icmpv6_stop_router_advertisements(protocol_interface_info_entry_t *cur, con
*/
static void icmpv6_send_ra(protocol_interface_info_entry_t *cur, const uint8_t *dest, const uint8_t *abro)
{
#ifndef HAVE_RPL
(void) abro;
#endif
if (cur->nwk_id == IF_6LoWPAN) {
nd_ra_build_by_abro(abro, dest, cur);
} else {

View File

@ -773,6 +773,9 @@ drop:
static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint8_t nh, uint16_t payload_length, uint16_t *hdrlen_out, const sockaddr_t *ll_src, bool pre_fragment)
{
(void) nh;
#ifndef HAVE_RPL
(void) ll_src;
#endif
if (payload_length < 2) {
return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4);
}
@ -853,6 +856,9 @@ len_err:
static buffer_t *ipv6_handle_routing_header(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t payload_length, uint16_t *hdrlen_out, bool *forward_out, bool pre_fragment)
{
#ifndef HAVE_RPL
(void) forward_out;
#endif
if (buf->options.ll_security_bypass_rx) {
tr_warn("Routing header: Security check fail");
protocol_stats_update(STATS_IP_RX_DROP, 1);

View File

@ -16,7 +16,8 @@
*/
#include "nsconfig.h"
#include "string.h"
#include <string.h>
#include <limits.h>
#include "ns_types.h"
#include "nsdynmemLIB.h"
#include "Core/include/ns_address_internal.h"
@ -30,6 +31,13 @@
#define TRACE_GROUP "buff"
// Get module working also on 16-bit platform
#if INT_MAX < 0xFFFF
#define BUFFER_MAX_SIZE ((size_t)INT_MAX)
#else
#define BUFFER_MAX_SIZE ((size_t)0xFFFF)
#endif
volatile unsigned int buffer_count = 0;
uint8_t *(buffer_corrupt_check)(buffer_t *buf)
@ -38,15 +46,12 @@ uint8_t *(buffer_corrupt_check)(buffer_t *buf)
return NULL;
}
if (buf->buf_ptr > buf->buf_end) {
tr_error("Buffer pointer end not set");
} else if (buffer_data_length(buf) < 0) {
tr_error("Buffer length overflow");
while (1);
} else if (buf->buf_end > buf->size || buf->buf_ptr > buf->size) {
tr_error("buffer pointer overridden");
if (buf->buf_ptr > buf->buf_end || buf->buf_end > buf->size) {
tr_error("Invalid buffer, size=%"PRIu16", buf_ptr=%"PRIu16", buf_end=%"PRIu16"", buf->size, buf->buf_ptr, buf->buf_end);
tr_error("Data: %s", tr_array(buffer_data_pointer(buf), 56));
while (1);
}
return buffer_data_pointer(buf);
}
@ -71,8 +76,8 @@ buffer_t *buffer_get_minimal(uint16_t size)
*/
buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspace)
{
buffer_t *buf;
uint16_t total_size;
buffer_t *buf = NULL;
uint32_t total_size;
total_size = headroom + size;
if (total_size < minspace) {
@ -83,10 +88,12 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac
* anyway be this much aligned. */
total_size = (total_size + 3) & ~ 3;
// Note - as well as this alloc+init, buffers can also be "realloced"
// in buffer_headroom()
if (total_size <= BUFFER_MAX_SIZE) {
// Note - as well as this alloc+init, buffers can also be "realloced"
// in buffer_headroom()
buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size);
}
buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size);
if (buf) {
platform_enter_critical();
buffer_count++;
@ -110,7 +117,7 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac
#endif
buf->size = total_size;
} else {
tr_error("buffer_get failed: alloc(%d)", (int) sizeof(buffer_t) + total_size);
tr_error("buffer_get failed: alloc(%"PRIu32")", (uint32_t)(sizeof(buffer_t) + total_size));
}
protocol_stats_update(STATS_BUFFER_ALLOC, 1);
@ -130,10 +137,14 @@ buffer_t *buffer_headroom(buffer_t *buf, uint16_t size)
uint16_t curr_len = buffer_data_length(buf);
if (buf->size < (curr_len + size)) {
buffer_t *restrict new_buf = NULL;
/* This buffer isn't big enough at all - allocate a new block */
// TODO - should we be giving them extra? probably
uint16_t new_total = (curr_len + size + 3) & ~ 3;
buffer_t *restrict new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total);
uint32_t new_total = (curr_len + size + 3) & ~ 3;
if (new_total <= BUFFER_MAX_SIZE) {
new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total);
}
if (new_buf) {
// Copy the buffer_t header
*new_buf = *buf;

View File

@ -322,7 +322,7 @@ struct socket *buffer_socket_set(buffer_t *buf, struct socket *socket);
} while(0)
/** get data length*/
#define buffer_data_length(x) (int16_t)(x->buf_end - x->buf_ptr)
#define buffer_data_length(x) (int)(x->buf_end - x->buf_ptr)
/** get data length Set*/
#define buffer_data_length_set(x,z) ((x)->buf_end = (x)->buf_ptr + (z))

View File

@ -287,14 +287,16 @@ void socket_release(socket_t *socket)
if (tcp_info(socket->inet_pcb)) {
/* This may trigger a reset if pending data. Do it first so you
* get just the reset, rather than a FIN. */
tcp_session_shutdown_read(tcp_info(socket->inet_pcb));
tcp_error sock_status = tcp_session_shutdown_read(tcp_info(socket->inet_pcb));
/* This can also cause TCP deletion */
if (tcp_info(socket->inet_pcb)) {
tcp_session_close(tcp_info(socket->inet_pcb));
sock_status = tcp_session_close(tcp_info(socket->inet_pcb));
}
if (tcp_info(socket->inet_pcb)) {
tcp_socket_released(tcp_info(socket->inet_pcb));
}
// prevent warning "statement with no effect" when TCP is disabled
(void) sock_status;
} else {
/* Unbind the internet control block - ensures users are not prevented
* from binding a new socket to the same port if the socket lingers
@ -1362,8 +1364,10 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr
protocol_push(buf);
#ifndef NO_TCP
/* TCP jumps back to here */
success:
#endif
if (flags & NS_MSG_LEGACY0) {
return 0;
} else {

View File

@ -87,7 +87,7 @@ static void DHCP_server_service_timer_stop(void)
int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_reply_packet_s *replyPacket, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, dhcpv6_gua_response_t *response, bool allocateNew)
{
dhcpv6_alloacted_address_entry_t *dhcp_allocated_address;
dhcpv6_allocated_address_t *dhcp_allocated_address = NULL;
dhcpv6_ia_non_temporal_address_s nonTemporalAddress;
bool address_allocated = false;
//Validate Client DUID
@ -279,12 +279,15 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8],
{
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (serverInfo) {
ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
//Delete Server data base
if (serverInfo->removeCb) {
serverInfo->removeCb(interface, cur->nonTemporalAddress, NULL);
uint8_t allocated_address[16];
libdhcpv6_allocated_address_write(allocated_address, cur, serverInfo);
serverInfo->removeCb(interface, allocated_address, NULL);
}
}
if (serverInfo->removeCb) {
// Clean all /128 'Thread Proxy' routes to self and others added when acting as a DHCP server
serverInfo->removeCb(interface, NULL, serverInfo->guaPrefix);
@ -312,18 +315,22 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8],
* /param guaPrefix Prefix which will be removed
* /param mode true trig autonous mode, false define address by default suffics + client id
*/
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode)
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list)
{
int retVal = -1;
dhcpv6_gua_server_entry_s *serverInfo;
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (!serverInfo) {
return -1;
serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (serverInfo) {
serverInfo->enableAddressAutonous = mode;
retVal = 0;
}
return retVal;
serverInfo->enableAddressAutonous = mode;
if (mode) {
serverInfo->disableAddressListAllocation = autonomous_skip_list;
} else {
serverInfo->disableAddressListAllocation = false;
}
return 0;
}
void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[static 16], dhcp_address_prefer_remove_cb *remove_cb, dhcp_address_add_notify_cb *add_cb)
@ -365,18 +372,18 @@ int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static
*/
int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_t guaPrefix[static 16], uint32_t maxClientCount)
{
int retVal = -1;
dhcpv6_gua_server_entry_s *serverInfo;
if (maxClientCount == 0) {
if (maxClientCount == 0 || maxClientCount > MAX_SUPPORTED_ADDRESS_LIST_SIZE) {
return -2;
} else {
serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (serverInfo) {
serverInfo->maxSuppertedClients = maxClientCount;
retVal = 0;
}
}
return retVal;
serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (!serverInfo) {
return -1;
}
serverInfo->maxSupportedClients = maxClientCount;
return 0;
}
/** SET Address Valid Lifetime parameter for allocated address, Default is 7200 seconds
@ -388,18 +395,17 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_
*/
int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t guaPrefix[static 16], uint32_t validLifeTimne)
{
int retVal = -1;
dhcpv6_gua_server_entry_s *serverInfo;
if (validLifeTimne < 120) {
retVal = -2;
} else {
serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (serverInfo) {
serverInfo->validLifetime = validLifeTimne;
retVal = 0;
}
return -2;
}
return retVal;
serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (!serverInfo) {
return -1;
}
serverInfo->validLifetime = validLifeTimne;
return 0;
}
#else
@ -422,11 +428,12 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds)
{
(void) timeUpdateInSeconds;
}
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode)
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list)
{
(void) interface;
(void) guaPrefix;
(void) mode;
(void) autonomous_skip_list;
return -1;
}

View File

@ -66,8 +66,9 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds);
* /param interface interface id of this thread instance.
* /param guaPrefix Prefix which will be removed
* /param mode true trig autonous mode, false define address by default suffics + client id
* /param autonomous_skip_list true skip address list allocation when autonous mode is selected
*/
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode);
int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list);
/* SET max accepted clients to server, Default is 200

View File

@ -202,6 +202,7 @@ typedef struct protocol_interface_rf_mac_setup {
mac_scan_type_t scan_type;
uint8_t mac_channel;
uint8_t mac_tx_start_channel;
//uint8_t cca_failure;
/* MAC TX Queue */
@ -244,6 +245,7 @@ typedef struct protocol_interface_rf_mac_setup {
uint32_t mlme_tick_count;
uint32_t symbol_rate;
uint32_t symbol_time_us;
uint32_t datarate;
uint8_t max_ED;
uint16_t mlme_ED_counter;
mac_tx_status_t mac_tx_status;

View File

@ -57,8 +57,13 @@ uint32_t mac_read_phy_datarate(const fhss_api_t *fhss_api)
if (!mac_setup) {
return 0;
}
uint32_t datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page);
// If datarate is not set, use default 250kbit/s.
uint32_t datarate = 0;
// When channel page is set, ask data rate directly from PHY driver, otherwise use data rate configured to MAC. Ultimately, use default value instead 0.
if (mac_setup->mac_channel_list.channel_page != CHANNEL_PAGE_UNDEFINED) {
datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page);
} else if (mac_setup->datarate) {
datarate = mac_setup->datarate;
}
if (!datarate) {
datarate = 250000;
}

View File

@ -1321,7 +1321,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_
timer_mac_stop(rf_mac_setup);
if (m_event == MAC_CCA_FAIL) {
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_FAIL, 0);
tr_debug("MAC CCA fail");
tr_info("MAC CCA fail");
/* CCA fail */
//rf_mac_setup->cca_failure++;
buf->status = MLME_BUSY_CHAN;
@ -1329,7 +1329,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_COUNT, buf->mac_payload_length);
if (m_event == MAC_TX_FAIL) {
sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_FAIL, 0);
tr_debug("MAC tx fail");
tr_info("MAC tx fail");
buf->status = MLME_TX_NO_ACK;
} else if (m_event == MAC_TX_DONE) {
if (mac_is_ack_request_set(buf) == false) {
@ -1430,7 +1430,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
if (rf_ptr->fhss_api && !buffer->asynch_request) {
// FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) {
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) {
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) {
if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry;
@ -1543,7 +1543,7 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt
mac_header_information_elements_preparation(buffer);
mcps_generic_sequence_number_allocate(rf_ptr, buffer);
mlme_key_descriptor_t *key_desc;
mlme_key_descriptor_t *key_desc = NULL;
if (buffer->fcf_dsn.securityEnabled) {
bool increment_framecounter = false;
//Remember to update security counter here!
@ -1600,7 +1600,7 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt
tr_debug("Too Long %u, %u pa %u header %u mic %u", frame_length, mac_payload_length, buffer->mac_header_length_with_security, buffer->security_mic_len, dev_driver->phy_MTU);
buffer->status = MLME_FRAME_TOO_LONG;
//decrement security counter
if (buffer->fcf_dsn.securityEnabled) {
if (key_desc) {
mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc);
}
return -1;
@ -1716,7 +1716,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in
ccm_globals_t ccm_ptr;
mac_pre_build_frame_t *buffer = &rf_ptr->enhanced_ack_buffer;
mlme_key_descriptor_t *key_desc;
mlme_key_descriptor_t *key_desc = NULL;
if (buffer->fcf_dsn.securityEnabled) {
//Remember to update security counter here!
@ -1755,7 +1755,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in
if ((frame_length) > ack_mtu_size - 2) {
buffer->status = MLME_FRAME_TOO_LONG;
if (buffer->fcf_dsn.securityEnabled) {
if (key_desc) {
//decrement security counter
mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc);
ccm_free(&ccm_ptr);
@ -1921,6 +1921,7 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma
memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
rf_ptr->mac_cca_retry = 0;
rf_ptr->mac_tx_retry = 0;
rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel;
mac_csma_param_init(rf_ptr);
if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
return -1;

View File

@ -783,6 +783,7 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
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);
@ -1090,6 +1091,7 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a
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);

View File

@ -429,7 +429,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
if (rf_ptr->mac_ack_tx_active) {
//Accept direct non crypted acks and crypted only if neighbor is at list
if (rf_ptr->ack_tx_possible || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
if (rf_ptr->ack_tx_possible) {
return PHY_TX_ALLOWED;
}
@ -481,10 +481,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
return 0;
}
//
bool waiting_ack = false;
if (rf_ptr->mac_ack_tx_active) {
mac_data_ack_tx_finish(rf_ptr);
return 0;
@ -506,11 +502,40 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
timer_mac_stop(rf_ptr);
}
if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) {
/* waiting_ack == false allows FHSS to change back to RX channel after transmission
* tx_completed == true allows FHSS to delete stored failure handles
*/
bool waiting_ack = false, tx_completed = false;
if (status == PHY_LINK_TX_SUCCESS && !rf_ptr->macTxRequestAck) {
waiting_ack = false;
tx_completed = true;
} else if (status == PHY_LINK_TX_SUCCESS && rf_ptr->macTxRequestAck) {
waiting_ack = true;
tx_completed = false;
} else if (status == PHY_LINK_CCA_FAIL) {
waiting_ack = false;
tx_completed = false;
} else if (status == PHY_LINK_CCA_OK) {
waiting_ack = false;
tx_completed = false;
} else if (status == PHY_LINK_TX_FAIL) {
waiting_ack = false;
tx_completed = false;
} else if (status == PHY_LINK_TX_DONE) {
waiting_ack = false;
tx_completed = true;
} else if (status == PHY_LINK_TX_DONE_PENDING) {
waiting_ack = false;
tx_completed = true;
}
rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_completed, rf_ptr->active_pd_data_request->msduHandle);
}
switch (status) {
case PHY_LINK_TX_SUCCESS:
if (rf_ptr->macTxRequestAck) {
timer_mac_start(rf_ptr, MAC_TIMER_ACK, rf_ptr->mac_ack_wait_duration); /*wait for ACK 1 ms*/
waiting_ack = true;
} else {
//TODO CHECK this is MAC_TX_ PERMIT OK
mac_tx_done_state_set(rf_ptr, MAC_TX_DONE);
@ -540,15 +565,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
default:
break;
}
if (rf_ptr->fhss_api) {
bool tx_is_done = false;
if (rf_ptr->mac_tx_result == MAC_TX_DONE) {
tx_is_done = true;
}
if (rf_ptr->active_pd_data_request->asynch_request == false) {
rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_is_done, rf_ptr->active_pd_data_request->msduHandle);
}
}
return 0;
}
@ -772,7 +788,7 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr,
return -1;
}
if (rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0 || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
rf_ptr->ack_tx_possible = true;
} else {
rf_ptr->ack_tx_possible = false;
@ -874,6 +890,11 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
if (message->id == MAC15_4_PD_SAP_DATA_IND) {
arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind);
mac_pre_parsed_frame_t *buffer = NULL;
if (pd_data_ind->data_len == 0) {
goto ERROR_HANDLER;
}
if (pd_data_ind->data_len < 3) {
return -1;
}
@ -881,7 +902,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
mac_fcf_sequence_t fcf_read;
const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);
mac_pre_parsed_frame_t *buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
if (buffer && mac_filter_modify_link_quality(rf_ptr->mac_interface_id, buffer) == 1) {
goto ERROR_HANDLER;
}
@ -919,7 +940,12 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
}
ERROR_HANDLER:
mcps_sap_pre_parsed_frame_buffer_free(buffer);
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
if (pd_data_ind->data_len >= 3) {
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
}
if (rf_ptr->fhss_api) {
rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0);
}
return -1;
} else if (message->id == MAC15_4_PD_SAP_DATA_TX_CONFIRM) {

View File

@ -281,6 +281,7 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de
return -1;
}
platform_enter_critical();
mlme_device_descriptor_t *device_ptr = rf_mac_setup->device_description_table + atribute_index;
//Copy description
@ -293,6 +294,24 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de
//tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter);
*device_ptr = *device_descriptor;
if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible &&
device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) {
//Compare address for pending neigbour add
if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) {
uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr);
if (short_id == device_ptr->ShortAddress) {
rf_mac_setup->ack_tx_possible = true;
}
} else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) {
if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) {
rf_mac_setup->ack_tx_possible = true;
}
}
}
platform_exit_critical();
return 0;
}

View File

@ -197,6 +197,20 @@ int ns_sw_mac_fhss_register(mac_api_t *mac_api, fhss_api_t *fhss_api)
return 0;
}
int ns_sw_mac_fhss_unregister(mac_api_t *mac_api)
{
if (!mac_api) {
return -1;
}
// Get a pointer to MAC setup structure
protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_mac_api(mac_api);
if (!mac_setup) {
return -1;
}
mac_setup->fhss_api = NULL;
return 0;
}
struct fhss_api *ns_sw_mac_get_fhss_api(struct mac_api_s *mac_api)
{
if (!mac_api) {

View File

@ -603,6 +603,7 @@ static protocol_interface_info_entry_t *protocol_core_interface_6lowpan_entry_ge
entry->mac_parameters->mac_prev_key_attribute_id = 0;
entry->mac_parameters->mac_default_key_attribute_id = 1;
entry->mac_parameters->mac_next_key_attribute_id = 2;
entry->mac_parameters->mac_default_key_index = 0;
entry->beacon_cb = beacon_received;
@ -1116,10 +1117,10 @@ void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, pro
default:
mac_data_poll_protocol_poll_mode_disable(cur);
if (!cur->rpl_domain) {
tr_debug("NON RPL Ready");
tr_info("NON RPL Ready");
//nwk_protocol_poll_mode_disable(cur->nwk_id, 0);
} else {
tr_debug("RPL Ready");
tr_info("RPL Ready");
}
}
} else {

View File

@ -60,8 +60,8 @@
const uint8_t ADDR_LINK_LOCAL_ALL_RPL_NODES[16] = { 0xff, 0x02, [15] = 0x1a };
/* Sensible default limits for a 6LoWPAN-ND node */
static size_t rpl_purge_threshold = 1 * 1024;
static size_t rpl_alloc_limit = 2 * 1024; // 0 means no limit
static size_t rpl_purge_threshold = 2 * 1024;
static size_t rpl_alloc_limit = 4 * 1024; // 0 means no limit
static size_t rpl_alloc_total;
#define RPL_ALLOC_OVERHEAD 8
@ -190,6 +190,10 @@ void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms)
{
rpl_policy_set_initial_dao_ack_wait(timeout_in_ms);
}
void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size)
{
rpl_policy_set_mrhof_parent_set_size(parent_set_size);
}
/* Send address registration to either specified address, or to non-registered address */
void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16])
@ -247,6 +251,56 @@ bool rpl_control_is_dodag_parent_candidate(protocol_interface_info_entry_t *inte
return false;
}
uint16_t rpl_control_candidate_list_size(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance)
{
if (!interface->rpl_domain) {
return 0;
}
return rpl_instance_address_candidate_count(rpl_instance, false);
}
uint16_t rpl_control_selected_parent_count(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance)
{
if (!interface->rpl_domain) {
return 0;
}
return rpl_instance_address_candidate_count(rpl_instance, true);
}
bool rpl_control_probe_parent_candidate(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16])
{
if (!interface->rpl_domain) {
return false;
}
// go through instances and parents and check if they match the address.
ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) {
if (rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id)) {
return true;
}
}
return false;
}
bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, rpl_instance_t *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx)
{
if (!interface->rpl_domain) {
return false;
}
rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(rpl_instance, ll_addr, interface->id);
if (!neighbour) {
return false;
}
return rpl_instance_possible_better_candidate(rpl_instance, neighbour, candidate_rank, etx);
}
uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t *interface, bool parent_list)
{
@ -266,6 +320,13 @@ uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t
return parent_list_size;
}
void rpl_control_neighbor_delete_from_instance(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, const uint8_t ll_addr[16])
{
rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id);
if (neighbour) {
rpl_delete_neighbour(instance, neighbour);
}
}
void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16])
{
@ -274,14 +335,26 @@ void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, con
}
// go through instances and delete address.
ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) {
rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id);
if (neighbour) {
rpl_delete_neighbour(instance, neighbour);
}
rpl_control_neighbor_delete_from_instance(interface, instance, ll_addr);
}
}
bool rpl_control_find_worst_neighbor(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance, uint8_t ll_addr[static 16])
{
if (!interface->rpl_domain) {
return false;
}
rpl_neighbour_t *neighbour = rpl_lookup_last_candidate_from_list(rpl_instance);
if (neighbour) {
memcpy(ll_addr, rpl_neighbour_ll_address(neighbour), 16);
return true;
}
return false;
}
/* Address changes need to trigger DAO target re-evaluation */
static void rpl_control_addr_notifier(struct protocol_interface_info_entry *interface, const if_address_entry_t *addr, if_address_callback_t reason)
{
@ -307,19 +380,24 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte
static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index)
{
(void)previous_etx;
(void)current_etx;
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id);
if (!cur || !cur->rpl_domain) {
return;
}
// ETX is "better" if now lower, or previous was "unknown" and new isn't infinite
bool better = current_etx < previous_etx || (previous_etx == 0 && current_etx != 0xffff);
rpl_domain_t *domain = cur->rpl_domain;
uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain);
tr_debug("Triggering parent selection due to ETX change on neigh index %u, etx %u", attribute_index, current_etx);
tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx);
rpl_dodag_t *dodag = NULL;
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
rpl_instance_trigger_parent_selection(instance, delay);
if (better) {
dodag = rpl_instance_current_dodag(instance);
}
rpl_instance_trigger_parent_selection(instance, delay, dodag);
if (rpl_instance_am_root(instance)) {
rpl_downward_paths_invalidate(instance);
}
@ -339,6 +417,7 @@ rpl_domain_t *rpl_control_create_domain(void)
domain->callback = NULL;
domain->cb_handle = NULL;
domain->force_leaf = false;
domain->process_routes = true;
ns_list_add_to_start(&rpl_domains, domain);
addr_notification_register(rpl_control_addr_notifier);
@ -495,8 +574,13 @@ rpl_dodag_t *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t instanc
rpl_dodag_t *dodag = rpl_lookup_dodag(instance, dodagid);
if (dodag) {
tr_error("Root DODAG already exists");
return NULL;
if (rpl_dodag_am_root(dodag)) {
tr_error("Root DODAG already exists");
return NULL;
}
// Delete non root information and recreate dodag
rpl_delete_dodag(dodag);
}
dodag = rpl_create_dodag(instance, dodagid, g_mop_prf);
if (!dodag) {
@ -547,13 +631,16 @@ void rpl_control_increment_dtsn(rpl_dodag_t *dodag)
//rpl_dodag_inconsistency(dodag); currently implied by rpl_dodag_increment_dtsn
}
void rpl_control_increment_dodag_version(rpl_dodag_t *dodag)
uint8_t rpl_control_increment_dodag_version(rpl_dodag_t *dodag)
{
uint8_t new_version = 240;
if (rpl_dodag_am_root(dodag)) {
uint8_t new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag));
new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag));
rpl_dodag_set_version_number_as_root(dodag, new_version);
}
return new_version;
}
void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf)
{
@ -586,6 +673,10 @@ void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf)
}
}
}
void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes)
{
domain->process_routes = process_routes;
}
/* Check whether the options section of a RPL control message is well-formed */
static bool rpl_control_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen)
@ -855,7 +946,6 @@ static void rpl_control_process_route_options(rpl_instance_t *instance, rpl_doda
}
rpl_dodag_update_dio_route(dodag, prefix, prefix_len, flags, lifetime, true);
}
/* We do not purge unadvertised routes. Thus if the root wants to purge
* a route before its lifetime is up, stopping advertising it is not
* sufficient, it has to advertise it with low or zero lifetime. This fits
@ -975,8 +1065,9 @@ malformed:
}
}
/* Never listen to nodes in a DODAG we're rooting */
if (rpl_dodag_am_root(dodag)) {
/* Never listen to nodes in a DODAG we're rooting or were root*/
if (rpl_dodag_am_root(dodag) ||
rpl_dodag_was_root(dodag)) {
/* TODO - if version is newer or unordered, increment our version to be higher? */
/* Old code had this trick - actually, would need to go further. Want to listen first, then use a higher
* than existing. */
@ -1009,7 +1100,7 @@ malformed:
const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag);
if (!conf) {
/* TODO - rate limit DIS? */
if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle)) {
if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) {
goto invalid_parent;
}
rpl_control_transmit_dis(domain, cur, RPL_SOLINFO_PRED_DODAGID | RPL_SOLINFO_PRED_INSTANCEID, instance_id, dodagid, 0, buf->src_sa.address);
@ -1043,15 +1134,21 @@ malformed:
/* Now we create the neighbour, if we don't already have a record */
if (!neighbour) {
if (domain->new_parent_add) {
if (!domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) {
goto invalid_parent;
}
}
neighbour = rpl_create_neighbour(version, buf->src_sa.address, cur->id, g_mop_prf, dtsn);
//Call Here new parent create
if (!neighbour) {
goto invalid_parent;
}
if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle)) {
goto invalid_parent;
}
}
@ -1182,7 +1279,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
const rpl_dio_route_list_t *routes = rpl_dodag_get_route_list(dodag);
const prefix_list_t *prefixes = rpl_dodag_get_prefix_list(dodag);
tr_debug("transmit dio, rank: %x", rank);
tr_info("transmit dio, rank: %x", rank);
protocol_interface_info_entry_t *downstream_if = protocol_stack_interface_info_get_by_id(domain->non_storing_downstream_interface);
length = 24;
if (conf) {
@ -1770,12 +1867,24 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print
void rpl_control_print(route_print_fn_t *print_fn)
{
print_fn("RPL memory usage %zu", rpl_alloc_total);
unsigned t = protocol_core_monotonic_time % 10;
unsigned s_full = protocol_core_monotonic_time / 10;
unsigned m = s_full / 60;
unsigned s = s_full % 60;
unsigned h = m / 60;
m %= 60;
// %zu doesn't work on some Mbed toolchains
print_fn("Time %02u:%02u:%02u.%u (%u.%u) RPL memory usage %" PRIu32, h, m, s, t, s_full, t, (uint32_t) rpl_alloc_total);
ns_list_foreach(rpl_domain_t, domain, &rpl_domains) {
rpl_domain_print(domain, print_fn);
}
}
uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain)
{
return rpl_policy_mrhof_parent_set_size(domain);
}
#ifdef RPL_STRUCTURES_H_
#error "rpl_structures.h should not be included by rpl_control.c"
#endif

View File

@ -42,7 +42,8 @@ typedef void rpl_domain_callback_t(rpl_event_t event, void *handle);
typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local);
typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle);
typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank);
typedef struct rpl_domain {
NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances;
@ -54,6 +55,8 @@ typedef struct rpl_domain {
int8_t non_storing_downstream_interface;
/* As part of shutdown, we can force entering leaf mode */
bool force_leaf;
/* if false routes are not set to routing table, instead default route is added for DODAGID */
bool process_routes;
rpl_domain_callback_t *callback;
rpl_prefix_callback_t *prefix_cb;
rpl_new_parent_callback_t *new_parent_add;
@ -129,13 +132,15 @@ struct rpl_dodag *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t in
void rpl_control_delete_dodag_root(rpl_domain_t *domain, struct rpl_dodag *dodag);
void rpl_control_update_dodag_route(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age);
void rpl_control_update_dodag_prefix(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool age);
void rpl_control_increment_dodag_version(struct rpl_dodag *dodag);
uint8_t rpl_control_increment_dodag_version(struct rpl_dodag *dodag);
void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf);
void rpl_control_set_dodag_pref(struct rpl_dodag *dodag, uint8_t pref);
void rpl_control_increment_dtsn(struct rpl_dodag *dodag);
/* Force leaf behaviour on a domain - useful before shutdown, and in conjunction with poison */
void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf);
/*Process routes from DIOs and add those as real routes. if routes are not processed assume DODAGID as default route*/
void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes);
/* Manually send poison on all existing instances a few times */
void rpl_control_poison(rpl_domain_t *domain, uint8_t poison_count);
@ -146,20 +151,28 @@ void rpl_control_delete_domain(rpl_domain_t *domain);
void rpl_control_set_domain_on_interface(struct protocol_interface_info_entry *cur, rpl_domain_t *domain, bool downstream);
void rpl_control_remove_domain_from_interface(struct protocol_interface_info_entry *cur);
void rpl_control_free_domain_instances_from_interface(struct protocol_interface_info_entry *cur);
void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle);
void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle);
/* Target publishing */
void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime);
void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]);
bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
bool rpl_control_is_dodag_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint16_t candidate_cmp_limiter);
uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list);
bool rpl_control_probe_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx);
uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list);
uint16_t rpl_control_candidate_list_size(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance);
uint16_t rpl_control_selected_parent_count(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance);
void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]);
void rpl_control_neighbor_delete_from_instance(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16]);
bool rpl_control_find_worst_neighbor(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, uint8_t ll_addr[16]);
/* Parent link confirmation API extension */
void rpl_control_request_parent_link_confirmation(bool requested);
void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count);
void rpl_control_set_dao_retry_count(uint8_t count);
void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms);
void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size);
void rpl_control_register_address(struct protocol_interface_info_entry *interface, const uint8_t addr[16]);
void rpl_control_address_register_done(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t status);
@ -176,6 +189,7 @@ bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl
const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_instance *instance);
const uint8_t *rpl_control_preferred_parent_addr(const struct rpl_instance *instance, bool global);
uint16_t rpl_control_current_rank(const struct rpl_instance *instance);
uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain);
#else /* HAVE_RPL */
@ -185,6 +199,8 @@ uint16_t rpl_control_current_rank(const struct rpl_instance *instance);
#define rpl_control_free_domain_instances_from_interface(cur) ((void) 0)
#define rpl_control_register_address(interface, addr) ((void) 0)
#define rpl_control_address_register_done(interface, ll_addr, status) ((void) 0)
#define rpl_policy_mrhof_parent_set_size_get(domain) (0)
#define rpl_control_set_mrhof_parent_set_size(parent_set_size)
#endif /* HAVE_RPL */

View File

@ -545,8 +545,7 @@ retry:
*/
ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
if (neighbour->dao_path_control & unassigned_pc) {
unassigned_pc &= neighbour->dao_path_control;
*path_control = unassigned_pc;
*path_control = neighbour->dao_path_control;
*parent = neighbour;
return target;
}
@ -561,14 +560,7 @@ retry:
}
}
/* If looking for a follow-up target, final path control must match */
if (t1) {
if (unassigned_pc != *path_control) {
continue;
}
} else {
*path_control = unassigned_pc;
}
*path_control = target->path_control;
return target;
}
@ -1786,7 +1778,7 @@ static bool rpl_instance_push_address_registration(protocol_interface_info_entry
if (!buf) {
return false;
}
tr_debug("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address));
tr_info("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address));
protocol_push(buf);
return true;
}
@ -1811,6 +1803,8 @@ static void rpl_instance_address_registration_cancel(rpl_instance_t *instance)
instance->wait_response = NULL;
instance->pending_neighbour_confirmation = false;
instance->delay_dao_timer = 0;
instance->dao_in_transit = false;
instance->dao_retry_timer = 0;
}
void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint16_t seconds)

View File

@ -45,12 +45,14 @@
static void rpl_mrhof_parent_selection(rpl_instance_t *instance);
static uint16_t rpl_mrhof_path_cost_through_neighbour(const rpl_neighbour_t *neighbour);
static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour);
static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx);
static rpl_objective_t rpl_mrhof = {
.ocp = RPL_OCP_MRHOF,
.parent_selection = rpl_mrhof_parent_selection,
.path_cost = rpl_mrhof_path_cost_through_neighbour,
.neighbour_acceptable = rpl_mrhof_neighbour_acceptable,
.possible_better_candidate = rpl_mrhof_possible_better_candidate,
};
typedef struct rpl_of0_params {
@ -94,6 +96,26 @@ static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const
return rpl_mrhof_link_metric_to_neighbour(neighbour) <= rpl_policy_mrhof_max_link_metric(instance->domain);
}
static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx)
{
uint16_t existing_path = rpl_mrhof_path_cost_through_neighbour(existing);
// Optimistically assume we could get a perfect link to this new person
// But add hysteresis to avoid switching unless potentially worthwhile
// (Compare rpl_mrhof_etx which assumes poor for unknown as a sort of hysteresis)
// Think: could actually use rpl_mrhof_etx here to get an existing ETX estimate
// (except that gives infinite if no current link, would want a variant that checks
// blacklist records for remembered poor ETX)
uint16_t threshold = rpl_policy_mrhof_parent_switch_threshold(instance->domain);
if (etx == 0) {
etx = 128;
} else if (etx >= (0xffff - threshold)) {
return false;
}
etx += threshold;
uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, etx);
return potential_path_with_hysteresis <= existing_path;
}
/* Given a preferred parent, we are only permitted to stretch our above the
* path cost through that parent by a certain (policy) amount to accommodate a

View File

@ -28,9 +28,12 @@ typedef struct rpl_objective {
uint16_t ocp;
/* Run the parent selection algorithm - see rpl_of0.c for detailed info */
void (*parent_selection)(struct rpl_instance *);
/* Return the path cost of a neighbour (for debug prints only) */
/* Return the path cost of a neighbour */
uint16_t (*path_cost)(const struct rpl_neighbour *);
bool (*neighbour_acceptable)(const struct rpl_instance *, const struct rpl_neighbour *);
/* Could someone with specified rank be a significantly better candidate than the existing one? */
/* (In future, this API could be extended to pass a metric pointer as well as rank) */
bool (*possible_better_candidate)(const struct rpl_instance *, const struct rpl_neighbour *existing, uint16_t rank, uint16_t etx);
ns_list_link_t link;
} rpl_objective_t;

View File

@ -42,12 +42,14 @@
static void rpl_of0_parent_selection(rpl_instance_t *instance);
static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour);
static bool rpl_of0_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour);
static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx);
static rpl_objective_t rpl_of0 = {
.ocp = RPL_OCP_OF0,
.parent_selection = rpl_of0_parent_selection,
.path_cost = rpl_of0_rank_through_neighbour,
.neighbour_acceptable = rpl_of0_neighbour_acceptable,
.possible_better_candidate = rpl_of0_possible_better_candidate,
};
#define DEFAULT_STEP_OF_RANK 3
@ -115,6 +117,14 @@ static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour)
return rpl_rank_add(neighbour->rank, rpl_of0_rank_increase(neighbour));
}
static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx)
{
(void)etx;
uint16_t existing_path = rpl_of0_rank_through_neighbour(existing);
uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, 2 * rpl_policy_of0_rank_factor(instance->domain) * existing->dodag_version->dodag->config.min_hop_rank_increase);
return potential_path_with_hysteresis <= existing_path;
}
/* Given a preferred parent, we are only permitted to stretch our above the
* path cost through that parent by a certain (policy) amount to accommodate a
* bigger parent set.

View File

@ -39,7 +39,7 @@ static int8_t rpl_policy_dao_retry_count_conf = 0;
static int16_t rpl_policy_dao_initial_timeout_conf = 20; // Default is 2 seconds 100ms ticks
static uint16_t rpl_policy_dio_validity_period_hysteresis = 0x0180; //Fixed Point 1.5
static uint8_t rpl_policy_multicast_config_min_advertisment_count = 0;
static uint8_t rpl_policy_mrhof_parent_set_size_conf = 3; // default parent set size
/* TODO - application API to control when to join new instances / DODAGs
*
@ -147,7 +147,7 @@ int8_t rpl_policy_dao_retry_count()
/* Given the next-hop address from a source routing header, which interface,
* if any, should we assume that next hop is on?
*/
#define ETX_SRH_THRESHOLD 0x800 /* 8.8 fixed-point, so 4 */
#define ETX_SRH_THRESHOLD 0x400 /* 8.8 fixed-point, so 4 */
int8_t rpl_policy_srh_next_hop_interface(rpl_domain_t *domain, int8_t if_id, const uint8_t *next_hop)
{
if (domain->non_storing_downstream_interface != -1) {
@ -326,11 +326,16 @@ uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain)
return 1;
}
void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size)
{
rpl_policy_mrhof_parent_set_size_conf = parent_set_size;
}
uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain)
{
(void)domain;
return 3;
return rpl_policy_mrhof_parent_set_size_conf;
}
uint16_t rpl_policy_mrhof_max_rank_stretch_for_extra_parents(const rpl_domain_t *domain)

View File

@ -59,6 +59,7 @@ uint_fast8_t rpl_policy_of0_rank_factor(const rpl_domain_t *domain);
bool rpl_policy_of0_dodag_preference_supersedes_grounded(const rpl_domain_t *domain);
uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain);
void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size);
uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain);
uint16_t rpl_policy_mrhof_max_link_metric(const rpl_domain_t *domain);
uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain);

View File

@ -32,10 +32,6 @@
struct rpl_objective;
/* Descriptor for a RPL neighbour within a DODAG
*
* The neighbour is normally associated with a DODAG Version, but may not be,
* if the version has been retired, and we haven't since heard from that
* neighbour. In that case dodag_version is NULL.
*
* Note that global address is only needed with downward routes, but I don't
* think it's worth optimising for an "upward-only" build. (Unless to be a RPL
@ -45,7 +41,7 @@ struct rpl_objective;
* first in the instance candidate_neighbour list, in order of preference.
*/
struct rpl_neighbour {
rpl_dodag_version_t *dodag_version; // Back pointer to DODAG Version (may be NULL, if not dodag_parent)
rpl_dodag_version_t *dodag_version; // Back pointer to DODAG Version
uint8_t ll_address[16]; // Link-local address (source of DIO)
uint8_t global_address[16]; // Global address (from DIO RIO)
bool dodag_parent: 1; // This is a DODAG parent (if true, dodag_version may not be NULL)
@ -87,10 +83,11 @@ struct rpl_dodag {
rpl_dodag_conf_t config; /* Configuration from DIO */
uint8_t info_version; /* Version for g_mop_prf and config */
bool root: 1; /* We are the root of this DODAG */
bool was_root: 1; /* If we have ever been a root in this DODAG */
bool leaf: 1; /* We are a leaf in this DODAG (by policy) */
bool have_config: 1; /* We have the config */
bool used: 1; /* We have ever been a member of this DODAG? */
uint8_t new_config_advertisment_count; /* We have advertiment new config at multicasti DIO */
uint8_t new_config_advertisment_count; /* We have advertiment new config at multicasti DIO max updated value is 0xfe*/
NS_LIST_HEAD(rpl_dodag_version_t, link) versions; /* List of DODAG versions (newest first) */
prefix_list_t prefixes; /* Prefixes advertised in DIO PIOs */
rpl_dio_route_list_t routes; /* Routes advertised in DIO RIOs*/

View File

@ -74,6 +74,8 @@ static NS_LIST_DEFINE(rpl_candidate_neighbour_set, rpl_neighbour_t, candidate_ne
static void rpl_instance_remove_parents(rpl_instance_t *instance);
static void rpl_instance_remove_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent);
static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *route);
static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t *instance);
static uint32_t rpl_dio_imax_time_calculate(uint16_t Imax, uint16_t fixed_point);
/* Rank comparison, and DAGRank(rank) */
uint16_t nrpl_dag_rank(const rpl_dodag_t *dodag, uint16_t rank)
@ -283,6 +285,16 @@ rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance)
return neighbour;
}
uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate)
{
return candidate->rank;
}
bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx)
{
return instance->of->possible_better_candidate(instance, replacing, candidate_rank, etx);
}
/* If we're a member of a DODAG Version matching the predicate in this instance,
* return it. Mainly used for handling DODAG Information Solicitations.
*/
@ -340,10 +352,19 @@ void rpl_instance_force_leaf(rpl_instance_t *instance)
instance->current_rank = RPL_RANK_INFINITE;
}
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay)
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag)
{
/* When "improving", let us have a minimum trigger time based on Imin, for large networks */
if (dodag) {
//Convert imin 100ms tick to seconds
uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10;
if (i_min_delay > delay) {
delay = i_min_delay;
}
}
if (instance->parent_selection_timer == 0 || instance->parent_selection_timer > delay) {
instance->parent_selection_timer = randLIB_randomise_base(delay, 0x7333, 0x8CCD) /* +/- 10% */;
instance->parent_selection_timer = randLIB_randomise_base(delay, 0x8000, 0x999A) /* Random between delay * 1.0-1.2 */;
tr_debug("Timed parent triggered %u", instance->parent_selection_timer);
}
}
@ -390,6 +411,15 @@ rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instan
return NULL;
}
rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance)
{
rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance);
if (neighbour && neighbour->considered && !neighbour->dodag_parent) {
return neighbour;
}
return NULL;
}
rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_t *addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn)
{
/* Should gate higher-rank neighbours here - ignore higher-rank neighbours
@ -563,7 +593,7 @@ void rpl_delete_dodag_version(rpl_dodag_version_t *version)
// triggering poison immediately.
// Give parent selection a chance to select another version (but will it have any info on-hand?)
instance->current_dodag_version = NULL;
rpl_instance_trigger_parent_selection(instance, 5);
rpl_instance_trigger_parent_selection(instance, 5, NULL);
}
ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
@ -638,6 +668,7 @@ rpl_dodag_t *rpl_create_dodag(rpl_instance_t *instance, const uint8_t *dodagid,
memcpy(dodag->id, dodagid, 16);
dodag->leaf = false;
dodag->root = false;
dodag->was_root = false;
dodag->have_config = false;
dodag->used = false;
dodag->g_mop_prf = g_mop_prf;
@ -678,15 +709,9 @@ void rpl_delete_dodag_root(rpl_dodag_t *dodag)
{
// This should trigger immediate poison
rpl_instance_set_dodag_version(dodag->instance, NULL, RPL_RANK_INFINITE);
// Deleting DODAG is not ideal - we will just pick up adverts from our
// former children, and recreate, possibly violating the MaxRankIncrease.
// Should retain DODAG version info and just unset root flag, which will
// limit what happens when we hear adverts.
// Problem is rpl_control_create_dodag_root which can't handle the
// case where DODAG already exists. This would always be a problem if
// we'd heard adverts in between delete and create, but would be an instant
// problem without this delete. Need to fix.
rpl_delete_dodag(dodag);
// Retain DODAG version info and just unset root flag
// We have was_root still set which will drop adverts for this dodag.
dodag->root = false;
}
/* Convert RPL configuration to generic trickle parameters. Returns true if
@ -792,6 +817,7 @@ void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root)
dodag->root = root;
if (root) {
rpl_instance_remove_parents(dodag->instance);
dodag->was_root = true;
} else {
rpl_instance_run_parent_selection(dodag->instance);
}
@ -803,6 +829,11 @@ bool rpl_dodag_am_root(const rpl_dodag_t *dodag)
{
return dodag->root;
}
bool rpl_dodag_was_root(const rpl_dodag_t *dodag)
{
return dodag->was_root;
}
#endif
void rpl_dodag_set_leaf(rpl_dodag_t *dodag, bool leaf)
@ -1163,10 +1194,20 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
{
rpl_neighbour_t *worst = NULL;
bool worst_acceptable = false;
bool worst_old = false;
/* Parents will be first - loop backwards so we take non-parents first */
ns_list_foreach_reverse(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
bool acceptable = instance->of->neighbour_acceptable(instance, neighbour);
bool old;
if (!neighbour->dodag_version) {
old = true;
} else {
uint32_t age = protocol_core_monotonic_time - neighbour->dio_timestamp;
uint32_t age_threshold = rpl_dio_imax_time_calculate(neighbour->dodag_version->dodag->dio_timer_params.Imax,
rpl_policy_dio_validity_period(instance->domain));
old = age > age_threshold;
}
if (!worst) {
goto new_worst;
}
@ -1176,6 +1217,13 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
break;
}
/* Prefer neighbours with DODAG version */
if (neighbour->dodag_version && !worst->dodag_version) {
continue;
} else if (!neighbour->dodag_version && worst->dodag_version) {
goto new_worst;
}
/* Prefer to purge "unacceptable" neighbours according to OF */
if (acceptable && !worst_acceptable) {
continue;
@ -1183,18 +1231,24 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t
goto new_worst;
}
/* Prefer to purge least-recently-heard-from */
uint32_t neighbour_age = protocol_core_monotonic_time - neighbour->dio_timestamp;
uint32_t worst_age = protocol_core_monotonic_time - worst->dio_timestamp;
if (neighbour_age <= worst_age) {
/* Prefer to purge old neighbours */
if (old && !worst_old) {
continue;
} else {
} else if (!old && worst_old) {
goto new_worst;
}
/* Tiebreak by path cost, assuming we have dodag_version */
if (neighbour->dodag_version && instance->of) {
/* worst must also have version to reach this tiebreak */
if (instance->of->path_cost(neighbour) <= instance->of->path_cost(worst)) {
continue;
}
}
new_worst:
worst = neighbour;
worst_acceptable = acceptable;
worst_old = old;
}
return worst;
@ -1225,24 +1279,19 @@ bool rpl_instance_purge(rpl_instance_t *instance)
*/
rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance);
if (neighbour && neighbour->considered && !neighbour->dodag_parent && neighbour->dao_path_control == 0) {
tr_debug("Candidate Purge: Remove %s", trace_ipv6(neighbour->ll_address));
rpl_delete_neighbour(instance, neighbour);
return true;
}
return false;
}
void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag)
void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag)
{
instance->neighbours_changed = true;
uint16_t delay = rpl_policy_dio_parent_selection_delay(instance->domain);
if (dodag) {
//Convert imin 100ms tick to seconds
uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10;
if (i_min_delay > delay) {
delay = i_min_delay;
}
}
rpl_instance_trigger_parent_selection(instance, delay);
rpl_instance_trigger_parent_selection(instance, delay, dodag);
}
static void rpl_instance_remove_parents(rpl_instance_t *instance)
@ -1315,6 +1364,10 @@ void rpl_dodag_update_implicit_system_routes(rpl_dodag_t *dodag, rpl_neighbour_t
/* Also add a specific route to the DODAGID */
ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric);
/* Check if we assume default route to DODAGID */
if (!dodag->instance->domain->process_routes) {
ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric);
}
}
/* Called when a DIO RIO route has been updated (but not the parent list) */
@ -1323,9 +1376,13 @@ static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *r
if (!rpl_dodag_is_current(dodag)) {
return;
}
rpl_instance_t *instance = dodag->instance;
if (!instance->domain->process_routes) {
// We dont add actual routes and only create default route throuh DODAGID
return;
}
ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
if (neighbour->dodag_parent) {
rpl_instance_update_system_dio_route(instance, neighbour, route);
@ -1340,6 +1397,11 @@ static void rpl_instance_update_system_routes_through_parent(rpl_instance_t *ins
rpl_dodag_update_implicit_system_routes(dodag, parent);
if (!instance->domain->process_routes) {
// We dont add actual routes and only create default route through DODAGID
return;
}
/* Then add the specific routes listed in the DIO as ROUTE_RPL_DIO */
ns_list_foreach(rpl_dio_route_t, route, &dodag->routes) {
rpl_instance_update_system_dio_route(instance, parent, route);
@ -1381,13 +1443,15 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
return;
}
if (instance->current_dodag_version && instance->current_dodag_version->dodag->root) {
if (instance->current_dodag_version &&
(instance->current_dodag_version->dodag->root || instance->current_dodag_version->dodag->was_root)) {
return;
}
ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) {
//Remove a Parent candidates which are not heared a long time ago and not slected ones
if (!n->dodag_parent && (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0)) {
tr_debug("Candidate timeout: Remove %s", trace_ipv6(n->ll_address));
rpl_delete_neighbour(instance, n);
continue;
}
@ -1429,7 +1493,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
if (original_preferred != preferred_parent) {
protocol_stats_update(STATS_RPL_PARENT_CHANGE, 1);
if (preferred_parent) {
tr_debug("New preferred parent %s", trace_array(preferred_parent->ll_address, 16));
tr_info("New preferred parent %s", trace_array(preferred_parent->ll_address, 16));
}
}
@ -1479,6 +1543,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance)
continue;
}
if (!instance->of->neighbour_acceptable(instance, n)) {
tr_debug("Candidate not acceptable: Remove %s", trace_ipv6(n->ll_address));
rpl_delete_neighbour(instance, n);
}
}
@ -1560,7 +1625,9 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_
conf = &dodag->config;
} else if (dodag->new_config_advertisment_count < rpl_policy_dio_multicast_config_advertisment_min_count()) {
conf = &dodag->config;
dodag->new_config_advertisment_count++;
if (dodag->new_config_advertisment_count < 0xfe) {
dodag->new_config_advertisment_count++;
}
} else {
conf = NULL;
}
@ -1699,7 +1766,7 @@ bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t *
return false;
}
uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents)
uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents)
{
uint16_t parent_list = 0;
@ -1717,7 +1784,6 @@ uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool sel
return parent_list;
}
void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr)
{
ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
@ -1767,17 +1833,21 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks)
if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) {
return;
}
// We dont have any valid address in interface
if (ns_list_count(&instance->dao_targets) == 0) {
return;
}
/* Address registrations for parent ongoing*/
if (rpl_policy_parent_confirmation_requested() && instance->pending_neighbour_confirmation) {
return;
}
/* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */
if (instance->dao_in_transit || instance->delay_dao_timer > 0) {
return;
/* Delay sending first DIO if we are still potentially gathering info */
/* Important to always send DIOs if we ever have sent any, so we can indicate problems to others */
if (!instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) {
// We dont have any valid address in interface
if (ns_list_count(&instance->dao_targets) == 0) {
return;
}
/* Address registrations for parent ongoing*/
if (instance->pending_neighbour_confirmation) {
return;
}
/* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */
if (instance->dao_in_transit || instance->delay_dao_timer > 0) {
return;
}
}
if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) {
instance->dio_not_consistent = false;

View File

@ -70,6 +70,7 @@ bool rpl_instance_am_root(const rpl_instance_t *instance);
uint8_t rpl_instance_mop(const rpl_instance_t *instance);
rpl_dodag_version_t *rpl_instance_current_dodag_version(const rpl_instance_t *instance);
rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance);
bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx);
rpl_dodag_version_t *rpl_instance_predicate_match(rpl_instance_t *instance, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, uint8_t version_num);
void rpl_instance_inconsistency(rpl_instance_t *instance);
void rpl_instance_consistent_rx(rpl_instance_t *instance);
@ -77,15 +78,16 @@ void rpl_instance_increment_dtsn(rpl_instance_t *instance);
void rpl_dodag_set_pref(rpl_dodag_t *dodag, uint8_t pref);
void rpl_instance_poison(rpl_instance_t *instance, uint8_t count);
void rpl_instance_force_leaf(rpl_instance_t *instance);
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay);
void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag);
void rpl_instance_remove_interface(rpl_instance_t *instance, int8_t if_id);
void rpl_instance_dio_trigger(rpl_instance_t *instance, struct protocol_interface_info_entry *cur, const uint8_t *addr);
void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair);
bool rpl_instance_local_repair(const rpl_instance_t *instance);
uint16_t rpl_instance_current_rank(const rpl_instance_t *instance);
uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate);
bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr);
bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t *ipv6_addr, uint16_t candidate_amount);
uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents);
uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents);
void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr);
void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds);
@ -97,8 +99,10 @@ uint8_t rpl_dodag_mop(const rpl_dodag_t *dodag);
void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root);
#ifdef HAVE_RPL_ROOT
bool rpl_dodag_am_root(const rpl_dodag_t *dodag);
bool rpl_dodag_was_root(const rpl_dodag_t *dodag);
#else
#define rpl_dodag_am_root(dodag) false
#define rpl_dodag_was_root(dodag) false
#endif
uint8_t rpl_dodag_get_version_number_as_root(const rpl_dodag_t *dodag);
void rpl_dodag_set_version_number_as_root(rpl_dodag_t *dodag, uint8_t number);
@ -131,6 +135,7 @@ void rpl_dodag_version_raise_greediness(rpl_dodag_version_t *version, uint16_t p
bool rpl_dodag_version_rank_indicates_possible_sub_dodag(const rpl_dodag_version_t *version, uint16_t rank);
rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instance, const uint8_t *addr, int8_t if_id);
rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance);
rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *instance, const uint8_t *ll_addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn);
void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour);
bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, const uint8_t *src, bool *become_leaf);
@ -142,7 +147,7 @@ bool rpl_neighbour_update_dtsn(rpl_neighbour_t *neighbour, uint8_t dtsn);
rpl_instance_t *rpl_neighbour_instance(const rpl_neighbour_t *neighbour);
void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag);
void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag);
void rpl_instance_run_parent_selection(rpl_instance_t *instance);
void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn);

View File

@ -229,6 +229,7 @@ uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suit
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
thep->client_knows_standard_ecc_ciphersuite = true;
/* no break */
/* fall through */
case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_COMPAT:
tr_debug("Client Sup ECC");
ret_val |= SEC_CIPHERSUITE_ECC;

View File

@ -53,16 +53,24 @@ typedef enum {
EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED
} eap_tls_sec_prot_state_e;
// Filters initial EAPOL-key re-transmission bursts
#define BURST_FILTER_TIMER_TIMEOUT 5 * 10
// How many times initial EAPOL-key is accepted on wait for identity response state
#define INITIAL_EAPOL_KEY_MAX_COUNT 2
typedef struct {
sec_prot_common_t common; /**< Common data */
sec_prot_t *tls_prot; /**< TLS security protocol */
eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */
tls_data_t tls_send; /**< EAP-TLS send buffer */
tls_data_t tls_recv; /**< EAP-TLS receive buffer */
uint16_t burst_filt_timer; /**< Burst filter timer */
uint8_t eap_id_seq; /**< EAP sequence */
uint8_t recv_eap_id_seq; /**< Last received EAP sequence */
uint8_t eap_code; /**< Received EAP code */
uint8_t eap_type; /**< Received EAP type */
uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */
int8_t tls_result; /**< Result of TLS operation */
bool wait_tls: 1; /**< Wait TLS (ECC calculation) before sending EAP-TLS message */
bool tls_ongoing: 1; /**< TLS handshake is ongoing */
@ -151,13 +159,15 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot)
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT);
data->tls_prot = NULL;
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
data->eap_id_seq = 0;
data->recv_eap_id_seq = 0;
data->eap_code = 0;
data->eap_type = 0;
eap_tls_sec_prot_lib_message_init(&data->tls_recv);
eap_tls_sec_prot_lib_message_init(&data->tls_send);
data->tls_result = EAP_TLS_RESULT_ERROR;
data->tls_result = EAP_TLS_RESULT_ERROR;
data->init_key_cnt = 0;
data->wait_tls = false;
data->tls_ongoing = false;
data->send_pending = false;
@ -186,13 +196,31 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_
// Decoding is successful
if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
// Handle only EAP messages (ignore initial EAPOL-key retransmissions)
// Handle EAP messages
if (data->recv_eapol_pdu.packet_type == EAPOL_EAP_TYPE) {
data->eap_code = data->recv_eapol_pdu.msg.eap.eap_code;
data->eap_type = data->recv_eapol_pdu.msg.eap.type;
// Call state machine
prot->state_machine(prot);
} else if (data->recv_eapol_pdu.packet_type == EAPOL_KEY_TYPE &&
sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_ID) {
/* If initial EAPOL-key transmission arrives to first EAP-TLS wait state i.e.
* when waiting for identity response, triggers re-transmission of identity
* request. This allows the supplicant to start EAP-TLS right away, if it has
* missed the original identity request.
*/
if (data->burst_filt_timer == 0 && data->init_key_cnt < INITIAL_EAPOL_KEY_MAX_COUNT) {
tr_info("EAP-TLS: initial EAPOL-key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
sec_prot_result_set(&data->common, SEC_RESULT_TIMEOUT);
// Call state machine
prot->state_machine(prot);
// Resets trickle timer to give time for supplicant to answer
sec_prot_timer_trickle_start(&data->common, &eap_tls_trickle_params);
data->init_key_cnt++;
}
// Filters repeated initial EAPOL-key messages
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
}
ret_val = 0;
}
@ -288,6 +316,13 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
if (data->burst_filt_timer > ticks) {
data->burst_filt_timer -= ticks;
} else {
data->burst_filt_timer = 0;
}
sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks);
}

View File

@ -72,10 +72,10 @@ typedef struct {
bool send_pending: 1; /**< TLS data is not yet send to network */
} eap_tls_sec_prot_int_t;
#define FWH_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay
#define FWH_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay
#define EAP_TLS_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay
#define EAP_TLS_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay
static uint16_t retry_timeout = FWH_RETRY_TIMEOUT_SMALL;
static uint16_t retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL;
static uint16_t supp_eap_tls_sec_prot_size(void);
static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot);
@ -93,7 +93,7 @@ static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks
static int8_t supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot);
static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot);
static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot);
static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot);
#define eap_tls_sec_prot_get(prot) (eap_tls_sec_prot_int_t *) &prot->data
@ -113,9 +113,9 @@ int8_t supp_eap_tls_sec_prot_register(kmp_service_t *service)
int8_t supp_eap_sec_prot_timing_adjust(uint8_t timing)
{
if (timing < 16) {
retry_timeout = FWH_RETRY_TIMEOUT_SMALL;
retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL;
} else {
retry_timeout = FWH_RETRY_TIMEOUT_LARGE;
retry_timeout = EAP_TLS_RETRY_TIMEOUT_LARGE;
}
return 0;
}
@ -493,7 +493,10 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
}
// Store sequence ID
supp_eap_tls_sec_prot_seq_id_update(prot);
if (supp_eap_tls_sec_prot_seq_id_update(prot)) {
// When receiving a new sequence number, adds more time for re-send if no response
data->common.ticks = retry_timeout;
}
// All fragments received for a message
if (result == EAP_TLS_MSG_RECEIVE_DONE && data->tls_ongoing) {
@ -524,10 +527,6 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
// Send EAP response
supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING);
data->send_pending = false;
// Add more time for re-send if no response
data->common.ticks = retry_timeout;
break;
case EAP_TLS_STATE_FINISH:
@ -550,10 +549,16 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
}
}
static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot)
static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot)
{
eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
bool new_seq_id = false;
if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) {
new_seq_id = true;
}
data->eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq;
return new_seq_id;
}
#endif /* HAVE_WS */

View File

@ -414,7 +414,8 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
if (auth_fwh_sec_prot_mic_validate(prot) < 0) {
return;
}
// PTK is fresh for installing any GTKs
sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys);
// If GTK was inserted set it valid
sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
// Reset PTK mismatch

View File

@ -315,6 +315,9 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params);
sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2);
// Store the hash for to-be installed GTK as used for the PTK
sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys);
break;
// Wait GKH message 2

View File

@ -318,10 +318,10 @@ static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e
// Indicates TX failure
if (tx_status == SEC_PROT_TX_ERR_TX_NO_ACK) {
sec_prot_result_set(&data->common, KMP_RESULT_ERR_TX_NO_ACK);
sec_prot_result_set(&data->common, SEC_RESULT_ERR_TX_NO_ACK);
} else if (tx_status != SEC_PROT_TX_OK) {
// Indicates other failure
sec_prot_result_set(&data->common, KMP_RESULT_ERR_UNSPEC);
sec_prot_result_set(&data->common, SEC_RESULT_ERR_UNSPEC);
}
prot->state_machine_call(prot);
return 0;

View File

@ -38,6 +38,8 @@
#define TRACE_GROUP "spke"
static const uint8_t empty_hash[GTK_HASH_LEN] = {0};
sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs)
{
sec_prot_keys_t *sec_keys = ns_dyn_mem_alloc(sizeof(sec_prot_keys_t));
@ -67,6 +69,7 @@ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, co
sec_keys->ptk_eui_64_set = false;
sec_keys->pmk_mismatch = false;
sec_keys->ptk_mismatch = false;
sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_keys);
}
void sec_prot_keys_delete(sec_prot_keys_t *sec_keys)
@ -581,9 +584,22 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhas
}
}
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash)
int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash)
{
return sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
}
int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk)
{
uint8_t gtk_hash[8];
sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
// Checks if GTK hash for the GTK would be all zero
if (memcmp(gtk_hash, empty_hash, GTK_HASH_LEN) == 0) {
return -1;
}
return 0;
}
gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
@ -639,7 +655,6 @@ gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t
bool sec_prot_keys_gtk_hash_empty(uint8_t *gtkhash)
{
const uint8_t empty_hash[GTK_HASH_LEN] = {0};
if (memcmp(gtkhash, empty_hash, GTK_HASH_LEN) == 0) {
return true;
} else {
@ -783,4 +798,57 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks)
return count;
}
void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys)
{
for (uint8_t index = 0; index < GTK_NUM; index++) {
memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN);
}
sec_keys->ins_gtk_hash_set = 0;
}
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys)
{
if (sec_keys->gtk_set_index >= 0) {
uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index);
if (!gtk) {
return;
}
uint8_t gtk_hash[GTK_HASH_LEN];
if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) {
return;
}
/* Store two byte hash. This is long enough for the GTK installed check, since
* possible conflict between hashes causes only that 4WH is initiated/is not
* initiated instead of GKH.
*/
memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN);
sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index);
}
}
bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index)
{
if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) {
return false;
}
uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, gtk_index);
if (!gtk) {
return false;
}
// Calculated GTK hash for the current GTK on the defined index
uint8_t gtk_hash[GTK_HASH_LEN];
if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) {
return false;
}
// If PTK has been used to install different GTK to index than the current one, trigger mismatch
if (memcmp(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN) != 0) {
return true;
}
return false;
}
#endif /* HAVE_WS */

View File

@ -54,6 +54,7 @@
#define GTK_HASH_LEN 8
#define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM
#define INS_GTK_HASH_LEN 2
#define PMK_LIFETIME_INSTALL 0xFFFFF
#define PTK_LIFETIME_INSTALL 0xFFFFF
@ -71,18 +72,24 @@ typedef struct {
bool updated: 1; /**< Group Transient Keys has been updated */
} sec_prot_gtk_keys_t;
typedef struct {
uint8_t hash[INS_GTK_HASH_LEN]; /**< Inserted GTKs for a PTK hash */
} sec_prot_gtk_hash_t;
// Security key data
typedef struct {
uint64_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */
uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */
uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */
uint8_t ptk_eui_64[8]; /**< Remote EUI-64 used to derive PTK or NULL */
sec_prot_gtk_hash_t ins_gtk_hash[GTK_NUM]; /**< Hashes for inserted GTKs for a PTK */
sec_prot_gtk_keys_t *gtks; /**< Group Transient Keys */
const sec_prot_certs_t *certs; /**< Certificates */
uint32_t pmk_lifetime; /**< PMK lifetime in seconds */
uint32_t ptk_lifetime; /**< PTK lifetime in seconds */
uint8_t gtkl; /**< Remote GTKL information */
int8_t gtk_set_index; /**< Index of GTK to set */
unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */
bool pmk_set: 1; /**< Pairwise Master Key set */
bool ptk_set: 1; /**< Pairwise Transient Key set */
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
@ -95,7 +102,8 @@ typedef struct {
// Frame counter data
typedef struct {
uint8_t gtk[GTK_LEN]; /**< GTK of the frame counter */
uint32_t frame_counter; /**< Frame counter */
uint32_t frame_counter; /**< Current frame counter */
uint32_t stored_frame_counter; /**< Stored Frame counter */
bool set : 1; /**< Value has been set */
} frame_counter_t;
@ -649,8 +657,20 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtk_ha
* \param gtk GTK key
* \param gtk_hash GTK hash for a GTK
*
* \return < 0 failure
* \return >= 0 success
*/
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash);
int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash);
/**
* sec_prot_keys_gtk_valid_check check if GTK is valid
*
* \param gtk GTK key
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk);
/**
* sec_prot_keys_gtks_hash_update update GTKs based on GTK hash
@ -751,4 +771,30 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks);
*/
uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_ptk_installed_gtk_hash_clear_all clear GTK hashes of the GTKs that has been installed
* to supplicant using the PTK
* \param sec_keys security keys
*
*/
void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_installed_gtk_hash_set set GTK hash of the GTK that has been installed
* to supplicant using the current PTK
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index
* for the supplicant i.e. GTK hash would change
*
* \param sec_keys security keys
*
*/
bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index);
#endif /* SEC_PROT_KEYS_H_ */

View File

@ -49,6 +49,26 @@ void trickle_start(trickle_t *t, const trickle_params_t *params)
trickle_begin_interval(t);
}
uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration)
{
trickle_time_t time_I = params->Imin - 1;
uint32_t total_time = time_I;
while (trickle_timer_expiration) {
if (time_I <= TRICKLE_TIME_MAX / 2) {
time_I *= 2;
} else {
time_I = TRICKLE_TIME_MAX;
}
if (time_I > params->Imax) {
time_I = params->Imax;
}
total_time += time_I;
trickle_timer_expiration--;
}
return total_time;
}
/* We don't expose the raw reset as API; users should use "inconsistent_heard".
* This avoids repeated resets stopping transmission by restarting the interval.
*/

View File

@ -76,5 +76,10 @@ bool trickle_running(const trickle_t *t, const trickle_params_t *params);
/* Stop the timer (by setting e to infinite) */
void trickle_stop(trickle_t *t);
/*
* Call return max time after n count expiration period 0 return 1 Imin - 1 period
*
*/
uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration);
#endif /* TRICKLE_H_ */

View File

@ -87,7 +87,7 @@ bool blacklist_reject(const uint8_t *ll64_address)
if (blacklist_entry) {
// If address is blacklisted rejects
if (blacklist_entry->ttl > blacklist_data->blacklist_entry_lifetime) {
tr_debug("blacklist reject: %s", trace_array(ll64_address + 8, 8));
tr_info("blacklist reject: %s", trace_array(ll64_address + 8, 8));
return true;
// Neighbor heard; updates blacklist entry TTL to full lifetime
} else {
@ -131,7 +131,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success)
// On successful link establishment remove address from blacklist
if (success) {
if (blacklist_entry) {
tr_debug("Blacklist removed");
tr_info("Blacklist removed");
blacklist_entry_free(blacklist_entry);
}
// On failure add address to blacklist or update timeout
@ -144,7 +144,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success)
/* TTL is blacklist entry lifetime + from 1.0 to 1.5 * interval */
blacklist_entry->ttl = blacklist_data->blacklist_entry_lifetime + randLIB_randomise_base(blacklist_entry->interval, 0x8000, 0xC000);
} else {
tr_debug("Blacklist add");
tr_info("Blacklist add");
blacklist_entry_add(ll64_address + 8);
}
}
@ -209,7 +209,7 @@ void blacklist_ttl_update(uint16_t ticks)
if (blacklist_entry->ttl > ticks) {
blacklist_entry->ttl -= ticks;
} else {
tr_debug("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8));
tr_info("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8));
blacklist_entry_free(blacklist_entry);
}
}

View File

@ -62,11 +62,13 @@ typedef struct {
etx_storage_t *etx_storage_list;
etx_sample_storage_t *etx_cache_storage_list;
uint32_t max_etx_update;
uint32_t max_etx;
uint16_t hysteresis; // 12 bit fraction
uint16_t init_etx_sample_count;
uint8_t accum_threshold;
uint8_t etx_min_sampling_time;
uint8_t ext_storage_list_size;
uint8_t min_sample_count;
uint8_t min_attempts_count;
bool cache_sample_requested;
int8_t interface_id;
} ext_info_t;
@ -79,8 +81,10 @@ static ext_info_t etx_info = {
.etx_storage_list = NULL,
.etx_cache_storage_list = NULL,
.ext_storage_list_size = 0,
.min_sample_count = 0,
.min_attempts_count = 0,
.max_etx_update = 0,
.max_etx = 0xffff,
.init_etx_sample_count = 1,
.cache_sample_requested = false,
.etx_min_sampling_time = 0,
.interface_id = -1
@ -89,7 +93,9 @@ static ext_info_t etx_info = {
static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index)
{
if (etx_info.hysteresis && !entry->stored_diff_etx) {
entry->stored_diff_etx = entry->etx;
if (entry->etx_samples >= etx_info.init_etx_sample_count) {
entry->stored_diff_etx = entry->etx;
}
}
uint32_t etx = attempts << (12 - ETX_MOVING_AVERAGE_FRACTION);
@ -99,11 +105,14 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack
} else {
etx = 0xffff;
}
if ((etx_info.max_etx_update) && etx > etx_info.max_etx_update) {
etx = etx_info.max_etx_update;
}
if (etx_info.cache_sample_requested && entry->etx_samples == 1) {
//tr_debug("Attempts %u ACK %u 1/8 update %u", attempts, acks_rx, etx);
if (etx_info.cache_sample_requested && entry->etx_samples <= etx_info.init_etx_sample_count) {
// skip the initial value as RSSI generated ETX is not valid
etx = etx << 3;
} else {
@ -111,18 +120,20 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack
etx += entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION);
}
if (etx > 0xffff) {
etx = 0xffff;
if (etx > etx_info.max_etx) {
etx = etx_info.max_etx;
}
// If real ETX value has been received do not update based on LQI or dBm
entry->tmp_etx = false;
entry->etx = etx;
etx_cache_entry_init(attribute_index);
// Checks if ETX value change callback is needed
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
if (entry->etx_samples >= etx_info.init_etx_sample_count) {
etx_cache_entry_init(attribute_index);
// Checks if ETX value change callback is needed
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
}
}
static void etx_cache_entry_init(uint8_t attribute_index)
@ -135,7 +146,6 @@ static void etx_cache_entry_init(uint8_t attribute_index)
storage->attempts_count = 0;
storage->etx_timer = etx_info.etx_min_sampling_time;
storage->received_acks = 0;
storage->sample_count = 0;
}
static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *entry, uint16_t time_update)
@ -148,23 +158,23 @@ static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *en
}
}
if (entry->etx_samples > ETX_ACCELERATED_SAMPLE_COUNT) {
if (entry->etx_samples > etx_info.init_etx_sample_count) {
//Slower ETX update phase
if (storage->sample_count < etx_info.min_sample_count || storage->etx_timer) {
if (storage->sample_count < 0xff) {
return false;
if (storage->attempts_count >= etx_info.min_attempts_count) {
if (storage->etx_timer == 0 || storage->attempts_count == 0xffff || storage->received_acks == 0xff) {
//Got least min sample in requested time or max possible sample
return true;
}
}
} else {
//Accelerated ETX at for new neighbor
if (storage->sample_count < ETX_ACCELERATED_INTERVAL) {
return false;
}
return false;
}
//tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks);
if (time_update == 0) {
return true;
}
return true;
return false;
}
@ -176,7 +186,6 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui
if (ack_rx) {
storage->received_acks++;
}
storage->sample_count++;
return storage;
}
@ -202,6 +211,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
if (!entry) {
return;
}
if (entry->etx_samples < 7) {
entry->etx_samples++;
}
@ -211,11 +221,15 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
etx_sample_storage_t *storage = etx_cache_sample_update(attribute_index, attempts, success);
entry->accumulated_failures = 0;
if (!entry->etx || (entry->etx_samples > 1 && !etx_update_possible(storage, entry, 0))) {
if (!etx_update_possible(storage, entry, 0)) {
return;
}
etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index);
if (entry->etx_samples < 7 && !success) {
entry->etx_samples = 7; //Stop Probing to failure
}
return;
}
@ -377,6 +391,13 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index)
if (!entry) {
return 0;
}
if (etx_info.cache_sample_requested && entry->etx_samples < etx_info.init_etx_sample_count) {
if (!entry->etx_samples) {
return 0;
}
}
return etx_current_calc(entry->etx, entry->accumulated_failures) >> 4;
}
@ -433,7 +454,12 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
if (!entry->etx) {
etx = etx_dbm_lqi_calc(lqi, dbm);
entry->etx = etx;
entry->stored_diff_etx = etx;
entry->tmp_etx = true;
if (etx_info.callback_ptr) {
etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4,
attribute_index);
}
}
// If local ETX has been calculated without remote incoming IDR and
// remote incoming IDR is available update it by remote incoming IDR value
@ -448,11 +474,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
entry->etx = etx >> 12;
local_incoming_idr >>= 4;
}
// If local ETX has been calculated indicates new neighbor
if (etx) {
etx_neighbor_add(interface_id, attribute_index);
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
}
}
@ -585,14 +607,18 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size)
}
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count)
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count)
{
//No ini ETX allocation done yet
if (etx_info.ext_storage_list_size == 0) {
return false;
}
if (min_wait_time || etx_min_sample_count) {
if (min_wait_time || etx_min_attempts_count) {
if (init_etx_sample_count == 0) {
return false;
}
if (!etx_info.etx_cache_storage_list) {
//allocate
etx_info.etx_cache_storage_list = ns_dyn_mem_alloc(sizeof(etx_sample_storage_t) * etx_info.ext_storage_list_size);
@ -615,8 +641,9 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
etx_info.etx_cache_storage_list = NULL;
}
etx_info.min_sample_count = etx_min_sample_count;
etx_info.min_attempts_count = etx_min_attempts_count;
etx_info.etx_min_sampling_time = min_wait_time;
etx_info.init_etx_sample_count = init_etx_sample_count;
return true;
}
@ -624,12 +651,23 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
void etx_max_update_set(uint16_t etx_max_update)
{
if (etx_max_update) {
//Define MAX ETX UPDATE
etx_info.max_etx_update = (etx_max_update / 128) << (12 - ETX_MOVING_AVERAGE_FRACTION);
} else {
etx_info.max_etx_update = 0;
}
}
void etx_max_set(uint16_t etx_max)
{
if (etx_max) {
//Define MAX ETX possible value
etx_info.max_etx = (etx_max / 128) << 12;
} else {
etx_info.max_etx = 0xffff;
}
}
etx_storage_t *etx_storage_entry_get(int8_t interface_id, uint8_t attribute_index)
{
if (etx_info.interface_id != interface_id || !etx_info.etx_storage_list || attribute_index >= etx_info.ext_storage_list_size) {
@ -698,6 +736,8 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store
if (current_etx > *stored_diff_etx) {
if (current_etx - *stored_diff_etx >= etx_info.hysteresis) {
callback = true;
} else if (current_etx == etx_info.max_etx && *stored_diff_etx != etx_info.max_etx) {
callback = true;
}
} else if (current_etx < *stored_diff_etx) {
if (*stored_diff_etx - current_etx >= etx_info.hysteresis) {
@ -768,35 +808,6 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index)
}
}
/**
* \brief A function to add ETX neighbor
*
* Notifies ETX module that neighbor has been added. Calls ETX value change callback
* if that is set.
*
* \param mac64_addr_ptr long MAC address
*
*/
void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index)
{
//tr_debug("Add attribute %u", attribute_index);
uint16_t stored_diff_etx;
etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index);
if (entry && etx_info.callback_ptr) {
// Gets table entry
if (entry->etx) {
stored_diff_etx = entry->stored_diff_etx;
if (!stored_diff_etx) {
stored_diff_etx = entry->etx;
}
etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx >> 4, entry->etx >> 4,
attribute_index);
}
}
}
void etx_cache_timer(int8_t interface_id, uint16_t seconds_update)
{
if (!etx_info.cache_sample_requested) {

View File

@ -64,7 +64,6 @@ typedef struct etx_sample_storage_s {
uint16_t attempts_count; /*!< TX attempt count */
uint8_t etx_timer; /*!< Count down from configured value 0 means that ETX Update is possible done again*/
uint8_t received_acks; /*!< Received ACK's */
uint8_t sample_count; /*!< Finished TX count */
} etx_sample_storage_t;
/**
@ -237,17 +236,6 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int
*/
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index);
/**
* \brief A function to add ETX neighbor
*
* Notifies ETX module that neighbor has been added. Calls ETX value change callback
* if that is set.
*
* \param attribute_index Neighbour attribute index
*
*/
void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index);
/**
* \brief A function for update cached ETX calculation
*
@ -266,13 +254,14 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update);
* ETX update will happen when min wait time is reached and also reached min etx sample count.
*
* \param min_wait_time how many seconds must wait before do new ETX
* \param etx_min_sample_count define how many completed TX process must be done for new ETX. Min accepted value is 4.
* \param etx_min_attempts_count define how many TX attempts process must be done for new ETX. Min accepted value is 4.
* \param init_etx_sample_count How Many sample is need to init etx calculate
*
* \return true Enable is OK
* \return false Memory allocation fail
*
*/
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count);
bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count);
/**
@ -285,4 +274,14 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_
*/
void etx_max_update_set(uint16_t etx_max_update);
/**
* \brief A function for set Maxium ETX value
*
* ETX RFC define that that Max value is 0xffff but this API cuold make that Poor link start go down slowly.
*
* \param etx_max 0 No limit for higher value means. This pameter will change normal ETX which could be 0xffff.
*
*/
void etx_max_set(uint16_t etx_max);
#endif /* ETX_H_ */

View File

@ -1123,8 +1123,9 @@ static void fhss_data_tx_done_callback(const fhss_api_t *api, bool waiting_ack,
}
}
static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type)
static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel)
{
(void) channel;
fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
if (!fhss_structure) {
return false;
@ -1384,7 +1385,9 @@ static void fhss_beacon_tasklet_func(arm_event_s *event)
if (!fhss_structure) {
return;
}
#ifdef FEA_TRACE_SUPPORT
uint8_t parent_address[8];
#endif
fhss_clear_active_event(fhss_structure, event->event_type);
// skip the init event as there will be a timer event after
if (event->event_type == FHSS_TIMER_EVENT) {

View File

@ -113,7 +113,10 @@ int8_t fhss_disable(fhss_structure_t *fhss_structure)
}
fhss_structure->fhss_api->synch_state_set(fhss_structure->fhss_api, FHSS_UNSYNCHRONIZED, 0);
ns_dyn_mem_free(fhss_structure->bs);
ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table);
ns_dyn_mem_free(fhss_structure->ws->tr51_output_table);
ns_dyn_mem_free(fhss_structure->ws);
fhss_failed_list_free(fhss_structure);
ns_dyn_mem_free(fhss_structure);
fhss_struct = 0;
return 0;

View File

@ -40,6 +40,7 @@ struct fhss_structure {
int8_t fhss_event_timer;
uint8_t active_fhss_events;
uint16_t number_of_channels;
uint16_t optimal_packet_length;
fhss_states fhss_state;
uint32_t fhss_timeout;
uint32_t fhss_timer;

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include "ns_types.h"
#include "ns_trace.h"
#include "fhss_api.h"
#include "fhss_config.h"
#include "fhss.h"
#include "fhss_common.h"
#include "fhss_ws.h"
#include "fhss_statistics.h"
#include "fhss_channel.h"
#include "channel_list.h"
#include <string.h>
#define TRACE_GROUP "fhta"
int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length)
{
(void) fhss_api;
(void) packet_length;
#ifdef HAVE_WS
fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
if (!fhss_structure) {
return -1;
}
fhss_structure->optimal_packet_length = packet_length;
fhss_set_txrx_slot_length(fhss_structure);
tr_debug("Setting FHSS optimal packet length to: %u", fhss_structure->optimal_packet_length);
#endif
return 0;
}

View File

@ -83,7 +83,6 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots);
static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure);
static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay);
static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure);
static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure);
// This function supports rounding up
static int64_t divide_integer(int64_t dividend, int32_t divisor)
@ -147,10 +146,10 @@ fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configurati
fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb);
fhss_struct->ws->fhss_configuration = *fhss_configuration;
fhss_struct->number_of_channels = channel_count;
fhss_struct->optimal_packet_length = OPTIMAL_PACKET_LENGTH;
fhss_ws_set_hop_count(fhss_struct, 0xff);
fhss_struct->rx_channel = fhss_configuration->unicast_fixed_channel;
fhss_struct->ws->min_synch_interval = DEFAULT_MIN_SYNCH_INTERVAL;
fhss_set_txrx_slot_length(fhss_struct);
ns_list_init(&fhss_struct->fhss_failed_tx_list);
return fhss_struct;
}
@ -173,14 +172,51 @@ static int fhss_ws_manage_channel_table_allocation(fhss_structure_t *fhss_struct
return 0;
}
static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure)
{
uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / WS_MAX_TXRX_SLOT_LEN_MS) / 2;
// No broadcast schedule, no TX slots
if (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval == 0 || fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval == 0) {
return;
}
uint32_t txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS;
if (fhss_structure->callbacks.read_datarate) {
/* Calculate minimum TX slot length which can fit optimal packet length twice.
* Twice, because 0, 1, 4, 5... hop starts transmission at the beginning of TX slot and 2, 3, 6, 7... hop at the middle of TX slot
*
* hop 0
* tx'ing | | | | | |
* | BC | RX | TX | RX | TX | RX | TX | BC |
* hop 1
* tx'ing | | | | | |
* | BC | TX | RX | TX | RX | TX | RX | BC |
* hop 2
* tx'ing | | | | | |
* | BC | RX | TX | RX | TX | RX | TX | BC |
* hop 3
* tx'ing | | | | | |
* | BC | TX | RX | TX | RX | TX | RX | BC |
*/
uint32_t datarate = fhss_structure->callbacks.read_datarate(fhss_structure->fhss_api);
if (datarate) {
txrx_slot_length_ms_tmp = ((fhss_structure->optimal_packet_length * 2) * (8000000 / datarate)) / 1000;
// Do not allow using too high TX slot length.
if (txrx_slot_length_ms_tmp > WS_TXRX_SLOT_LEN_MS) {
tr_debug("TX slot length setting too high %"PRIu32"ms, using %"PRIu32"ms", txrx_slot_length_ms_tmp, (uint32_t)WS_TXRX_SLOT_LEN_MS);
txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS;
}
}
}
uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / txrx_slot_length_ms_tmp) / 2;
if (!number_of_tx_slots) {
return 0;
return;
}
fhss_structure->ws->txrx_slot_length_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / (number_of_tx_slots * 2);
return number_of_tx_slots;
tr_info("TX slot length: %"PRIu32"ms", fhss_structure->ws->txrx_slot_length_ms);
}
static uint32_t fhss_get_number_of_tx_slots(fhss_structure_t *fhss_structure)
{
return ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / fhss_structure->ws->txrx_slot_length_ms) / 2;
}
static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
@ -193,8 +229,8 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
fhss_structure->ws->bc_slot = 0;
}
} else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) {
next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
fhss_structure->ws->bc_slot++;
next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
} else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) {
if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
next_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, NULL, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
@ -305,8 +341,11 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots)
{
(void) slots;
uint16_t queue_size = 0;
fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id);
fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id);
if (!fhss_structure) {
return;
}
if (fhss_structure->ws->is_on_bc_channel == true) {
queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true);
@ -394,7 +433,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
if (fhss_state == FHSS_SYNCHRONIZED) {
uint32_t fhss_broadcast_interval = fhss_structure->ws->fhss_configuration.fhss_broadcast_interval;
uint8_t fhss_bc_dwell_interval = fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval;
fhss_set_txrx_slot_length(fhss_structure);
// Start broadcast schedule when BC intervals are known
if (fhss_broadcast_interval && fhss_bc_dwell_interval) {
fhss_broadcast_handler(fhss_structure->fhss_api, 0);
@ -407,6 +446,9 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
}
} else if (fhss_state == FHSS_UNSYNCHRONIZED) {
fhss_structure->ws->synchronization_time = 0;
eventOS_callback_timer_stop(fhss_structure->fhss_event_timer);
fhss_stop_timer(fhss_structure, fhss_unicast_handler);
fhss_stop_timer(fhss_structure, fhss_broadcast_handler);
}
fhss_structure->fhss_state = fhss_state;
@ -531,7 +573,7 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
if (fhss_structure->ws->is_on_bc_channel == true) {
return true;
}
uint32_t number_of_tx_slots = fhss_set_txrx_slot_length(fhss_structure);
uint32_t number_of_tx_slots = fhss_get_number_of_tx_slots(fhss_structure);
// Allow transmission when broadcast interval is very short comparing to MAX slot length
if (!number_of_tx_slots) {
return true;
@ -539,9 +581,22 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
uint32_t remaining_time_ms = get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval)) / 1000;
uint32_t tx_slot_begin_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (fhss_structure->ws->txrx_slot_length_ms * (fhss_structure->own_hop & 1));
/* Return false when our first TX slot has not yet started
* |------remaining_time_ms---|
* |
* v
* | BC | RX | TX | RX | TX | RX | TX | BC |
*/
if (tx_slot_begin_ms < remaining_time_ms) {
return false;
}
tx_slot_begin_ms = tx_slot_begin_ms - (((tx_slot_begin_ms - remaining_time_ms) / (2 * fhss_structure->ws->txrx_slot_length_ms)) * (2 * fhss_structure->ws->txrx_slot_length_ms));
uint32_t rx_slot_begin_ms = tx_slot_begin_ms - fhss_structure->ws->txrx_slot_length_ms;
// Check if we are currently on TX slot.
/* Check if we are currently on TX slot.
* | | |
* v v v
* | BC | RX | TX | RX | TX | RX | TX | BC |
*/
if ((remaining_time_ms <= tx_slot_begin_ms) && (remaining_time_ms > rx_slot_begin_ms)) {
return true;
}
@ -551,6 +606,10 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure)
static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length)
{
/*
* Check if there is enough time for transmitting before the next multicast slot.
*/
#ifdef FHSS_WS_PROTECT_MC_SLOTS
if (!fhss_structure->ws->fhss_configuration.fhss_broadcast_interval || !fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) {
return true;
}
@ -560,6 +619,13 @@ static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_
return false;
}
return true;
#else
(void) fhss_structure;
(void) tx_length;
(void) phy_header_length;
(void) phy_tail_length;
return true;
#endif
}
static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t handle, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length)
@ -663,7 +729,7 @@ static void fhss_ws_data_tx_done_callback(const fhss_api_t *api, bool waiting_ac
}
}
static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type)
static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel)
{
fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
if (!fhss_structure) {
@ -687,7 +753,7 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle,
fhss_failed_handle_remove(fhss_structure, handle);
return false;
}
fhss_failed_tx->bad_channel = fhss_structure->rx_channel;
fhss_failed_tx->bad_channel = channel;
} else {
// Create new failure handle and return true to retransmit
fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel);

View File

@ -21,8 +21,10 @@
* At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts
*/
#define WS_NUMBER_OF_CHANNEL_RETRIES 4
//TX/RX slot length in milliseconds
#define WS_MAX_TXRX_SLOT_LEN_MS 100
// TX slot length is optimised to this packet length
#define OPTIMAL_PACKET_LENGTH 500
// Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY.
#define WS_TXRX_SLOT_LEN_MS 100
// Default minimum broadcast synchronization interval in seconds
#define DEFAULT_MIN_SYNCH_INTERVAL 60
// Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization
@ -55,5 +57,6 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
int fhss_ws_remove_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8]);
int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_configuration_t *fhss_configuration);
int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_count);
void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure);
#endif /*FHSS_WS_H_*/

View File

@ -31,7 +31,7 @@ uint16_t crc16_ccitt(uint8_t *message, int nBytes);
/**
* @param data data which crc will be calculate
* @param data_length Lenght of data pointer
* @param data_length Length of data pointer
* @param polynomial Polynomial which will be used to calculate CRC, POLYNOMIAL_CRC15_CCIT, POLYNOMIAL_CRC15_ANSI
* @return Calculated 16bit CRC value
*/

View File

@ -842,7 +842,7 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr)
if (retval != 0) {
tr_warn("dhcp service socket_sendto fails: %i", retval);
} else {
tr_debug("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address));
tr_info("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address));
}
}
bool dhcp_service_timer_tick(uint16_t ticks)

View File

@ -49,17 +49,81 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void)
}
entry->serverDynamic_DUID = server_duid_ptr;
entry->serverDynamic_DUID_length = 16;
entry->clientIdSequence = 0;
entry->firstFreedId = 0;
entry->firstUnusedId = DHCP_ADDRESS_ID_START;
entry->enableAddressAutonous = true;
entry->clientIdDefaultSuffics = 0x0000000;
entry->maxSuppertedClients = 200;
entry->disableAddressListAllocation = false;
entry->maxSupportedClients = 200;
entry->validLifetime = 7200;
entry->removeCb = NULL;
entry->addCb = NULL;
ns_list_init(&entry->allocatedAddressList);
return entry;
}
static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_alloacted_address_entry_t *entry)
static uint16_t libdhcpv6_get_next_freed_id(dhcpv6_gua_server_entry_s *serverInfo)
{
uint16_t last_allocated_id = DHCP_ADDRESS_ID_START - 1;
ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (last_allocated_id + 1 == cur->allocatedID) {
//Last and current plus 1 so normal order
last_allocated_id = cur->allocatedID;
continue;
}
if ((cur->allocatedID - last_allocated_id) == 2) {
//one missing sequence between last and current
if (last_allocated_id + 1 == serverInfo->firstFreedId) {
//Skip Current freedID this will update after this call to new one
last_allocated_id = cur->allocatedID;
continue;
}
} else if (last_allocated_id + 1 == serverInfo->firstFreedId) {
//Skip first if it is last freedId
return last_allocated_id + 2;
}
return last_allocated_id + 1;
}
//No more freed ID so return 0
return 0;
}
static uint16_t libdhcpv6_address_id_allocate(dhcpv6_gua_server_entry_s *serverInfo)
{
uint16_t address_id;
if (serverInfo->firstFreedId) {
address_id = serverInfo->firstFreedId;
//Discover next free freed possible value
serverInfo->firstFreedId = libdhcpv6_get_next_freed_id(serverInfo);
} else {
//Allocated new ID
address_id = serverInfo->firstUnusedId++;
}
return address_id;
}
static void libdhcpv6_gen_suffics_from_eui48(uint8_t *ptr, uint8_t *eui48)
{
*ptr++ = *eui48++ ^ 2;
*ptr++ = *eui48++;
*ptr++ = *eui48++;
*ptr++ = 0xff;
*ptr++ = 0xfe;
*ptr++ = *eui48++;
*ptr++ = *eui48++;
*ptr = *eui48++;
}
static void libdhcpv6_gen_suffics_from_allocated_id(uint8_t *ptr, uint8_t *server_unique_48_bit_id, uint16_t allocated_id)
{
memcpy(ptr, server_unique_48_bit_id, 6);
common_write_16_bit(allocated_id, ptr + 6);
}
static uint16_t libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_t *entry)
{
//GENERATE ADDRESS
uint8_t *ptr = entry->nonTemporalAddress;
@ -70,25 +134,78 @@ static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dh
entry->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
memcpy(ptr, entry->linkId, 8);
*ptr ^= 2;
} else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
*ptr++ = entry->linkId[0] ^ 2;
*ptr++ = entry->linkId[1];
*ptr++ = entry->linkId[2];
*ptr++ = 0xff;
*ptr++ = 0xfe;
*ptr++ = entry->linkId[3];
*ptr++ = entry->linkId[4];
*ptr = entry->linkId[5];
} else {
ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr);
ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr);
return 0;
}
} else {
ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr);
ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr);
if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
libdhcpv6_gen_suffics_from_eui48(ptr, entry->linkId);
return 0;
}
}
serverInfo->clientIdSequence++;
uint16_t allocated_id = libdhcpv6_address_id_allocate(serverInfo);
libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, allocated_id);
return allocated_id;
}
static void libdhcpv6_address_free(dhcpv6_gua_server_entry_s *server_info, dhcpv6_allocated_address_entry_t *entry)
{
ns_list_remove(&server_info->allocatedAddressList, entry);
if (!server_info->enableAddressAutonous) {
if (entry->allocatedID + 1 == server_info->firstUnusedId) {
server_info->firstUnusedId--;
} else if (server_info->firstFreedId == 0 || server_info->firstFreedId > entry->allocatedID) {
server_info->firstFreedId = entry->allocatedID;
}
}
ns_dyn_mem_free(entry);
}
void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo)
{
memcpy(ptr, serverInfo->guaPrefix, 8);
ptr += 8;
if (serverInfo->enableAddressAutonous) {
//Generate address from link layer address
if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
memcpy(ptr, address->linkId, 8);
*ptr ^= 2;
return;
} else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
libdhcpv6_gen_suffics_from_eui48(ptr, address->linkId);
return;
}
}
//Generate from 16-bit allocate and default suffic's
libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, address->allocatedID);
}
static bool libdhcpv6_address_suffics_compare(const uint8_t *suffics, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo)
{
uint8_t allocated_suffics[8];
if (serverInfo->enableAddressAutonous) {
//Generate address from link layer address
if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
memcpy(allocated_suffics, address->linkId, 8);
allocated_suffics[0] ^= 2;
goto compare_suffics;
} else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) {
libdhcpv6_gen_suffics_from_eui48(allocated_suffics, address->linkId);
goto compare_suffics;
}
}
//Generate from 16-bit allocate and default suffic's
libdhcpv6_gen_suffics_from_allocated_id(allocated_suffics, serverInfo->clientIdDefaultSuffics, address->allocatedID);
compare_suffics:
if (memcmp(allocated_suffics, suffics, 8)) {
return false;
}
return true;
}
@ -97,15 +214,16 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds)
//Check All allocated server inside this loop
ns_list_foreach(dhcpv6_gua_server_entry_s, cur, &dhcpv6_gua_server_list) {
//Check All allocated address in this module
ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, address, &cur->allocatedAddressList) {
ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, address, &cur->allocatedAddressList) {
//Update
if (address->preferredLifetime) {
if (address->preferredLifetime <= timeUpdateInSeconds) {
//Stop use this address for leasequery and delete Route or address map
address->preferredLifetime = 0;
if (cur->removeCb) {
cur->removeCb(cur->interfaceId, address->nonTemporalAddress, cur->guaPrefix);
uint8_t allocated_address[16];
libdhcpv6_allocated_address_write(allocated_address, address, cur);
cur->removeCb(cur->interfaceId, allocated_address, cur->guaPrefix);
}
} else {
address->preferredLifetime -= timeUpdateInSeconds;
@ -113,8 +231,7 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds)
}
if (address->lifetime <= timeUpdateInSeconds) {
ns_list_remove(&cur->allocatedAddressList, address);
ns_dyn_mem_free(address);
libdhcpv6_address_free(cur, address);
} else {
address->lifetime -= timeUpdateInSeconds;
}
@ -187,6 +304,15 @@ dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t
duid_length = libdhcpv6_duid_linktype_size(serverDUIDType) + 2;
ptr = common_write_16_bit(serverDUIDType, ptr);
memcpy(ptr, serverDUID, libdhcpv6_duid_linktype_size(serverDUIDType));
//SET Defaultsuffics
if (libdhcpv6_duid_linktype_size(serverDUIDType) == 8) {
memcpy(entry->clientIdDefaultSuffics, serverDUID, 3);
memcpy(entry->clientIdDefaultSuffics + 3, serverDUID + 5, 3);
} else {
memcpy(entry->clientIdDefaultSuffics, serverDUID, 6);
}
entry->clientIdDefaultSuffics[0] ^= 0x02;
//SET DUID
if (libdhcpv6_server_duid_set(entry, duid_ll, DHCPV6_DUID_LINK_LAYER_TYPE, duid_length) != 0) {
@ -208,7 +334,7 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix);
if (serverInfo) {
if ((serverInfo->interfaceId == interfaceId) && (memcmp(serverInfo->guaPrefix, prefix, 8) == 0)) {
ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
ns_list_remove(&serverInfo->allocatedAddressList, cur);
ns_dyn_mem_free(cur);
}
@ -219,26 +345,52 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t
}
}
static dhcpv6_alloacted_address_entry_t *libdhcpv6_address_entry_allocate(uint32_t validLifetime)
static void libdhcpv6_address_entry_lifetime_set(dhcpv6_allocated_address_entry_t *entry, uint32_t validLifetime)
{
dhcpv6_alloacted_address_entry_t *entry = ns_dyn_mem_alloc(sizeof(dhcpv6_alloacted_address_entry_t));
if (entry) {
if (validLifetime != 0xffffffff) {
entry->lifetime = validLifetime;
entry->preferredLifetime = (validLifetime >> 1);
} else {
entry->lifetime = 0xffffffff;
entry->preferredLifetime = 0xffffffff;
}
if (validLifetime != 0xffffffff) {
entry->lifetime = validLifetime;
entry->preferredLifetime = (validLifetime >> 1);
} else {
entry->lifetime = 0xffffffff;
entry->preferredLifetime = 0xffffffff;
}
return entry;
}
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
static void libdhcpv6_copy_allocated_entry_to_temp(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, dhcpv6_gua_server_entry_s *serverInfo)
{
ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (memcmp(cur->nonTemporalAddress, address, 16) == 0) {
return cur;
libdhcpv6_allocated_address_write(address->nonTemporalAddress, cur, serverInfo);
memcpy(address->linkId, cur->linkId, 8);
address->T0 = cur->T0;
address->T1 = cur->T1;
address->iaID = cur->iaID;
address->lifetime = cur->lifetime;
address->preferredLifetime = cur->preferredLifetime;
address->linkType = cur->linkType;
}
static void libdhcpv6_copy_temp_to_allocated_entry(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, uint16_t allocated_id)
{
memcpy(cur->linkId, address->linkId, 8);
cur->allocatedID = allocated_id;
cur->T0 = address->T0;
cur->T1 = address->T1;
cur->iaID = address->iaID;
cur->lifetime = address->lifetime;
cur->preferredLifetime = address->preferredLifetime;
cur->linkType = address->linkType;
}
dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
{
if (memcmp(serverInfo->guaPrefix, address, 8)) {
return NULL;
}
ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) {
libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo);
return &serverInfo->tempAddressEntry;
}
}
return NULL;
@ -246,49 +398,95 @@ dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcp
void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address)
{
ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (memcmp(cur->nonTemporalAddress, address, 16) == 0) {
ns_list_remove(&serverInfo->allocatedAddressList, cur);
ns_dyn_mem_free(cur);
if (memcmp(serverInfo->guaPrefix, address, 8)) {
return;
}
ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) {
libdhcpv6_address_free(serverInfo, cur);
return;
}
}
}
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew)
static void libdhcpv6_address_id_add_to_list(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *allocated)
{
dhcpv6_alloacted_address_entry_t *newEntry = NULL;
if (serverInfo->firstUnusedId != allocated->allocatedID + 1) {
ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (cur->allocatedID > allocated->allocatedID) {
//Add before new allocated
if (cur->link.prev) {
ns_list_add_before(&serverInfo->allocatedAddressList, cur, allocated);
} else {
//New first
ns_list_add_to_start(&serverInfo->allocatedAddressList, allocated);
}
return;
}
}
}
ns_list_add_to_end(&serverInfo->allocatedAddressList, allocated);
}
dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew)
{
dhcpv6_allocated_address_t *newEntry = NULL;
dhcpv6_allocated_address_entry_t *allocatedEntry = NULL;
uint16_t duiLength = 6;
if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
duiLength = 8;
}
ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (serverInfo->enableAddressAutonous && serverInfo->disableAddressListAllocation) {
//Accept allways when autonous
newEntry = &serverInfo->tempAddressEntry;
allocateNew = false;
}
ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) {
if (cur->linkType == linkType) {
if (memcmp(cur->linkId, linkId, duiLength) == 0) {
cur->iaID = iaID;
if (serverInfo->validLifetime != 0xffffffff) {
cur->lifetime = serverInfo->validLifetime ;
cur->preferredLifetime = (serverInfo->validLifetime >> 1);
} else {
cur->lifetime = 0xffffffff;
cur->preferredLifetime = 0xffffffff;
}
return cur;
libdhcpv6_address_entry_lifetime_set(cur, serverInfo->validLifetime);
libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo);
return &serverInfo->tempAddressEntry;
}
}
}
if (allocateNew) {
if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSuppertedClients) {
newEntry = libdhcpv6_address_entry_allocate(serverInfo->validLifetime);
if (newEntry) {
memcpy(newEntry->linkId, linkId, duiLength);
newEntry->linkType = linkType;
newEntry->iaID = iaID;
newEntry->T0 = T0;
newEntry->T1 = T1;
libdhcpv6_address_generate(serverInfo, newEntry);
ns_list_add_to_end(&serverInfo->allocatedAddressList, newEntry);
if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSupportedClients) {
allocatedEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_allocated_address_entry_t));
if (allocatedEntry) {
newEntry = &serverInfo->tempAddressEntry;
}
}
}
if (newEntry) {
if (serverInfo->validLifetime != 0xffffffff) {
newEntry->lifetime = serverInfo->validLifetime;
newEntry->preferredLifetime = (serverInfo->validLifetime >> 1);
} else {
newEntry->lifetime = 0xffffffff;
newEntry->preferredLifetime = 0xffffffff;
}
memcpy(newEntry->linkId, linkId, duiLength);
newEntry->linkType = linkType;
newEntry->iaID = iaID;
newEntry->T0 = T0;
newEntry->T1 = T1;
uint16_t allocated_id = libdhcpv6_address_generate(serverInfo, newEntry);
if (!serverInfo->disableAddressListAllocation) {
libdhcpv6_copy_temp_to_allocated_entry(allocatedEntry, newEntry, allocated_id);
if (serverInfo->enableAddressAutonous) {
ns_list_add_to_end(&serverInfo->allocatedAddressList, allocatedEntry);
} else {
//Add to list to proper order
libdhcpv6_address_id_add_to_list(serverInfo, allocatedEntry);
}
}
}

View File

@ -28,9 +28,25 @@
#include "libDHCPv6/libDHCPv6.h"
#define MAX_SUPPORTED_ADDRESS_LIST_SIZE 0x0000fffd
#define DHCP_ADDRESS_ID_START 2
typedef void (dhcp_address_prefer_remove_cb)(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info);
typedef struct dhcpv6_alloacted_address_entry_s {
typedef struct dhcpv6_allocated_address_entry_s {
uint8_t linkId[8]; /*!< Services UL64 */
uint32_t iaID;
uint32_t T0;
uint32_t T1;
uint32_t preferredLifetime;
uint32_t lifetime;
uint16_t linkType;
uint16_t allocatedID;
ns_list_link_t link; /*!< List link entry */
} dhcpv6_allocated_address_entry_t;
typedef struct dhcpv6_allocated_address_s {
uint8_t nonTemporalAddress[16];
uint8_t linkId[8]; /*!< Services UL64 */
uint16_t linkType;
@ -39,18 +55,9 @@ typedef struct dhcpv6_alloacted_address_entry_s {
uint32_t T1;
uint32_t preferredLifetime;
uint32_t lifetime;
ns_list_link_t link; /*!< List link entry */
} dhcpv6_alloacted_address_entry_t;
} dhcpv6_allocated_address_t;
typedef NS_LIST_HEAD(dhcpv6_alloacted_address_entry_t, link) dhcpv6_alloacted_address_list_t;
typedef struct thread_dhcpv6_server_data_s {
uint8_t prefix[8]; /*!< Services Prefix */
uint16_t maxSuppertedClients;
uint32_t clientIdSequence; /*!< Define */
dhcpv6_alloacted_address_list_t allocatedAddressList;
ns_list_link_t link; /*!< List link entry */
} dhcpv6_server_data_entry_t;
typedef NS_LIST_HEAD(dhcpv6_allocated_address_entry_t, link) dhcpv6_allocated_address_list_t;
typedef struct dhcp_address_cache_update {
uint8_t *allocatedAddress;
@ -62,19 +69,22 @@ typedef bool (dhcp_address_add_notify_cb)(int8_t interfaceId, dhcp_address_cache
typedef struct dhcpv6_gua_server_entry_s {
int8_t interfaceId;
bool enableAddressAutonous;
bool enableAddressAutonous: 1;
bool disableAddressListAllocation: 1;
uint16_t socketInstance_id;
uint8_t guaPrefix[8];
uint8_t serverDynamic_DUID_length;
uint32_t maxSuppertedClients;
uint32_t clientIdDefaultSuffics;
uint32_t clientIdSequence; /*!< Define */
uint32_t maxSupportedClients;
uint8_t clientIdDefaultSuffics[6];
uint16_t firstFreedId;
uint16_t firstUnusedId; /*!< This is first unused Id */
uint32_t validLifetime;
dhcp_duid_options_params_t serverDUID;
uint8_t *serverDynamic_DUID;
dhcp_address_prefer_remove_cb *removeCb;
dhcp_address_add_notify_cb *addCb;
dhcpv6_alloacted_address_list_t allocatedAddressList;
dhcpv6_allocated_address_list_t allocatedAddressList;
dhcpv6_allocated_address_t tempAddressEntry;
ns_list_link_t link; /*!< List link entry */
} dhcpv6_gua_server_entry_s;
@ -84,10 +94,11 @@ int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *d
void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t interfaceId);
void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds);
void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);
dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_interfaceid(int8_t interfaceId, const uint8_t *prefixPtr);
dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstance(uint16_t socketInstance, uint8_t *prefixPtr);
dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew);
dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew);
void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo);
#else
#define libdhcpv6_gua_server_list_empty() true
#define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL

View File

@ -65,6 +65,7 @@ int8_t net_6lowpan_nd_parameter_set(const nd_parameters_s *p)
return 0;
#else
(void) p;
return -2;
#endif
}
@ -89,6 +90,8 @@ int8_t net_6lowpan_nd_timer_base_tick_set(uint8_t base_tick_x_100ms)
}
nd_base_tick = base_tick_x_100ms;
#else
(void) base_tick_x_100ms;
#endif
return 0;
}
@ -103,5 +106,7 @@ void net_6lowpan_nd_parameter_read(nd_parameters_s *p)
{
#ifdef HAVE_6LOWPAN_ND
*p = nd_params;
#else
(void) p;
#endif
}

View File

@ -146,12 +146,14 @@ int8_t net_load_balance_network_switch_cb_set(int8_t interface_id, net_load_bala
return load_balance_network_switch_cb_set(interface_ptr->lb_api, network_switch_notify);
#else
(void) interface_id;
(void) network_switch_notify;
return -1;
#endif
}
int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval)
int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval)
{
#ifdef HAVE_6LOWPAN_ND
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
@ -188,6 +190,8 @@ int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon
return 0;
#else
(void) interface_id;
(void) enable_periodic_beacon_interval;
return -1;
#endif
}
@ -205,6 +209,7 @@ int8_t net_load_balance_delete(int8_t interface_id)
return load_balance_delete(lb_api);
#else
(void) interface_id;
return -1;
#endif
}
@ -223,6 +228,9 @@ int8_t net_load_balance_threshold_set(int8_t interface_id, uint8_t threshold_min
return load_balance_network_threshold_set(interface_ptr->lb_api, threshold_min, threshold_max);
#else
(void) interface_id;
(void) threshold_min;
(void) threshold_max;
return -1;
#endif
}
@ -259,8 +267,10 @@ void net_load_balance_internal_state_activate(protocol_interface_info_entry_t *i
set_req.value_pointer = &state;
set_req.value_size = sizeof(bool);
interface_ptr->mac_api->mlme_req(interface_ptr->mac_api, MLME_SET, &set_req);
#else
(void) interface_ptr;
(void) state;
#endif
}
#ifdef HAVE_RPL
@ -361,6 +371,8 @@ int8_t net_load_balance_set_max_probability(int8_t interface_id, uint8_t max_p)
return load_balance_set_max_probability(interface_ptr->lb_api, max_p);
#else
(void) interface_id;
(void) max_p;
return -1;
#endif
}

View File

@ -400,6 +400,10 @@ int8_t arm_nwk_6lowpan_gp_address_mode(int8_t interface_id, net_6lowpan_gp_addre
return 0;
#else
(void) interface_id;
(void) mode;
(void) short_address_base;
(void) define_new_short_address_at_DAD;
return -2;
#endif
}
@ -895,7 +899,7 @@ int8_t arm_pana_client_key_pull(int8_t interface_id)
return pana_client_key_pull(interface_id);
}
int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info)
int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || thread_info(cur) || !cur->mac_parameters || (cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) {
@ -903,6 +907,9 @@ int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_la
}
#ifndef HAVE_6LOWPAN_ND
(void) mode;
(void) sec_level;
(void) psk_key_info;
return -1;
#else
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {

View File

@ -108,6 +108,8 @@ int8_t socket_close(int8_t sid)
int8_t socket_listen(int8_t socket, uint8_t backlog)
{
#ifdef NO_TCP
(void) socket;
(void) backlog;
return -1;
#else
socket_t *socket_ptr = socket_pointer_get(socket);
@ -141,6 +143,9 @@ int8_t socket_listen(int8_t socket, uint8_t backlog)
int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_fptr)(void *))
{
#ifdef NO_TCP
(void) listen_socket_id;
(void) addr;
(void) passed_fptr;
return -1;
#else
socket_t *socket_ptr = socket_pointer_get(listen_socket_id);
@ -189,6 +194,8 @@ int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_
int8_t socket_shutdown(int8_t socket, uint8_t how)
{
#ifdef NO_TCP
(void) socket;
(void) how;
return -1;
#else
socket_t *socket_ptr = socket_pointer_get(socket);
@ -608,8 +615,8 @@ int8_t socket_connect(int8_t socket, ns_address_t *address, uint8_t randomly_tak
socket_ptr->flags |= SOCKET_FLAG_CONNECTING;
}
#endif
exit:
#endif
if (status != 0) {
memcpy(inet_pcb->remote_address, ns_in6addr_any, 16);
inet_pcb->remote_port = 0;

View File

@ -136,6 +136,7 @@ SRCS += \
source/Service_Libs/fhss/fhss_common.c \
source/Service_Libs/fhss/channel_functions.c \
source/Service_Libs/fhss/channel_list.c \
source/Service_Libs/fhss/fhss_test_api.c \
source/Service_Libs/fnv_hash/fnv_hash.c \
source/Service_Libs/hmac/hmac_sha1.c \
source/Service_Libs/ieee_802_11/ieee_802_11.c \