diff --git a/nanostack/dhcp_service_api.h b/nanostack/dhcp_service_api.h index d8b9b5b1168..3efae996b45 100644 --- a/nanostack/dhcp_service_api.h +++ b/nanostack/dhcp_service_api.h @@ -69,7 +69,8 @@ typedef enum dhcp_instance_type { DHCP_INSTANCE_CLIENT, - DHCP_INSTANCE_SERVER + DHCP_INSTANCE_SERVER, + DHCP_INTANCE_RELAY_AGENT } dhcp_instance_type_e; /** @@ -124,6 +125,16 @@ typedef int (dhcp_service_receive_resp_cb)(uint16_t instance_id, void *ptr, uint uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_type, dhcp_service_receive_req_cb *receive_req_cb); +/** +* \brief Enable DHCPv6 Relay Agent to server. +* +* +* \param instance The instance ID of the registered server. +* \param server_address global server IPv6 address +*/ +void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address); + + /** * \brief Deletes a server instance. * diff --git a/nanostack/fhss_api.h b/nanostack/fhss_api.h index 16820aeaaee..0f0774cd024 100644 --- a/nanostack/fhss_api.h +++ b/nanostack/fhss_api.h @@ -132,8 +132,9 @@ typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_ * @param api FHSS instance. * @param fhss_state FHSS state (FHSS states are defined by FHSS api). * @param pan_id PAN id of the network FHSS synchronizes with. + * @return -1 when failed, otherwise current MAC channel. */ -typedef void fhss_synch_state_set(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id); +typedef int16_t fhss_synch_state_set(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id); /** * @brief Read timestamp. @@ -215,6 +216,13 @@ typedef int mac_read_mac_address(const fhss_api_t *fhss_api, uint8_t *mac_addres */ typedef uint32_t mac_read_datarate(const fhss_api_t *fhss_api); +/** + * @brief Read 32-bit timestamp. + * @param fhss_api FHSS instance. + * @return Timestamp. + */ +typedef uint32_t mac_read_timestamp(const fhss_api_t *fhss_api); + /** * @brief Change channel. * @param fhss_api FHSS instance. @@ -287,6 +295,7 @@ struct fhss_callback { mac_read_tx_queue_size *read_tx_queue_size; /**< Read MAC TX queue size. */ mac_read_mac_address *read_mac_address; /**< Read MAC address. */ mac_read_datarate *read_datarate; /**< Read PHY datarate. */ + mac_read_timestamp *read_timestamp; /**< Read timestamp. */ mac_change_channel *change_channel; /**< Change channel. */ mac_send_fhss_frame *send_fhss_frame; /**< Send FHSS frame. */ mac_synch_lost_notification *synch_lost_notification; /**< Send notification when FHSS synchronization is lost. */ diff --git a/nanostack/fhss_config.h b/nanostack/fhss_config.h index 5695367659f..6a1cf3507ab 100644 --- a/nanostack/fhss_config.h +++ b/nanostack/fhss_config.h @@ -96,8 +96,11 @@ typedef int32_t fhss_vendor_defined_cf(const fhss_api_t *api, uint16_t slot, uin */ typedef struct fhss_ws_configuration { - /** WS channel function. */ - fhss_ws_channel_functions ws_channel_function; + /** WS unicast channel function. */ + fhss_ws_channel_functions ws_uc_channel_function; + + /** WS broadcast channel function. */ + fhss_ws_channel_functions ws_bc_channel_function; /** Broadcast schedule identifier. */ uint16_t bsi; @@ -111,6 +114,12 @@ typedef struct fhss_ws_configuration /** Broadcast dwell interval. Range: 15-250 milliseconds. */ uint8_t fhss_bc_dwell_interval; + /** Unicast fixed channel */ + uint8_t unicast_fixed_channel; + + /** Broadcast fixed channel */ + uint8_t broadcast_fixed_channel; + /** Channel mask. */ uint32_t channel_mask[8]; diff --git a/nanostack/fhss_ws_extension.h b/nanostack/fhss_ws_extension.h index c440451204d..44d86d1f6d9 100644 --- a/nanostack/fhss_ws_extension.h +++ b/nanostack/fhss_ws_extension.h @@ -37,6 +37,7 @@ typedef struct unicast_timing_info { unsigned unicast_channel_function:3; /**< Unicast schedule channel function */ uint8_t unicast_dwell_interval; /**< Unicast dwell interval */ uint16_t unicast_number_of_channels; /**< Unicast number of channels */ + uint16_t fixed_channel; /**< Unicast fixed channel*/ uint_fast24_t ufsi; /**< Unicast fractional sequence interval */ uint32_t utt_rx_timestamp; /**< UTT-IE reception timestamp */ } unicast_timing_info_t; @@ -47,6 +48,7 @@ typedef struct unicast_timing_info { typedef struct broadcast_timing_info { unsigned broadcast_channel_function:3; /**< Broadcast schedule channel function */ uint8_t broadcast_dwell_interval; /**< Broadcast dwell interval */ + uint16_t fixed_channel; /**< Broadcast fixed channel*/ uint16_t broadcast_slot; /**< Broadcast slot number */ uint16_t broadcast_schedule_id; /**< Broadcast schedule identifier */ uint_fast24_t broadcast_interval_offset; /**< Broadcast interval offset */ @@ -78,9 +80,10 @@ typedef fhss_ws_neighbor_timing_info_t *fhss_get_neighbor_info(const fhss_api_t * @param fhss_api FHSS instance. * @param eui64 EUI-64 address of parent. * @param bc_timing_info Pointer to parent broadcast timing/hopping schedule info. + * @param force_synch If false, synchronization is done only if minimum (internal) synchronization interval is exceed. * @return 0 on success, -1 on fail. */ -extern int ns_fhss_ws_set_parent(const fhss_api_t *fhss_api, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info); +extern int ns_fhss_ws_set_parent(const fhss_api_t *fhss_api, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info, const bool force_synch); /** * @brief Remove parent which was set by ns_fhss_ws_set_parent function. diff --git a/nanostack/mac_api.h b/nanostack/mac_api.h index b889ee25a73..33c954bf980 100644 --- a/nanostack/mac_api.h +++ b/nanostack/mac_api.h @@ -137,8 +137,9 @@ typedef void mcps_data_request_ext(const mac_api_t* api, const mcps_data_req_t * * @brief mcps_purge_request MCPS_PURGE request call * @param api API to handle the request * @param data MCPS-PURGE.request specific values + * @return 0 in case of success, non-zero otherwise */ -typedef void mcps_purge_request(const mac_api_t* api, const mcps_purge_t *data); +typedef uint8_t mcps_purge_request(const mac_api_t* api, const mcps_purge_t *data); //Upper layer specific callback functions (will also be set by Upper layer after mac_api_t has been created and given to it) diff --git a/nanostack/net_fhss.h b/nanostack/net_fhss.h index 2223a5af3bf..b201420e14f 100644 --- a/nanostack/net_fhss.h +++ b/nanostack/net_fhss.h @@ -39,10 +39,9 @@ extern "C" { extern fhss_api_t *ns_fhss_create(const fhss_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer, fhss_statistics_t *fhss_statistics); /** - * @brief TODO: description. + * @brief Creates FHSS WS API instance which will be registered to software MAC. * @param fhss_configuration Basic FHSS configuration. * @param fhss_timer FHSS platform timer interface and configuration. - * @param fhss_statistics FHSS statistics storage. * @return New FHSS instance if successful, NULL otherwise. */ extern fhss_api_t *ns_fhss_ws_create(const fhss_ws_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer); diff --git a/nanostack/thread_bbr_api.h b/nanostack/thread_bbr_api.h index 91e697baad5..55a8e9f97da 100644 --- a/nanostack/thread_bbr_api.h +++ b/nanostack/thread_bbr_api.h @@ -75,6 +75,7 @@ int thread_bbr_start(int8_t interface_id, int8_t backbone_interface_id); * */ int thread_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t timeout_b, uint32_t delay); + /** * Set prefix to be used as combining multiple thread networks on backbone. * @@ -89,6 +90,20 @@ int thread_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t tim */ int thread_bbr_prefix_set(int8_t interface_id, uint8_t *prefix); +/** + * Set sequence number to be used by bbr + * + * update sequence number value + * + * \param interface_id interface ID of the Thread network. + * \param sequence_number value that needs to be set on bbr + * + * \return 0 on success + * \return <0 in case of errors + * + */ +int thread_bbr_sequence_number_set(int8_t interface_id, uint8_t sequence_number); + /** * Set the Thread validation interface destination address. * diff --git a/nanostack/thread_commissioning_api.h b/nanostack/thread_commissioning_api.h index 85923328c8e..6495786534b 100644 --- a/nanostack/thread_commissioning_api.h +++ b/nanostack/thread_commissioning_api.h @@ -189,8 +189,10 @@ void *thread_commission_device_get_next(void *ptr, int8_t interface_id, bool *sh typedef struct thread_commissioning_link_configuration { uint8_t name[16]; /**< Name of the Thread network. utf8 string nul terminated if shorter than 16. */ + uint8_t destination_address[16]; /**index); // If primary parent has changed clears priority from previous parent if (entry->link_role != PRIORITY_PARENT_NEIGHBOUR) { + new_primary = true; protocol_6lowpan_neighbor_priority_clear_all(interface_id, PRIORITY_1ST); } entry->link_role = PRIORITY_PARENT_NEIGHBOUR; @@ -501,6 +504,10 @@ uint16_t protocol_6lowpan_neighbor_priority_set(int8_t interface_id, addrtype_t if (etx_entry) { protocol_stats_update(STATS_ETX_1ST_PARENT, etx_entry->etx >> 4); } + + if (new_primary) { + ws_primary_parent_update(cur, entry); + } return 1; } else { return 0; @@ -519,9 +526,11 @@ uint16_t protocol_6lowpan_neighbor_second_priority_set(int8_t interface_id, addr mac_neighbor_table_entry_t * entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), addr_ptr + PAN_ID_LEN, addr_type); if (entry) { + bool new_secondary = false; etx_storage_t *etx_entry = etx_storage_entry_get(interface_id, entry->index); // If secondary parent has changed clears priority from previous parent if (entry->link_role != SECONDARY_PARENT_NEIGHBOUR) { + new_secondary = true; protocol_6lowpan_neighbor_priority_clear_all(interface_id, PRIORITY_2ND); } entry->link_role = SECONDARY_PARENT_NEIGHBOUR; @@ -529,6 +538,9 @@ uint16_t protocol_6lowpan_neighbor_second_priority_set(int8_t interface_id, addr if (etx_entry) { protocol_stats_update(STATS_ETX_2ND_PARENT, etx_entry->etx >> 4); } + if (new_secondary) { + ws_secondary_parent_update(cur); + } return 1; } else { return 0; @@ -557,7 +569,6 @@ void protocol_6lowpan_neighbor_priority_clear_all(int8_t interface_id, neighbor_ } } -#endif #endif #endif diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index e8f4fe95771..4e8cec5ba1b 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -1786,7 +1786,7 @@ int8_t arm_6lowpan_bootstarp_bootstrap_set(int8_t interface_id, net_6lowpan_mode */ if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) { //rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); - //rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, cur); + //rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, cur); } #endif cur->configure_flags |= INTERFACE_BOOTSTRAP_DEFINED; @@ -2073,6 +2073,8 @@ static void protocol_6lowpan_bootstrap_rpl_callback(rpl_event_t event, void *han tr_error("RPL Local repair fail-->interface to idle"); nwk_bootsrap_state_update(ARM_NWK_NWK_CONNECTION_DOWN, cur); break; + default: + break; } } @@ -2179,7 +2181,7 @@ void nwk_6lowpan_nd_address_registartion_ready(protocol_interface_info_entry_t * // arm_nwk_6lowpan_rpl_dodag_poison from a previous connection may have left force_leaf set rpl_control_force_leaf(protocol_6lowpan_rpl_domain, false); rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, true); - rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, cur); + rpl_control_set_callback(protocol_6lowpan_rpl_domain, protocol_6lowpan_bootstrap_rpl_callback, NULL, cur); } // Send unicast DIS to coordinator nwk_bootstrap_icmp_rpl_dis_coord_msg_tx(cur); diff --git a/source/6LoWPAN/MAC/mpx_api.h b/source/6LoWPAN/MAC/mpx_api.h index a61e3e00537..739b07b3307 100644 --- a/source/6LoWPAN/MAC/mpx_api.h +++ b/source/6LoWPAN/MAC/mpx_api.h @@ -39,9 +39,10 @@ typedef void mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s * @param api API to handle the request * @param purge MCPS-purge request * @param user_id MPX user ID + * @return 0 if purge requst was OK, non-zero otherwise * */ -typedef void mpx_data_purge_request(const mpx_api_t *api, struct mcps_purge_s *purge, uint16_t user_id); +typedef uint8_t mpx_data_purge_request(const mpx_api_t *api, struct mcps_purge_s *purge, uint16_t user_id); /** * @brief mpx_data_confirm MPX-DATA confirm is called as a response to MPX-DATA request diff --git a/source/6LoWPAN/Thread/thread_bbr_api.c b/source/6LoWPAN/Thread/thread_bbr_api.c index 6c0b09a2c0f..9064b890d29 100644 --- a/source/6LoWPAN/Thread/thread_bbr_api.c +++ b/source/6LoWPAN/Thread/thread_bbr_api.c @@ -40,12 +40,16 @@ #include "common_functions.h" #include "thread_border_router_api.h" #include "thread_bbr_api.h" +#include "net_ipv6_api.h" +#include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ipv6_constants.h" #include "DHCPv6_Server/DHCPv6_server_service.h" +#include "6LoWPAN/Thread/thread_dhcpv6_server.h" #include "thread_management_if.h" #include "6LoWPAN/Thread/thread_config.h" #include "6LoWPAN/Thread/thread_constants.h" #include "6LoWPAN/Thread/thread_common.h" +#include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_extension.h" #include "6LoWPAN/Thread/thread_extension_bbr.h" @@ -96,7 +100,6 @@ typedef struct { #define RFC6106_DNS_SEARCH_LIST_OPTION 31 static NS_LIST_DEFINE(bbr_instance_list, thread_bbr_t, link); - static thread_bbr_t *thread_bbr_find_by_interface(int8_t interface_id) { thread_bbr_t *this = NULL; @@ -579,7 +582,7 @@ static void thread_bbr_network_data_send(thread_bbr_t *this, uint8_t prefix[8], // delete old prefix memset(this->bbr_prefix,0,8); // create new prefix - if (DHCPv6_server_service_init(this->interface_id, prefix, eui64, DHCPV6_DUID_HARDWARE_EUI64_TYPE) != 0) { + if (thread_dhcp6_server_init(this->interface_id, prefix, eui64, THREAD_MIN_PREFIX_LIFETIME) != 0) { tr_warn("DHCP server alloc fail"); // set 20 seconds delay before next process this->br_delay_timer = 20; @@ -587,8 +590,6 @@ static void thread_bbr_network_data_send(thread_bbr_t *this, uint8_t prefix[8], } memcpy(this->bbr_prefix,prefix,8); - DHCPv6_server_service_set_address_validlifetime(this->interface_id, this->bbr_prefix, THREAD_MIN_PREFIX_LIFETIME); - br_info.P_default_route = true; br_info.P_dhcp = true; br_info.P_on_mesh = true; @@ -724,7 +725,7 @@ static bool thread_bbr_activated(thread_bbr_t *this, uint32_t seconds) return true; } - if (cur->thread_info->routerIdReqCoapID) { + if (cur->thread_info->routerIdRequested) { // Router id reguest pending we need to wait for response return false; } @@ -978,25 +979,31 @@ int thread_bbr_nd_entry_add (int8_t interface_id, const uint8_t *addr_data_ptr, int thread_bbr_dua_entry_add (int8_t interface_id, const uint8_t *addr_data_ptr, uint32_t lifetime, const uint8_t *mleid_ptr) { thread_bbr_t *this = thread_bbr_find_by_interface(interface_id); + thread_pbbr_dua_info_t *map; if (!this || this->backbone_interface_id < 0) { return -1; } - thread_pbbr_dua_info_t *map = ns_dyn_mem_alloc(sizeof(thread_pbbr_dua_info_t)); - if (!map) { - goto error; + ipv6_route_t *route = ipv6_route_lookup_with_info(addr_data_ptr, 128, interface_id, NULL, ROUTE_THREAD_PROXIED_DUA_HOST, NULL, 0); + if (!route){ + map = ns_dyn_mem_alloc(sizeof(thread_pbbr_dua_info_t)); + if (!map) { + goto error; + } + // We are using route info field to store BBR MLEID map + route = ipv6_route_add_with_info(addr_data_ptr, 128, interface_id, NULL, ROUTE_THREAD_PROXIED_DUA_HOST, map, 0, lifetime, 0); + if (!route) { + // Direct route to host allows ND proxying to work + ns_dyn_mem_free(map); + goto error; + } + // Route info autofreed + route->info_autofree = true; } + map = route->info.info; memcpy(map->mleid_ptr, mleid_ptr, 8); map->last_contact_time = protocol_core_monotonic_time; + route->info.info = map; - // We are using route info field to store BBR MLEID map - ipv6_route_t *route = ipv6_route_add_with_info(addr_data_ptr, 128, interface_id, NULL, ROUTE_THREAD_PROXIED_DUA_HOST, map, 0, lifetime, 0); - if (!route) { - // Direct route to host allows ND proxying to work - ns_dyn_mem_free(map); - goto error; - } - // Route info autofreed - route->info_autofree = true; // send NA thread_bbr_na_send(this->backbone_interface_id, addr_data_ptr); @@ -1006,15 +1013,6 @@ int thread_bbr_dua_entry_add (int8_t interface_id, const uint8_t *addr_data_ptr, return -2; } -struct ipv6_route *thread_bbr_dua_entry_find(int8_t interface_id, const uint8_t *addr_data_ptr) { - ipv6_route_t *route = ipv6_route_choose_next_hop(addr_data_ptr, interface_id, NULL); - if (!route || route->prefix_len < 128 || !route->on_link || route->info.source != ROUTE_THREAD_PROXIED_DUA_HOST ) { - //Not found - return NULL; - } - return route; -} - int thread_bbr_proxy_state_update(int8_t caller_interface_id , int8_t handler_interface_id, bool status) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(handler_interface_id); @@ -1099,7 +1097,11 @@ int thread_bbr_start(int8_t interface_id, int8_t backbone_interface_id) // By default multicast forwarding is not enabled as it causes multicast loops multicast_fwd_set_forwarding(this->interface_id, false); + // Adjust BBR neighbor and destination cache size + arm_nwk_ipv6_max_cache_entries(THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE); + thread_extension_bbr_init(interface_id,backbone_interface_id); + return 0; #else return -1; @@ -1131,6 +1133,17 @@ int thread_bbr_prefix_set(int8_t interface_id, uint8_t *prefix) #endif // HAVE_THREAD_BORDER_ROUTER } +int thread_bbr_sequence_number_set(int8_t interface_id, uint8_t sequence_number) +{ + (void) interface_id; + (void) sequence_number; +#ifdef HAVE_THREAD_BORDER_ROUTER + return thread_extension_bbr_sequence_number_set(interface_id, sequence_number); +#else + return -1; +#endif // HAVE_THREAD_BORDER_ROUTER +} + int thread_bbr_validation_interface_address_set(int8_t interface_id, const uint8_t *addr_ptr, uint16_t port) { (void) interface_id; diff --git a/source/6LoWPAN/Thread/thread_bbr_api_internal.h b/source/6LoWPAN/Thread/thread_bbr_api_internal.h index dd05ca7525b..9e434990331 100644 --- a/source/6LoWPAN/Thread/thread_bbr_api_internal.h +++ b/source/6LoWPAN/Thread/thread_bbr_api_internal.h @@ -67,7 +67,6 @@ void thread_bbr_seconds_timer(int8_t interface_id, uint32_t tics); */ int thread_bbr_commissioner_proxy_service_update(int8_t interface_id); - #else #define thread_bbr_init(interface_id, external_commisssioner_port) #define thread_bbr_delete(interface_id) @@ -118,12 +117,6 @@ int thread_bbr_dua_entry_add (int8_t interface_id, const uint8_t *addr_data_ptr, */ int thread_bbr_na_send(int8_t interface_id, const uint8_t target[static 16]); -/** - * \brief Find if bbr has dua entry - * - * \param interface_id addr_data_ptr - */ -struct ipv6_route *thread_bbr_dua_entry_find(int8_t interface_id, const uint8_t *addr_data_ptr); #else #define thread_bbr_proxy_state_update(caller_interface_id , handler_interface_id, status) (NULL) @@ -131,7 +124,6 @@ struct ipv6_route *thread_bbr_dua_entry_find(int8_t interface_id, const uint8_t #define thread_bbr_network_data_update_notify(cur) #define thread_bbr_nd_entry_add(interface_id, addr_data_ptr, lifetime, info) (0) #define thread_bbr_dua_entry_add(interface_id, addr_data_ptr, lifetime, mleid_ptr) (0) -#define thread_bbr_dua_entry_find(interface_id, addr_data_ptr) (NULL) #define thread_bbr_na_send(interface_id, target) (0) #endif //HAVE_THREAD_BORDER_ROUTER diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 0e26b643edf..f16ece331a6 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -86,7 +86,7 @@ #include "MPL/mpl.h" #include "MLE/mle.h" #include "MLE/mle_tlv.h" -#include "thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "thread_config.h" #include "thread_meshcop_lib.h" #include "multicast_api.h" @@ -136,8 +136,6 @@ static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void * static bool thread_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { - - // Sleepy host protocol_interface_info_entry_t *cur_interface = user_data; if (thread_am_router(cur_interface)) { @@ -676,8 +674,6 @@ static void thread_bootstrap_ml_address_update(protocol_interface_info_entry_t * // Generate new ML64 address thread_generate_ml64_address(cur); - // Generate new domain address - thread_extension_address_generate(cur); // Register multicast addresses thread_bootstrap_all_nodes_multicast_register(cur); @@ -698,8 +694,6 @@ int thread_configuration_thread_activate(protocol_interface_info_entry_t *cur, l //Define Default Contexts lowpan_context_update(&cur->lowpan_contexts, LOWPAN_CONTEXT_C, 0xFFFF, linkConfiguration->mesh_local_ula_prefix, 64, true); - thread_extension_activate(cur); - thread_extension_bbr_route_update(cur); blacklist_clear(); @@ -896,7 +890,7 @@ void thread_interface_init(protocol_interface_info_entry_t *cur) { thread_discovery_reset(cur->id); thread_routing_set_mesh_callbacks(cur); - thread_dhcp_client_init(cur->id); + dhcp_client_init(cur->id); thread_management_client_init(cur->id); thread_address_registration_init(); cur->mpl_seed_id_mode = MULTICAST_MPL_SEED_ID_MAC_SHORT; @@ -1069,9 +1063,7 @@ void thread_tasklet(arm_event_s *event) case THREAD_CHILD_UPDATE: tr_debug_extra("Thread SM THREAD_CHILD_UPDATE"); - if (thread_info(cur)->thread_endnode_parent) { - thread_host_bootstrap_child_update(cur, cur->thread_info->thread_endnode_parent->mac64); - } + thread_host_bootstrap_child_update(cur, cur->thread_info->thread_endnode_parent->mac64); break; case THREAD_ANNOUNCE_ACTIVE: { tr_debug_extra("Thread SM THREAD_ANNOUNCE_ACTIVE"); @@ -1178,6 +1170,10 @@ void thread_bootstrap_ready(protocol_interface_info_entry_t *cur) thread_leader_service_generate_network_data(cur); } + if (thread_addresses_needs_to_be_registered(cur)) { + thread_info(cur)->childUpdateReqTimer = 1; + } + cur->bootsrap_state_machine_cnt = 0; mac_data_poll_protocol_poll_mode_decrement(cur); } @@ -1194,6 +1190,31 @@ void thread_neighbor_list_clean(struct protocol_interface_info_entry *cur) } } +void thread_reed_fed_neighbour_links_clean(struct protocol_interface_info_entry *cur) +{ + mac_neighbor_table_list_t *mac_table_list = &mac_neighbor_info(cur)->neighbour_list; + + if (thread_i_am_router(cur)) { + return; + } + + if (thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE || + thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) { + return; + } + + if (!thread_info(cur)->thread_endnode_parent) { + return; + } + ns_list_foreach_safe(mac_neighbor_table_entry_t, cur_entry, mac_table_list) { + // do not remove parent entry + if (memcmp(cur_entry->mac64, thread_info(cur)->thread_endnode_parent->mac64, 8) != 0) { + tr_debug("Free short addr: %x", cur_entry->mac16); + mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), cur_entry); + } + } +} + void thread_clean_old_16_bit_address_based_addresses(protocol_interface_info_entry_t *cur) { uint8_t static_address[16]; @@ -1612,7 +1633,6 @@ void thread_bootstrap_routing_activate(protocol_interface_info_entry_t *cur) if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_FULL_END_DEVICE || cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) { thread_meshlocal_route_set(cur); - thread_extension_route_set(cur); // FEDs and routers (REEDs) perform their own address resolution thread_nd_service_activate(cur->id); } else { @@ -1627,7 +1647,7 @@ void thread_bootstrap_attached_finish(protocol_interface_info_entry_t *cur) cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY; cur->lowpan_info &= ~INTERFACE_NWK_ROUTER_DEVICE; cur->bootsrap_state_machine_cnt = 10; - cur->thread_info->routerIdReqCoapID = 0; + cur->thread_info->routerIdRequested = false; cur->thread_info->networkDataRequested = false; clear_power_state(ICMP_ACTIVE); @@ -1644,8 +1664,6 @@ void thread_bootstrap_attached_finish(protocol_interface_info_entry_t *cur) thread_generate_ml16_address(cur); //GENERATE ML-EID64 thread_generate_ml64_address(cur); - // Generate new domain address - thread_extension_address_generate(cur); thread_bootstrap_routing_activate(cur); thread_bootstrap_network_data_update(cur); // After successful attach if there is announcement info present, send announcement back to previous channel @@ -1823,8 +1841,7 @@ static void thread_dhcp_client_gua_error_cb(int8_t interface, uint8_t dhcp_addr[ tr_warn("Address Get fail: %s from: %s", trace_ipv6(prefix), trace_ipv6(dhcp_addr)); if (prefix && dhcp_addr) { tr_debug("Delete Current Server data"); - thread_dhcp_client_global_address_delete(interface, dhcp_addr, prefix); - //TODO shuold we try again or select new Server + dhcp_client_global_address_delete(interface, dhcp_addr, prefix); } } } @@ -1964,6 +1981,10 @@ void thread_discover_native_commissioner_response(protocol_interface_info_entry_ config_ptr[n].rfChannel = cur_class->channel; memcpy(config_ptr[n].name, cur_class->network_name, 16); memcpy(config_ptr[n].extented_pan_id, cur_class->extented_pan_id, 8); + memcpy(config_ptr[n].destination_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(&config_ptr[n].destination_address[8], cur_class->extented_mac, 8); + config_ptr[n].destination_address[8] ^= 2; + config_ptr[n].destination_port = cur_class->commissioner_port; n++; } @@ -2023,7 +2044,7 @@ void thread_discover_native_commissioner_response(protocol_interface_info_entry_ interface->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY; interface->lowpan_info &= ~INTERFACE_NWK_ROUTER_DEVICE; - interface->thread_info->routerIdReqCoapID = 0; + interface->thread_info->routerIdRequested = false; interface->thread_info->networkDataRequested = false; interface->bootsrap_state_machine_cnt = 10; @@ -2128,6 +2149,12 @@ static bool thread_bootstrap_sync_after_reset_start(protocol_interface_info_entr uint16_t my_short_address; uint8_t parent_mac64[8]; + // link sync is allowed only once in bootstrap start and we might get here in other cases also + if (!cur->thread_info->link_sync_allowed) { + return false; + } + cur->thread_info->link_sync_allowed = false; + int link_info_err = thread_nvm_store_link_info_get(parent_mac64, &my_short_address); if ( link_info_err!= THREAD_NVM_FILE_SUCCESS) { tr_warning("thread_nvm_store_link_info_get returned %d", link_info_err); @@ -2136,7 +2163,7 @@ static bool thread_bootstrap_sync_after_reset_start(protocol_interface_info_entr link_info_err = thread_nvm_store_link_info_clear(); if ( link_info_err!= THREAD_NVM_FILE_SUCCESS) { tr_warning("thread_nvm_store_link_info_clear returned %d", link_info_err); - } + } if (thread_is_router_addr(my_short_address)) { thread_info(cur)->routerShortAddress = my_short_address; thread_dynamic_storage_build_mle_table(cur->id); @@ -2278,7 +2305,7 @@ void thread_bootstrap_stop(protocol_interface_info_entry_t *cur) thread_leader_service_leader_data_free(cur->thread_info); thread_bootstrap_all_nodes_multicast_unregister(cur); thread_data_base_init(cur->thread_info, cur->id); - thread_dhcp_client_delete(cur->id); + dhcp_client_delete(cur->id); thread_nd_service_delete(cur->id); thread_child_id_request_entry_clean(cur); thread_registered_mcast_addr_entry_clean(cur); @@ -2356,6 +2383,7 @@ static int thread_nd_prefix_context_allocate(protocol_interface_info_entry_t *cu if (cid == 16) { return -1; } + context.cid = cid; context.compression = true; context.stableData = stableData; @@ -2499,6 +2527,7 @@ int thread_bootstrap_network_data_process(protocol_interface_info_entry_t *cur, genericService.P_slaac = ((flags >> THREAD_P_SLAAC_BIT_MOVE) & 1); genericService.P_on_mesh = ((flags >> THREAD_P_ON_MESH_BIT_MOVE) & 1); genericService.P_nd_dns = ((flags >> THREAD_P_ND_DNS_BIT_MOVE) & 1); + genericService.P_res1 = ((flags >> THREAD_P_ND_RES_BIT_MOVE) & 1); if (thread_nd_local_list_add_on_mesh_prefix(networkDataStorage, &prefixTlv, &genericService) == 0) { if (networkDataStorage->stableUpdatePushed || networkDataStorage->temporaryUpdatePushed) { if (!genericService.P_slaac) { @@ -2525,7 +2554,7 @@ int thread_bootstrap_network_data_process(protocol_interface_info_entry_t *cur, memcpy(&addr[8], ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(genericService.routerID, &addr[14]); tr_debug("Delete DHCPv6 given address"); - thread_dhcp_client_global_address_delete(cur->id, addr, prefixTlv.Prefix); + dhcp_client_global_address_delete(cur->id, addr, prefixTlv.Prefix); } } @@ -2702,6 +2731,8 @@ int thread_bootstrap_network_data_activate(protocol_interface_info_entry_t *cur) thread_border_router_network_data_update_notify(cur); thread_bbr_network_data_update_notify(cur); + thread_maintenance_timer_set(cur, THREAD_MAINTENANCE_TIMER_INTERVAL); + return 0; } @@ -2744,7 +2775,6 @@ int thread_bootstrap_network_data_save(protocol_interface_info_entry_t *cur, thr return 0; } - void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t *cur) { // Route prefix is variable-length, so need to zero pad for ip6tos @@ -2794,6 +2824,8 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * if (curBorderRouter->P_dhcp && weHostService && nd_proxy_enabled_for_upstream(cur->id) && nd_proxy_upstream_route_onlink(cur->id,curPrefix->servicesPrefix)) { // don't add tr_debug("Suppressing onlink %s for proxy", trace_ipv6_prefix(curPrefix->servicesPrefix, curPrefix->servicesPrefixLen)); + } else if (curBorderRouter->P_res1) { + ipv6_route_add(curPrefix->servicesPrefix, curPrefix->servicesPrefixLen, cur->id, NULL, ROUTE_THREAD_PROXIED_DUA_HOST, 0xffffffff, 0); } else { //add tr_debug("Adding onlink %s", trace_ipv6_prefix(curPrefix->servicesPrefix, curPrefix->servicesPrefixLen)); @@ -2818,8 +2850,8 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * if (!thread_dhcpv6_address_entry_available(curPrefix->servicesPrefix, &cur->ip_addresses)) { thread_addr_write_mesh_local_16(addr, curBorderRouter->routerID, cur->thread_info); /* Do not allow multiple DHCP solicits from one prefix => delete previous */ - thread_dhcp_client_global_address_delete(cur->id, NULL, curPrefix->servicesPrefix); - if (thread_dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, thread_dhcp_client_gua_error_cb) == 0) { + dhcp_client_global_address_delete(cur->id, NULL, curPrefix->servicesPrefix); + if (dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, thread_dhcp_client_gua_error_cb) == 0) { tr_debug("GP Address Requested"); } } @@ -2839,6 +2871,10 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * icmpv6_slaac_address_add(cur, curPrefix->servicesPrefix, curPrefix->servicesPrefixLen, 0xffffffff, 0xffffffff, true, SLAAC_IID_DEFAULT); } } + // generate address based on res1 bit + if (curBorderRouter->P_res1) { + thread_extension_dua_address_generate(cur,curPrefix->servicesPrefix,64); + } } // for each borderRouterList diff --git a/source/6LoWPAN/Thread/thread_bootstrap.h b/source/6LoWPAN/Thread/thread_bootstrap.h index 212f1ca0449..e45bb99a6f4 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_bootstrap.h @@ -106,6 +106,9 @@ void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, void thread_bootstrap_ready(struct protocol_interface_info_entry *cur); int thread_bootstrap_reset(struct protocol_interface_info_entry *cur); void thread_neighbor_list_clean(struct protocol_interface_info_entry *cur); + +/* Function to remove linked neighbours for REEDs and FEDs */ +void thread_reed_fed_neighbour_links_clean(struct protocol_interface_info_entry *cur); bool thread_bootstrap_request_network_data(struct protocol_interface_info_entry *cur, struct thread_leader_data_s *leaderData, uint16_t short_address); bool thread_check_is_this_my_parent(struct protocol_interface_info_entry *cur, struct mac_neighbor_table_entry *entry_temp); void thread_clean_old_16_bit_address_based_addresses(struct protocol_interface_info_entry *cur); @@ -191,7 +194,6 @@ int thread_bootstrap_announce_send(protocol_interface_info_entry_t *cur, uint8_t void thread_bootstrap_announcement_start(protocol_interface_info_entry_t *cur, uint8_t channel_page, uint16_t channel, uint8_t count, uint16_t period); void thread_bootstrap_temporary_attach(protocol_interface_info_entry_t *cur, uint8_t channel_page, uint16_t channel, uint16_t panid, uint64_t timestamp); - #else #define thread_interface_up(cur) ((void) 0) #define thread_bootstrap_state_machine(cur) ((void)0) diff --git a/source/6LoWPAN/Thread/thread_border_router_api.c b/source/6LoWPAN/Thread/thread_border_router_api.c index 8ca402db62b..83385243ce2 100644 --- a/source/6LoWPAN/Thread/thread_border_router_api.c +++ b/source/6LoWPAN/Thread/thread_border_router_api.c @@ -42,6 +42,7 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Thread/thread_config.h" #include "6LoWPAN/Thread/thread_common.h" +#include "6LoWPAN/Thread/thread_extension_bbr.h" #include "6LoWPAN/Thread/thread_network_data_lib.h" #include "6LoWPAN/Thread/thread_network_data_storage.h" #include "6LoWPAN/Thread/thread_management_client.h" @@ -591,6 +592,15 @@ void thread_border_router_network_data_update_notify(protocol_interface_info_ent thread_border_router_network_data_appl_callback(cur); } + +void thread_border_router_old_partition_data_clean(int8_t interface_id) +{ + thread_border_router_t *this = thread_border_router_find_by_interface(interface_id); + if (this) { + coap_service_request_delete_by_service_id(this->coap_service_id); + } + thread_extension_bbr_old_partition_data_clean(interface_id); +} #endif // HAVE_THREAD_ROUTER /*External APIs*/ @@ -837,7 +847,6 @@ int thread_border_router_dns_search_list_option_set(int8_t interface_id, uint8_t static void thread_tmf_client_network_data_set_cb(int8_t interface_id, int8_t status, uint8_t *data_ptr, uint16_t data_len) { protocol_interface_info_entry_t *cur; - (void) status; (void) data_len; (void) data_ptr; @@ -846,7 +855,7 @@ static void thread_tmf_client_network_data_set_cb(int8_t interface_id, int8_t st return; } - cur->thread_info->localServerDataBase.publish_active = false; + cur->thread_info->localServerDataBase.publish_coap_req_id = 0; tr_debug("BR a/sd response status: %s, addr: %x",status?"Fail":"OK", cur->thread_info->localServerDataBase.registered_rloc16); @@ -855,9 +864,11 @@ static void thread_tmf_client_network_data_set_cb(int8_t interface_id, int8_t st thread_border_router_publish(cur->id); } - // always update RLOC to new one. If COAP response fails then resubmit timer will trigger new a/sd - cur->thread_info->localServerDataBase.registered_rloc16 = mac_helper_mac16_address_get(cur); - cur->thread_info->localServerDataBase.release_old_address = false; + if (status == 0) { + // If request was successful, then update RLOC to new one. + cur->thread_info->localServerDataBase.registered_rloc16 = mac_helper_mac16_address_get(cur); + cur->thread_info->localServerDataBase.release_old_address = false; + } } #endif @@ -884,21 +895,20 @@ int thread_border_router_publish(int8_t interface_id) rloc16 = mac_helper_mac16_address_get(cur); tr_debug("Border router old: %x, new: %x", cur->thread_info->localServerDataBase.registered_rloc16, rloc16); - if (cur->thread_info->localServerDataBase.publish_active) { + if (cur->thread_info->localServerDataBase.publish_coap_req_id) { if (rloc16 != cur->thread_info->localServerDataBase.registered_rloc16) { /* - * Device short address has changed, cancel previous a/sd and a/as requests + * Device short address has changed, cancel previous a/sd requests * and start resubmit timer * */ - tr_debug("address changed, kill pending reuqests"); - thread_management_client_pending_coap_request_kill(cur->id); + tr_debug("RLOC changed, kill pending a/sd request"); + thread_management_client_coap_message_delete(cur->id, cur->thread_info->localServerDataBase.publish_coap_req_id); thread_border_router_resubmit_timer_set(interface_id, 5); - return 0; } else { cur->thread_info->localServerDataBase.publish_pending = true; tr_debug("Activate pending status for publish"); - return 0; } + return 0; } //Allocate Memory for Data @@ -926,8 +936,10 @@ int thread_border_router_publish(int8_t interface_id) if (payload_ptr) { ns_dyn_mem_free(payload_ptr); } - if (ret_val == 0) { - cur->thread_info->localServerDataBase.publish_active = true; + if (ret_val > 0) { + // a/sd request successful, save coap request id + cur->thread_info->localServerDataBase.publish_coap_req_id = (uint16_t)ret_val; + ret_val = 0 ; } thread_border_router_resubmit_timer_set(interface_id, -1); diff --git a/source/6LoWPAN/Thread/thread_border_router_api_internal.h b/source/6LoWPAN/Thread/thread_border_router_api_internal.h index 9d7694a23e2..c1227173dd7 100644 --- a/source/6LoWPAN/Thread/thread_border_router_api_internal.h +++ b/source/6LoWPAN/Thread/thread_border_router_api_internal.h @@ -85,6 +85,14 @@ void thread_border_router_network_data_appl_callback(protocol_interface_info_ent * */ void thread_border_router_network_data_update_notify(protocol_interface_info_entry_t *cur); + +/** + * \brief Clear data related to old partition. + * + * \param interface_id Network interface ID. + */ +void thread_border_router_old_partition_data_clean(int8_t interface_id); + #else #define thread_border_router_init(interface_id) #define thread_border_router_delete(interface_id) @@ -92,6 +100,7 @@ void thread_border_router_network_data_update_notify(protocol_interface_info_ent #define thread_border_router_resubmit_timer_set(interface_id, seconds) #define thread_border_router_network_data_appl_callback(cur) #define thread_border_router_network_data_update_notify(cur) +#define thread_border_router_old_partition_data_clean(interface_id) #endif #endif /* THREAD_BORDER_ROUTER_API_INTERNAL_H_ */ diff --git a/source/6LoWPAN/Thread/thread_commissioning_api.c b/source/6LoWPAN/Thread/thread_commissioning_api.c index a80a5ad58f1..f5815360ac7 100644 --- a/source/6LoWPAN/Thread/thread_commissioning_api.c +++ b/source/6LoWPAN/Thread/thread_commissioning_api.c @@ -35,6 +35,7 @@ #include "ns_list.h" #include "ns_trace.h" #include "nsdynmemLIB.h" +#include "randLIB.h" #include "common_functions.h" #include "ns_sha256.h" @@ -74,6 +75,8 @@ typedef NS_LIST_HEAD(device_t, link) device_list_t; typedef struct commissioner_entry { device_list_t device_list; uint8_t destination_address[16]; + uint8_t final_dest_address[16]; // Relay message final destination + uint8_t leader_address[16]; // leader ALOC for contacting the leader uint8_t PSKc_ptr[16]; thread_commissioning_status_cb *status_cb_ptr; uint16_t destination_port; @@ -82,7 +85,8 @@ typedef struct commissioner_entry { int8_t interface_id; int8_t coap_service_id; int8_t coap_secure_service_id; - int8_t coap_virtual_service_id; + int8_t coap_secure_virtual_service_id; + int8_t coap_udp_proxy_service_id; bool registered: 1; bool native_commissioner: 1; @@ -167,7 +171,7 @@ static commissioner_t *commissioner_find_by_service(int8_t service_id) { commissioner_t *this = NULL; ns_list_foreach(commissioner_t, cur_ptr, &instance_list) { - if (cur_ptr->coap_service_id == service_id || cur_ptr->coap_virtual_service_id == service_id || cur_ptr->coap_secure_service_id == service_id) { + if (cur_ptr->coap_service_id == service_id || cur_ptr->coap_secure_virtual_service_id == service_id || cur_ptr->coap_secure_service_id == service_id || cur_ptr->coap_udp_proxy_service_id == service_id) { this = cur_ptr; break; } @@ -237,12 +241,46 @@ static int commission_finalisation_resp_send(int8_t coap_service_id, device_t *d * Callback functions */ +static int thread_commissioning_active_get_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) +{ + commissioner_t *this = commissioner_find_by_service(service_id); + commissioning_state_e state = COMMISSIONING_STATE_REJECT;// Default is accept if we get error it is rejected + uint8_t *ptr; + uint16_t len; + (void) source_address; + (void) source_port; + + /* Transaction failed */ + if (!response_ptr) { + return -1; + } + + tr_debug("management get response from comm module"); + if (!this) { + return -2; + } + + if ((len = thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, &ptr)) > 0) { + state = COMMISSIONING_STATE_ACCEPT; + tr_debug(" TLV ml prefix=%s\r\n", trace_array(ptr, len)); + memcpy(this->leader_address, ptr, 8); + memcpy(this->leader_address + 8, ADDR_SHORT_ADR_SUFFIC, 6); + common_write_16_bit(0xfc00, this->leader_address + 14); + } + + if (this->status_cb_ptr) { + this->status_cb_ptr(this->interface_id, this->session_id, state); + } + return 0; +} + static int commissioning_leader_petition_recv_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) { commissioner_t *this = commissioner_find_by_service(service_id); commissioning_state_e state = COMMISSIONING_STATE_REJECT; uint16_t session_id = 0; - uint8_t *ptr; + uint8_t *ptr = NULL; + char *uri_ptr = THREAD_URI_ACTIVE_GET; (void) source_address; (void) source_port; @@ -267,6 +305,16 @@ static int commissioning_leader_petition_recv_cb(int8_t service_id, uint8_t sour } tr_debug("petition response session_id: %d state:%d",session_id, state); + // if registered and native commissioner send ACTIVE_GET to BBR to get mesh parameters + // if not native set leader ALOC from stack + if (this->native_commissioner) { + coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, uri_ptr, COAP_CT_OCTET_STREAM, NULL, 0, thread_commissioning_active_get_cb); + return 0; + } else { + thread_management_get_leader_aloc(this->interface_id, this->leader_address); + } + user_response: if (state == COMMISSIONING_STATE_REJECT) { thci_trace("commissionerPetitionRejected"); @@ -376,10 +424,54 @@ static int commission_dataset_changed_notify_recv_cb(int8_t service_id, uint8_t (void)source_port; tr_debug("Dataset changed - notification received from: %s", trace_ipv6(source_address)); + commissioner_t *this = commissioner_find_by_service(service_id); + + if (!this) { + return -1; + } + + coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_ACTIVE_GET, COAP_CT_OCTET_STREAM, NULL, 0, thread_commissioning_active_get_cb); + coap_service_response_send(service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_NONE, NULL, 0); return 0; } +static int thread_commission_udp_proxy_receive_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *request_ptr) +{ + tr_debug("Recv UDP_RX.ntf"); + + commissioner_t *this = commissioner_find_by_service(service_id); + uint8_t *udp_encapsulation_ptr, *udp_tmf_ptr; + uint16_t udp_encapsulation_len, udp_tmf_len; + uint8_t *ipv6_addr_ptr; + uint16_t ipv6_addr_len; + uint16_t dest_port; + + (void) source_port; + + if (!this || !source_address || !request_ptr) { + return -1; // goto error response + } + + udp_encapsulation_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_UDP_ENCAPSULATION, &udp_encapsulation_ptr); + ipv6_addr_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_IPV6_ADDRESS, &ipv6_addr_ptr); + + if (udp_encapsulation_len == 0 || ipv6_addr_len < 16) { + tr_warn("Corrupted UDP_RX.ntf received (%d, %d)", udp_encapsulation_len, ipv6_addr_len); + return -1; + } + + dest_port = common_read_16_bit(udp_encapsulation_ptr + 2); + udp_tmf_len = udp_encapsulation_len - 4; + udp_tmf_ptr = udp_encapsulation_ptr + 4; + + tr_debug("UDP_RX tmf: %s", trace_array(udp_tmf_ptr, udp_tmf_len)); + + coap_service_virtual_socket_recv(this->coap_udp_proxy_service_id, ipv6_addr_ptr, dest_port, udp_tmf_ptr, udp_tmf_len); + + return -1; // no response sent +} static uint8_t *bloom_filter_calculate(uint8_t *bloom_filter_ptr,device_list_t device_list, int *steering_tlv_max_length) { @@ -403,6 +495,35 @@ static uint8_t *bloom_filter_calculate(uint8_t *bloom_filter_ptr,device_list_t d return bloom_filter_ptr; } +static int thread_commissioner_set_steering_data(commissioner_t *this, uint16_t session_id, uint8_t *steering_data_ptr, uint8_t steering_data_len) +{ + uint8_t payload[24];/* 4 + 16 + 4*/ + uint8_t *ptr; + int8_t coap_service_id; + if (!this || steering_data_len > 16) { + return -1; + } + + ptr = payload; + ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_STEERING_DATA, steering_data_len, steering_data_ptr); + ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_COMMISSIONER_SESSION_ID, session_id); + + tr_debug("thread commissioner set steering data %s", trace_array(steering_data_ptr, steering_data_len)); + memcpy(this->final_dest_address, this->leader_address,16); + //default uri for thread version 1.1 + char *uri = THREAD_URI_COMMISSIONER_SET; + + if (this->native_commissioner) { + coap_service_id = this->coap_udp_proxy_service_id; + } else { + coap_service_id = this->coap_service_id; + } + + coap_service_request_send(coap_service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, uri, COAP_CT_OCTET_STREAM, payload, ptr - payload, NULL); + + return 0; +} static int commission_steering_data_update(commissioner_t *this) { @@ -414,7 +535,7 @@ static int commission_steering_data_update(commissioner_t *this) //bloom filter calculation function call bloom_filter_calculate(bloom_filter_ptr, this->device_list, &steering_tlv_length); tr_debug("Steering bloom set :%s", trace_array(bloom_filter_ptr, 16)); - ret = thread_management_set_steering_data(this->management_instance, this->session_id,bloom_filter_ptr, steering_tlv_length, NULL); + ret = thread_commissioner_set_steering_data(this, this->session_id,bloom_filter_ptr, steering_tlv_length); if (ret) { tr_warn("Steering data set failed %d", ret); return -1; @@ -475,7 +596,7 @@ static int commission_relay_rx_recv_cb(int8_t service_id, uint8_t source_address tr_warn("catching device for iid:%s", trace_array(&joiner_address[8], 8)); } device_ptr->joiner_router_rloc = joiner_router_rloc; - coap_service_virtual_socket_recv(this->coap_virtual_service_id, joiner_address, joiner_port, udp_ptr, udp_len); + coap_service_virtual_socket_recv(this->coap_secure_virtual_service_id, joiner_address, joiner_port, udp_ptr, udp_len); return -1; // no response sent } @@ -616,20 +737,55 @@ static int commissioner_br_security_done_cb(int8_t service_id, uint8_t address[1 return 0; } -static int thread_commissioning_remote_addr_set(commissioner_t *this) +static int thread_commission_udp_proxy_virtual_socket_send_cb(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port, const uint8_t *data_ptr, uint16_t data_len) { - if (0 == thread_management_get_leader_address(this->interface_id, this->destination_address)) { - tr_debug("on-mesh commissioner"); - this->destination_port = THREAD_MANAGEMENT_PORT; - this->native_commissioner = false; - } else if (0 == thread_commissioning_native_commissioner_get_connection_info(this->interface_id, - this->destination_address, &this->destination_port)) { - tr_debug("native commissioner"); - this->native_commissioner = true; - } else { - tr_error("No remote address"); + (void) port; + uint8_t *payload_ptr; + uint8_t *ptr; + uint16_t payload_len; + uint16_t source_port; + + commissioner_t *this = commissioner_find_by_service(service_id); + if (!this) { + return -1; + } + + tr_debug("UDP_TX.ntf tmf: %s", trace_array(data_ptr, data_len)); + if (!this || !destination_addr_ptr || !data_ptr) { return -1; } + + payload_len = 2 + THREAD_IPV6_ADDRESS_TLV_LENGTH + 4 + 4 + data_len; // MESHCOP_TLV_IPV6_ADDRESS + MESHCOP_TLV_UDP_ENCAPSULATION + + payload_ptr = ns_dyn_mem_alloc(payload_len); + if (!payload_ptr) { + return -3; + } + + ptr = payload_ptr; + + tr_debug("br_address %s final dest_address %s and port %d", trace_ipv6(this->destination_address), + trace_ipv6(this->final_dest_address), this->destination_port); + + /* MESHCOP_TLV_IPV6_ADDRESS */ + ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_IPV6_ADDRESS, THREAD_IPV6_ADDRESS_TLV_LENGTH, this->final_dest_address); + + /* MESHCOP_TLV_UDP_ENCAPSULATION */ + *ptr++ = MESHCOP_TLV_UDP_ENCAPSULATION; + *ptr++ = 0xff; + ptr = common_write_16_bit(2 + 2 + data_len, ptr); // length (Port x 2 + TMF message) + source_port = randLIB_get_16bit(); // ephemeral port, 16-bit number + ptr = common_write_16_bit(source_port, ptr); // source port, + ptr = common_write_16_bit(THREAD_MANAGEMENT_PORT, ptr); // destination port + memcpy(ptr, data_ptr, data_len); + ptr += data_len; + + /* Send UDP_TX.ntf */ + coap_service_request_send(this->coap_secure_service_id, COAP_REQUEST_OPTIONS_NONE, this->destination_address, this->destination_port, + COAP_MSG_TYPE_NON_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_UDP_TRANSMIT_NOTIFICATION, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr, NULL); + + ns_dyn_mem_free(payload_ptr); + return 0; } @@ -638,16 +794,17 @@ Public api functions */ int thread_commissioning_register(int8_t interface_id, uint8_t PSKc[static 16]) { - if (commissioner_find(interface_id)) { - return -1; + commissioner_t *this = commissioner_find(interface_id); + if (!this) { + this = commissioner_create(interface_id); } - commissioner_t *this = commissioner_create(interface_id); if (!this) { return -2; } memcpy(this->PSKc_ptr,PSKc,16); - - this->management_instance = thread_management_register(interface_id); + if (this->registered) { + return 0; + } this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); coap_service_register_uri(this->coap_service_id, THREAD_URI_RELAY_RECEIVE, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_relay_rx_recv_cb); coap_service_register_uri(this->coap_service_id, THREAD_URI_JOINER_APPLICATION_REQUEST, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_application_provision_req_recv_cb); @@ -655,10 +812,15 @@ int thread_commissioning_register(int8_t interface_id, uint8_t PSKc[static 16]) this->coap_secure_service_id = coap_service_initialize(this->interface_id, THREAD_COMMISSIONING_PORT, COAP_SERVICE_OPTIONS_SECURE | COAP_SERVICE_OPTIONS_SECURE_BYPASS, commissioner_br_security_start_cb, commissioner_br_security_done_cb); coap_service_register_uri(this->coap_secure_service_id, THREAD_URI_RELAY_RECEIVE, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_relay_rx_recv_cb); + coap_service_register_uri(this->coap_secure_service_id, THREAD_URI_UDP_RECVEIVE_NOTIFICATION, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_commission_udp_proxy_receive_cb); + + this->coap_secure_virtual_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_SECURE | COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET, joiner_commissioner_security_start_cb, commissioning_security_done_cb); + coap_service_register_uri(this->coap_secure_virtual_service_id, THREAD_URI_JOINER_FINALIZATION, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_finalisation_req_recv_cb); + coap_service_virtual_socket_set_cb(this->coap_secure_virtual_service_id, commission_virtual_socket_send_cb); + + this->coap_udp_proxy_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET, NULL, NULL); + coap_service_virtual_socket_set_cb(this->coap_udp_proxy_service_id, thread_commission_udp_proxy_virtual_socket_send_cb); - this->coap_virtual_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_SECURE | COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET, joiner_commissioner_security_start_cb, commissioning_security_done_cb); - coap_service_register_uri(this->coap_virtual_service_id, THREAD_URI_JOINER_FINALIZATION, COAP_SERVICE_ACCESS_POST_ALLOWED, commission_finalisation_req_recv_cb); - coap_service_virtual_socket_set_cb(this->coap_virtual_service_id, commission_virtual_socket_send_cb); return 0; } @@ -672,11 +834,11 @@ int thread_commissioning_unregister(int8_t interface_id) // Unregister the commissioner thread_commissioning_petition_keep_alive(this->interface_id, COMMISSIONING_STATE_REJECT); } - thread_management_unregister(this->management_instance); coap_service_delete(this->coap_service_id); coap_service_delete(this->coap_secure_service_id); - coap_service_delete(this->coap_virtual_service_id); + coap_service_delete(this->coap_secure_virtual_service_id); + coap_service_delete(this->coap_udp_proxy_service_id); commissioner_delete(this); return 0; @@ -690,7 +852,6 @@ int thread_commissioning_petition_start(int8_t interface_id, char *commissioner_ uint8_t service_id; uint8_t *ptr; char *uri_ptr; - this = commissioner_find(interface_id); if (!this) { @@ -705,16 +866,14 @@ int thread_commissioning_petition_start(int8_t interface_id, char *commissioner_ return -3; } - if (thread_commissioning_remote_addr_set(this)) { - return -4; - } - if (this->native_commissioner) { uri_ptr = THREAD_URI_COMMISSIONER_PETITION; service_id = this->coap_secure_service_id; } else { uri_ptr = THREAD_URI_LEADER_PETITION; service_id = this->coap_service_id; + thread_management_get_leader_aloc(this->interface_id, this->destination_address); + this->destination_port = THREAD_MANAGEMENT_PORT; } this->status_cb_ptr = status_cb_ptr; @@ -747,16 +906,13 @@ int thread_commissioning_petition_keep_alive(int8_t interface_id, commissioning_ return -1; } - if (thread_commissioning_remote_addr_set(this)) { - return -4; - } - if (this->native_commissioner) { uri_ptr = THREAD_URI_COMMISSIONER_KEEP_ALIVE; service_id = this->coap_secure_service_id; } else { uri_ptr = THREAD_URI_LEADER_KEEP_ALIVE; service_id = this->coap_service_id; + thread_management_get_leader_aloc(this->interface_id, this->destination_address); } ptr = payload; @@ -867,6 +1023,20 @@ void *thread_commission_device_get_next(void *ptr, int8_t interface_id, bool *sh return cur_ptr; } +int thread_commissioning_attach(int8_t interface_id, uint8_t *destination_address, uint16_t destination_port) +{ + tr_debug("start ethernet commissioner attach"); + commissioner_t *this = commissioner_find(interface_id); + if (!this) { + return -1; + } + memcpy(this->destination_address, destination_address,16); + this->destination_port = destination_port; + this->native_commissioner = true; + return 0; + +} + int thread_commissioning_native_commissioner_start(int8_t interface_id, thread_commissioning_native_select_cb *cb_ptr) { protocol_interface_info_entry_t *cur; @@ -909,6 +1079,18 @@ int thread_commissioning_native_commissioner_connect(int8_t interface_id, thread return -2; } *cur->thread_info->native_commissioner_link = *link_ptr; + + commissioner_t *this = commissioner_find(interface_id); + if (!this) { + this = commissioner_create(interface_id); + } + if (!this) { + return -3; + } + + this->native_commissioner = true; + memcpy(this->destination_address, link_ptr->destination_address,16); + this->destination_port = link_ptr->destination_port; //TODO check that we are scanning for networks and reset backup timers return 0; @@ -916,22 +1098,15 @@ int thread_commissioning_native_commissioner_connect(int8_t interface_id, thread int thread_commissioning_native_commissioner_get_connection_info(int8_t interface_id, uint8_t *address_ptr, uint16_t *port) { - protocol_interface_info_entry_t *cur; - cur = protocol_stack_interface_info_get_by_id(interface_id); + commissioner_t *this = commissioner_find(interface_id); tr_debug("get native connection info"); - if(!cur || !cur->thread_info) { + if (!this) { return -1; } - if (thread_attach_ready(cur) != 0) { - return -2; - } - if (protocol_6lowpan_interface_get_link_local_cordinator_address(cur, address_ptr) != 0) { - return -1; - } - if (port) { - *port = cur->thread_info->native_commissioner_port; - } + memcpy(address_ptr,this->destination_address,16); + + *port = this->destination_port; return 0; } @@ -1031,4 +1206,11 @@ int thread_commissioning_native_commissioner_connect(int8_t interface_id, thread return -1; } +int thread_commissioning_attach(int8_t interface_id, uint8_t *destination_address, uint16_t destination_port) { + (void)interface_id; + (void)destination_address; + (void)destination_port; + return -1; +} + #endif diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index 0716d79cf7a..567851ecb4b 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -44,9 +44,11 @@ #include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_beacon.h" +#include "6LoWPAN/Thread/thread_diagnostic.h" +#include "6LoWPAN/Thread/thread_extension_bbr.h" #include "6LoWPAN/Thread/thread_leader_service.h" #include "6LoWPAN/Thread/thread_routing.h" -#include "6LoWPAN/Thread/thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/Thread/thread_discovery.h" #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_router_bootstrap.h" @@ -60,6 +62,7 @@ #include "6LoWPAN/Thread/thread_management_internal.h" #include "6LoWPAN/Thread/thread_management_client.h" #include "6LoWPAN/Thread/thread_management_server.h" +#include "6LoWPAN/Thread/thread_resolution_server.h" #include "6LoWPAN/Thread/thread_resolution_client.h" #include "6LoWPAN/Thread/thread_address_registration_client.h" #include "6LoWPAN/Thread/thread_resolution_client.h" @@ -226,6 +229,7 @@ int8_t thread_bootstrap_up(protocol_interface_info_entry_t *cur) ret_val = nwk_6lowpan_up(cur); cur->nwk_nd_re_scan_count = 0; + cur->thread_info->link_sync_allowed = true; return ret_val; } @@ -258,9 +262,11 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur) thread_leader_mleid_rloc_map_to_nvm_write(cur); thread_bootstrap_stop(cur); mle_service_interface_unregister(cur->id); + thread_diagnostic_delete(cur->id); // delete before thread_management_server_delete as they share same coap_service id + thread_management_client_delete(cur->id); // delete before thread_management_server_delete as they share same coap_service id + thread_nd_service_disable(cur->id); // delete before thread_management_server_delete as they share same coap_service id thread_management_server_delete(cur->id); thread_joiner_application_deinit(cur->id); - thread_management_client_delete(cur->id); //free network Data thread_network_data_free_and_clean(&cur->thread_info->networkDataStorage); //free local also here @@ -451,7 +457,7 @@ void thread_data_base_init(thread_info_t *thread_info, int8_t interfaceId) thread_leader_commissioner_create(thread_info); thread_info->rfc6775 = false; thread_info->threadPrivatePrefixInfo.ulaValid = false; - thread_info->routerIdReqCoapID = 0; + thread_info->routerIdRequested = false; thread_info->networkDataRequested = false; thread_info->proactive_an_timer = 0; @@ -905,6 +911,7 @@ static void thread_child_update_req_timer(protocol_interface_info_entry_t *cur, if (cur->thread_info->childUpdateReqTimer == -1) { return; } + if (cur->thread_info->childUpdateReqTimer > seconds) { cur->thread_info->childUpdateReqTimer -= seconds; } else { @@ -945,6 +952,20 @@ static void thread_key_switch_timer(protocol_interface_info_entry_t *cur, uint16 } } +static void thread_maintenance_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + if (thread_info(cur)->thread_maintenance_timer) { + if (thread_info(cur)->thread_maintenance_timer > seconds) { + thread_info(cur)->thread_maintenance_timer -= seconds; + return; + } + } + + thread_info(cur)->thread_maintenance_timer = THREAD_MAINTENANCE_TIMER_INTERVAL ; + + thread_bootstrap_network_data_activate(cur); +} + void thread_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t ticks) { uint8_t leader_address[16]; @@ -1003,6 +1024,7 @@ void thread_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t ticks) } thread_router_bootstrap_timer(cur, ticks); + thread_maintenance_timer(cur, ticks); thread_border_router_seconds_timer(cur->id, ticks); thread_bbr_seconds_timer(cur->id, ticks); thread_lowpower_timer(cur, ticks); @@ -1720,9 +1742,105 @@ uint8_t *thread_leader_data_tlv_write(uint8_t *ptr, protocol_interface_info_entr return ptr; } +bool thread_addresses_needs_to_be_registered(protocol_interface_info_entry_t *cur) +{ + lowpan_context_t *ctx; + uint8_t thread_realm_local_mcast_addr[16]; + uint8_t thread_ll_unicast_prefix_based_mcast_addr[16]; + if (thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_SLEEPY_END_DEVICE && + thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_END_DEVICE) { + // No address registration for others than MED or SED + return false; + } + + // check for addresses + ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { + if (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_GLOBAL || (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_REALM_LOCAL + && !thread_addr_is_mesh_local_16(e->address, cur))) { + ctx = lowpan_context_get_by_address(&cur->lowpan_contexts, e->address); + if (!ctx) { + return true; + } + if (ctx->cid != 0) { + return true; + + } + } + } + + // check for multicast groups + thread_bootstrap_all_nodes_address_generate(thread_realm_local_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_REALM_LOCAL); + thread_bootstrap_all_nodes_address_generate(thread_ll_unicast_prefix_based_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_LINK_LOCAL); + ns_list_foreach(if_group_entry_t, entry, &cur->ip_groups) + { + if (!memcmp((entry->group), ADDR_MULTICAST_SOLICITED, 13)) { + /* Skip solicited node multicast address */ + continue; + } + if (addr_ipv6_equal(entry->group, thread_realm_local_mcast_addr)) { + /* Skip well-known realm-local all Thread nodes multicast address */ + continue; + } + if (addr_ipv6_equal(entry->group, thread_ll_unicast_prefix_based_mcast_addr)) { + /* Skip well-known link-local all Thread nodes multicast address */ + continue; + } + if (addr_ipv6_equal(entry->group, ADDR_ALL_MPL_FORWARDERS)) { + /* Skip All MPL Forwarders address */ + continue; + } + if (addr_ipv6_equal(entry->group, ADDR_REALM_LOCAL_ALL_NODES)) { + /* Skip Mesh local all nodes */ + continue; + } + if (addr_ipv6_equal(entry->group, ADDR_REALM_LOCAL_ALL_ROUTERS)) { + /* Skip Mesh local all routers */ + continue; + } + return true; + } + return false; +} + +uint8_t *thread_ml_address_tlv_write(uint8_t *ptr, protocol_interface_info_entry_t *cur) +{ + lowpan_context_t *ctx; + uint8_t *address_len_ptr; + + if (thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_SLEEPY_END_DEVICE && + thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_END_DEVICE) { + // No address registration for others than MED or SED + return ptr; + } + *ptr++ = MLE_TYPE_ADDRESS_REGISTRATION; + address_len_ptr = ptr++; + + *address_len_ptr = 0; + + ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { + + if (*address_len_ptr > 148 ) { + // Maximum length of address registrations + continue; + } + if (!thread_addr_is_mesh_local_16(e->address, cur)) { + ctx = lowpan_context_get_by_address(&cur->lowpan_contexts, e->address); + if (ctx && ctx->cid == 0) { + //Write TLV to list + *ptr++ = (ctx->cid | 0x80); + memcpy(ptr, e->address + 8, 8); + ptr += 8; + *address_len_ptr += 9; + } + } + } + return ptr; +} + uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_info_entry_t *cur) { uint8_t thread_realm_local_mcast_addr[16]; + uint8_t thread_ll_unicast_prefix_based_mcast_addr[16]; lowpan_context_t *ctx; uint8_t *address_len_ptr; @@ -1738,7 +1856,6 @@ uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_ // Register all global addressess ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) { - if (*address_len_ptr > 148 ) { // Maximum length of address registrations continue; @@ -1762,23 +1879,27 @@ uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_ } /* Registers multicast addresses to the parent */ - thread_bootstrap_all_nodes_address_generate(thread_realm_local_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 3); - + thread_bootstrap_all_nodes_address_generate(thread_realm_local_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_REALM_LOCAL); + thread_bootstrap_all_nodes_address_generate(thread_ll_unicast_prefix_based_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_LINK_LOCAL); ns_list_foreach(if_group_entry_t, entry, &cur->ip_groups) { if (*address_len_ptr > 148) { // Maximum length of address registrations continue; } - if (addr_ipv6_multicast_scope(entry->group) < IPV6_SCOPE_REALM_LOCAL) { - /* Skip Link Local multicast address */ + + if (!memcmp((entry->group), ADDR_MULTICAST_SOLICITED, 13)) { + /* Skip solicited node multicast address */ continue; } - if (addr_ipv6_equal(entry->group, thread_realm_local_mcast_addr)) { /* Skip well-known realm-local all Thread nodes multicast address */ continue; } + if (addr_ipv6_equal(entry->group, thread_ll_unicast_prefix_based_mcast_addr)) { + /* Skip well-known link-local all Thread nodes multicast address */ + continue; + } if (addr_ipv6_equal(entry->group, ADDR_ALL_MPL_FORWARDERS)) { /* Skip All MPL Forwarders address */ continue; @@ -1935,9 +2056,34 @@ static void thread_address_notification_cb(struct protocol_interface_info_entry } } -void thread_mcast_group_change(struct protocol_interface_info_entry *interface, if_group_entry_t *group, bool addr_added) +static bool thread_mcast_should_register_address(struct protocol_interface_info_entry *cur, uint8_t *addr) { + uint8_t thread_realm_local_mcast_addr[16]; + uint8_t thread_ll_unicast_prefix_based_mcast_addr[16]; + thread_bootstrap_all_nodes_address_generate(thread_realm_local_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_REALM_LOCAL); + thread_bootstrap_all_nodes_address_generate(thread_ll_unicast_prefix_based_mcast_addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, IPV6_SCOPE_LINK_LOCAL); + if (addr_ipv6_multicast_scope(addr) >= IPV6_SCOPE_LINK_LOCAL) { + if (memcmp(addr, ADDR_MULTICAST_SOLICITED, 13) == 0) { + return false; + } + if (memcmp(addr, thread_realm_local_mcast_addr, 16) == 0) { + return false; + } + if (memcmp(addr, thread_ll_unicast_prefix_based_mcast_addr, 16) == 0) { + return false; + } + if (memcmp(addr, ADDR_LINK_LOCAL_ALL_NODES, 16) == 0) { + return false; + } + if (memcmp(addr, ADDR_LINK_LOCAL_ALL_ROUTERS, 16) == 0) { + return false; + } + } + return true; +} +void thread_mcast_group_change(struct protocol_interface_info_entry *interface, if_group_entry_t *group, bool addr_added) +{ if (thread_attach_ready(interface) != 0) { return; } @@ -1946,7 +2092,7 @@ void thread_mcast_group_change(struct protocol_interface_info_entry *interface, if (thread_bootstrap_should_register_address(interface)) { /* Trigger Child Update Request only if MTD child's multicast address change */ - if (addr_ipv6_multicast_scope(group->group) > IPV6_SCOPE_LINK_LOCAL) { + if (thread_mcast_should_register_address(interface, group->group)) { interface->thread_info->childUpdateReqTimer = 1; } } else { @@ -1956,10 +2102,16 @@ void thread_mcast_group_change(struct protocol_interface_info_entry *interface, } } +static void thread_old_partition_data_clean(int8_t interface_id) +{ + thread_management_client_old_partition_data_clean(interface_id); + thread_border_router_old_partition_data_clean(interface_id); +} + void thread_partition_data_purge(protocol_interface_info_entry_t *cur) { /* Partition has been changed. Wipe out data related to old partition */ - thread_management_client_pending_coap_request_kill(cur->id); + thread_old_partition_data_clean(cur->id); /* Reset previous routing information */ thread_routing_reset(&cur->thread_info->routing); @@ -1967,6 +2119,9 @@ void thread_partition_data_purge(protocol_interface_info_entry_t *cur) /* Flush address cache */ ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache); + /* Remove linked neighbours for REEDs and FEDs */ + thread_reed_fed_neighbour_links_clean(cur); + } bool thread_partition_match(protocol_interface_info_entry_t *cur, thread_leader_data_t *leaderData) @@ -1997,5 +2152,10 @@ void thread_neighbor_communication_update(protocol_interface_info_entry_t *cur, thread_neighbor_last_communication_time_update(&cur->thread_info->neighbor_class, neighbor_attribute_index); } +void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur, uint16_t delay) +{ + thread_info(cur)->thread_maintenance_timer = delay; +} + #endif diff --git a/source/6LoWPAN/Thread/thread_common.h b/source/6LoWPAN/Thread/thread_common.h index 09ffce3900f..6e849529875 100644 --- a/source/6LoWPAN/Thread/thread_common.h +++ b/source/6LoWPAN/Thread/thread_common.h @@ -309,10 +309,10 @@ typedef struct thread_info_s { uint16_t routerShortAddress; uint16_t reedJitterTimer; uint16_t reedMergeAdvTimer; - uint16_t routerIdReqCoapID; // COAP msg id of RouterID request int16_t childUpdateReqTimer; uint16_t childUpdateReqMsgId; uint16_t proactive_an_timer; + uint16_t thread_maintenance_timer; //uint8_t lastValidRouteMask[8]; int8_t interface_id; //Thread Interface ID uint8_t version; @@ -322,11 +322,13 @@ typedef struct thread_info_s { bool rfc6775: 1; bool requestFullNetworkData: 1; bool leaderCab: 1; + bool routerIdRequested: 1; bool releaseRouterId: 1; bool networkSynch: 1; bool networkDataRequested: 1; bool end_device_link_synch: 1; bool router_mc_addrs_registered: 1; + bool link_sync_allowed:1; bool leader_synced:1; // flag used by leader after restart } thread_info_t; @@ -397,6 +399,11 @@ void thread_child_mcast_entries_remove(protocol_interface_info_entry_t *cur, con uint8_t thread_leader_data_tlv_size(protocol_interface_info_entry_t *cur); uint8_t *thread_leader_data_tlv_write(uint8_t *ptr, protocol_interface_info_entry_t *cur); uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_info_entry_t *cur); + +// returns true if SED/MED needs to register additional address to parent +bool thread_addresses_needs_to_be_registered(protocol_interface_info_entry_t *cur); +// write mesh local address tlv +uint8_t *thread_ml_address_tlv_write(uint8_t *ptr, protocol_interface_info_entry_t *cur); int thread_link_reject_send(protocol_interface_info_entry_t *interface, const uint8_t *ll64); thread_leader_info_t *thread_allocate_and_init_leader_private_data(void); thread_route_cost_t thread_link_quality_to_cost(thread_link_quality_e quality); @@ -441,6 +448,7 @@ bool thread_partition_match(protocol_interface_info_entry_t *cur, thread_leader_ void thread_partition_info_update(protocol_interface_info_entry_t *cur, thread_leader_data_t *leaderData); void thread_neighbor_communication_update(protocol_interface_info_entry_t *cur, uint8_t neighbor_attribute_index); bool thread_stable_context_check(protocol_interface_info_entry_t *cur, buffer_t *buf); +void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur, uint16_t delay); #else // HAVE_THREAD NS_DUMMY_DEFINITIONS_OK diff --git a/source/6LoWPAN/Thread/thread_config.h b/source/6LoWPAN/Thread/thread_config.h index 0db796cd5d9..cd7406d6eba 100644 --- a/source/6LoWPAN/Thread/thread_config.h +++ b/source/6LoWPAN/Thread/thread_config.h @@ -326,6 +326,17 @@ */ #define THREAD_BBR_ROUTER_ID_REQUEST_STATUS THREAD_COAP_STATUS_TLV_HAVE_CHILD_ID_REQUEST +/* + * Number of destination and neighbor cache entries assuming 250 thread devices (worst case) connecting to cloud service. + * Six entries reserved for backbone devices. + */ +#define THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE 256 + +/* + * Timeout to solicit address from DHCP if previous request fails. + */ +#define THREAD_MAINTENANCE_TIMER_INTERVAL 300 + /** * Build time flag to enable THCI special traces for test harness purposes */ diff --git a/source/6LoWPAN/Thread/thread_constants.h b/source/6LoWPAN/Thread/thread_constants.h index 4150f4cc237..971a1fa1c97 100644 --- a/source/6LoWPAN/Thread/thread_constants.h +++ b/source/6LoWPAN/Thread/thread_constants.h @@ -145,6 +145,7 @@ #define THREAD_DEFAULT_KEY_SWITCH_GUARD_TIME 624 // Hours #define THREAD_DEFAULT_KEY_ROTATION 672 // Hours #define THREAD_COMMISSIONER_KEEP_ALIVE_INTERVAL 50000 // Default thread commissioner keep-alive message interval (milliseconds) +#define THREAD_DELAY_JOIN_ENT 50 // Minimum delay for Joiner router before sending joiner entrust (milliseconds) #define THREAD_FAILED_CHILD_TRANSMISSIONS 4 #define THREAD_FAILED_ROUTER_TRANSMISSIONS 4 diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_client.h b/source/6LoWPAN/Thread/thread_dhcpv6_client.h deleted file mode 100644 index cc97006e05a..00000000000 --- a/source/6LoWPAN/Thread/thread_dhcpv6_client.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2014-2015, 2017, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef SOURCE_6LOWPAN_THREAD_THREAD_DHCPV6_CLIENT_H_ -#define SOURCE_6LOWPAN_THREAD_THREAD_DHCPV6_CLIENT_H_ - -#include - -/* Thread DHCP client implementation. - * - * Responsibilities of this module are: - * - send router id address request and receive new router address and inform it to thread bootstrap. - * - handle Global address queries and refresh inside thread network. - * - */ - -/* Initialize dhcp thread dhcp client. - * - * This instance needs to bee initialized once for each thread network interface. - * if only one thread instance is supported this is needed to call only once. - * - * /param interface interface id of this thread instance. - * - */ - -void thread_dhcp_client_init(int8_t interface); - -/* Delete dhcp thread dhcp client. - * - * When this is called all addressed assigned by this module are removed from stack. - */ -void thread_dhcp_client_delete(int8_t interface); - -/* Global address handler. - * - * This module updates the addresses from dhcp server and sets them in stack. - * this module makes refresh of address when needed. - * - */ - - -/* give dhcp server and prefix for global address assignment - * - * /param interface interface where address is got - * /param dhcp_addr dhcp server ML16 address where address is registered. - * /param prefix dhcp server ML16 address where address is registered. - * /param mac64 64 bit mac address for identifieng client. - * /param error_cb error callback that is called if address cannot be created or becomes invalid. - * /param register_status true if address registered. - * - */ -typedef void (thread_dhcp_client_global_adress_cb)(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status); - -int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], thread_dhcp_client_global_adress_cb *error_cb); - -/* Renew all leased adddresses might be used when short address changes - * - * /param interface interface where address is got - */ -void thread_dhcp_client_global_address_renew(int8_t interface); - -/* Delete address from device - * if prefix is NULL all are deleted - * - * /param interface interface where address is got - * /param prefix dhcp server ML16 address where address is registered. - * - */ -void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]); - -#endif /* SOURCE_6LOWPAN_THREAD_THREAD_DHCPV6_CLIENT_H_ */ diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_server.c b/source/6LoWPAN/Thread/thread_dhcpv6_server.c new file mode 100644 index 00000000000..f0c8f6dafe2 --- /dev/null +++ b/source/6LoWPAN/Thread/thread_dhcpv6_server.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "nsconfig.h" +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) +#include +#include +#include "eventOS_event.h" +#include "eventOS_event_timer.h" +#include "common_functions.h" +#include "ns_trace.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "ipv6_stack/protocol_ipv6.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Common_Protocols/ipv6.h" +#include "DHCPv6_Server/DHCPv6_server_service.h" +#include "6LoWPAN/Thread/thread_bbr_api_internal.h" + +#define TRACE_GROUP "thds" + +static void thread_service_remove_GUA_from_neighcache(protocol_interface_info_entry_t *cur, uint8_t *targetAddress) +{ + ipv6_neighbour_t *neighbour_entry; + + neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, targetAddress); + if (neighbour_entry) { + tr_debug("Remove from neigh Cache: %s", tr_ipv6(targetAddress)); + ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, neighbour_entry); + } +} + +static void thread_dhcp_address_prefer_remove_cb(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info) +{ + protocol_interface_info_entry_t *curPtr = protocol_stack_interface_info_get_by_id(interfaceId); + if (!curPtr) { + return; + } + if (!targetAddress) { + //Clear All targets routes + ipv6_route_table_remove_info(interfaceId, ROUTE_THREAD_PROXIED_HOST,prefix_info); + } else { + tr_debug("Address Preferred Timeout"); + ipv6_route_delete(targetAddress, 128, interfaceId, NULL, ROUTE_THREAD_PROXIED_HOST); + thread_service_remove_GUA_from_neighcache(curPtr, targetAddress); + + } + +} + +static bool thread_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_update_t *address_info, void *route_src) +{ + protocol_interface_info_entry_t *curPtr = protocol_stack_interface_info_get_by_id(interfaceId); + if (!curPtr) { + return false; + } + + // If this is solicit from existing address, flush ND cache. + if (address_info->allocatedNewAddress) { + // coverity[returned_null] for ignoring protocol_stack_interface_info_get_by_id NULL return + thread_service_remove_GUA_from_neighcache(curPtr, address_info->allocatedAddress); + } + + if (thread_bbr_nd_entry_add(interfaceId,address_info->allocatedAddress, address_info->validLifeTime, route_src) == -1) { + // No nanostack BBR present we will put entry for application implemented BBR + ipv6_route_t *route = ipv6_route_add_with_info(address_info->allocatedAddress, 128, interfaceId, NULL, ROUTE_THREAD_PROXIED_HOST,route_src,0, address_info->validLifeTime, 0); + if (!route) { + return false; + } + + } + return true; +} + +int thread_dhcp6_server_init(int8_t interface_id, uint8_t prefix[8], uint8_t eui64[8], uint32_t validLifeTimne) +{ + if (DHCPv6_server_service_init(interface_id, prefix, eui64, DHCPV6_DUID_HARDWARE_EUI64_TYPE) != 0) { + return -1; + } + //Register Callbacks + DHCPv6_server_service_callback_set(interface_id, prefix, thread_dhcp_address_prefer_remove_cb, thread_dhcp_address_add_cb); + //SET Timeout + DHCPv6_server_service_set_address_validlifetime(interface_id, prefix, validLifeTimne); + + return 0; +} + +#endif diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_server.h b/source/6LoWPAN/Thread/thread_dhcpv6_server.h new file mode 100644 index 00000000000..b8e56a63f0b --- /dev/null +++ b/source/6LoWPAN/Thread/thread_dhcpv6_server.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THREAD_DHCPV6_SERVER_H_ +#define THREAD_DHCPV6_SERVER_H_ +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) +int thread_dhcp6_server_init(int8_t interface_id, uint8_t prefix[8], uint8_t eui64[8], uint32_t validLifeTimne); +#else +#define thread_dhcp6_server_init(interface_id, prefix, eui64, validLifeTimne) (-1) +#endif + + +#endif /* THREAD_DHCPV6_SERVER_H_ */ diff --git a/source/6LoWPAN/Thread/thread_diagnostic.c b/source/6LoWPAN/Thread/thread_diagnostic.c index fdce83ece82..33e1b419c3d 100644 --- a/source/6LoWPAN/Thread/thread_diagnostic.c +++ b/source/6LoWPAN/Thread/thread_diagnostic.c @@ -35,6 +35,7 @@ #include "nsdynmemLIB.h" #include "net_interface.h" #include "thread_management_if.h" +#include "thread_management_server.h" #include "thread_common.h" #include "thread_joiner_application.h" #include "thread_leader_service.h" @@ -229,6 +230,10 @@ static int thread_diagnostic_configuration_calc(protocol_interface_info_entry_t payload_len += 2+1; break; + case DIAGCOP_TLV_MAX_CHILD_TIMEOUT: + payload_len += 2 + 4; + break; + default: // todo: Other TLV's not supported atm break; @@ -254,6 +259,7 @@ static uint8_t *thread_diagnostic_get_build(protocol_interface_info_entry_t *cur uint8_t *ptr; int written_address_count = 0; uint16_t ipv6_address_count = 0; + uint32_t max_child_timeout = 0; uint8_t extended_address[8] = {0}; arm_net_interface_address_list_size(cur->id, &ipv6_address_count); @@ -352,6 +358,12 @@ static uint8_t *thread_diagnostic_get_build(protocol_interface_info_entry_t *cur response_ptr = thread_diagcop_tlv_data_write_uint8(response_ptr, DIAGCOP_TLV_CHANNEL_PAGES, 0); break; + case DIAGCOP_TLV_MAX_CHILD_TIMEOUT: + if (thread_router_bootstrap_child_max_timeout_get(cur, &max_child_timeout) == 0) { + response_ptr = thread_diagcop_tlv_data_write_uint32(response_ptr, DIAGCOP_TLV_MAX_CHILD_TIMEOUT, max_child_timeout); + } + break; + default: break; @@ -532,7 +544,7 @@ int thread_diagnostic_init(int8_t interface_id) this->interface_id = interface_id; - this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); + this->coap_service_id = thread_management_server_service_id_get(interface_id); if (this->coap_service_id < 0) { tr_error("Thread diagnostic init failed"); ns_dyn_mem_free(this); @@ -556,8 +568,9 @@ int thread_diagnostic_delete(int8_t interface_id) if (!this) { return -1; } - - coap_service_delete(this->coap_service_id); + coap_service_unregister_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_REQUEST); + coap_service_unregister_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_RESET); + coap_service_unregister_uri(this->coap_service_id, THREAD_URI_DIAGNOSTIC_QUERY); ns_list_remove(&instance_list, this); ns_dyn_mem_free(this); return 0; diff --git a/source/6LoWPAN/Thread/thread_extension.h b/source/6LoWPAN/Thread/thread_extension.h index 671ea9823c8..b6f64d1e909 100644 --- a/source/6LoWPAN/Thread/thread_extension.h +++ b/source/6LoWPAN/Thread/thread_extension.h @@ -46,19 +46,15 @@ void thread_extension_allocate(protocol_interface_info_entry_t *cur); void thread_extension_free(protocol_interface_info_entry_t *cur); void thread_extension_init(int8_t interface_id, int8_t coap_service_id); void thread_extension_mtd_service_register(protocol_interface_info_entry_t *cur); -int thread_extension_network_prefix_get(int8_t interface_id, uint8_t *options_ptr, uint8_t *prefix_ptr, uint8_t *prefix_len); void thread_extension_network_data_process(struct protocol_interface_info_entry *cur); int thread_extension_primary_bbr_get(struct protocol_interface_info_entry *cur, uint8_t *addr_ptr, uint8_t *seq_ptr, uint32_t *timer1_ptr, uint32_t *timer2_ptr); void thread_extension_address_registration(struct protocol_interface_info_entry *interface, const uint8_t *addr, const uint8_t *child_mac64, bool refresh_child_entry, bool duplicate_child_detected); -void thread_extension_address_generate(protocol_interface_info_entry_t *cur); +void thread_extension_dua_address_generate(protocol_interface_info_entry_t *cur, const uint8_t *domain_prefix, uint8_t domain_prefix_len); void thread_extension_aloc_generate(struct protocol_interface_info_entry *cur); bool thread_extension_aloc_map(protocol_interface_info_entry_t *cur, uint16_t *addr16); void thread_extension_mcast_subscrition_change(protocol_interface_info_entry_t *interface); void thread_extension_address_registration_trigger(protocol_interface_info_entry_t *interface); -void thread_extension_route_set(protocol_interface_info_entry_t *cur); -void thread_extension_activate(protocol_interface_info_entry_t *cur); bool thread_extension_enabled(protocol_interface_info_entry_t *cur); -bool thread_extension_context_can_delete(int8_t id, uint8_t servicesPrefix[16], uint8_t context_prefix_length); bool thread_extension_version_check(uint8_t version); void thread_extension_discover_response_read(struct discovery_response_list *nwk_info, uint16_t discover_response_tlv, uint8_t *data_ptr, uint16_t data_len); void thread_extension_discover_response_tlv_write(uint16_t *data, uint8_t version, uint16_t securityPolicy); @@ -70,35 +66,31 @@ uint8_t thread_extension_discover_response_len(protocol_interface_info_entry_t * uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_t *cur, uint8_t *ptr); #else -#define thread_extension_joining_enabled(interface_id) false -#define thread_extension_discover_response_len(cur) 0 +#define thread_extension_joining_enabled(interface_id) (false) +#define thread_extension_discover_response_len(cur) (0) #define thread_extension_discover_response_write(cur, ptr) (ptr) #endif //HAVE_THREAD_ROUTER #else -#define thread_extension_allocate(cur) -#define thread_extension_free(cur) -#define thread_extension_init(interface_id,coap_service_id) -#define thread_extension_network_prefix_get(interface_id,options_ptr,prefix_ptr,prefix_len) (-1) -#define thread_extension_network_data_process(cur) +#define thread_extension_allocate(cur) ((void) 0) +#define thread_extension_free(cur) ((void) 0) +#define thread_extension_init(interface_id,coap_service_id) ((void) 0) +#define thread_extension_network_data_process(cur) ((void) 0) #define thread_extension_primary_bbr_get(cur,addr_ptr,seq_ptr,timer1_ptr, timer2_ptr) (-1) -#define thread_extension_address_registration(interface,addr,child_mac64,refresh_child_entry,duplicate_child_detected) -#define thread_extension_address_generate(cur) -#define thread_extension_aloc_generate(cur) -#define thread_extension_aloc_map(cur, addr16) false -#define thread_extension_mcast_subscrition_change(interface) -#define thread_extension_route_set(cur) -#define thread_extension_activate(cur) +#define thread_extension_address_registration(interface,addr,child_mac64,refresh_child_entry,duplicate_child_detected) ((void) 0) +#define thread_extension_aloc_generate(cur) ((void) 0) +#define thread_extension_aloc_map(cur, addr16) (false) +#define thread_extension_mcast_subscrition_change(interface) ((void) 0) #define thread_extension_enabled(cur) (false) #define thread_extension_version_check(version) (false) -#define thread_extension_discover_response_read(nwk_info, discover_response_tlv, data_ptr, data_len) -#define thread_extension_discover_response_tlv_write(data, version, extension_bit) (data) -#define thread_extension_service_init(cur) 0 -#define thread_extension_joining_enabled(interface_id) false -#define thread_extension_discover_response_len(cur) 0 +#define thread_extension_discover_response_read(nwk_info, discover_response_tlv, data_ptr, data_len) ((void) 0) +#define thread_extension_discover_response_tlv_write(data, version, securityPolicy) ((void) 0) +#define thread_extension_service_init(cur) (0) +#define thread_extension_joining_enabled(interface_id) (false) +#define thread_extension_discover_response_len(cur) (0) #define thread_extension_discover_response_write(cur, ptr) (ptr) -#define thread_extension_addr_ntf_send(cur,destination_address,addr_data_ptr,bbr_status) -#define thread_extension_context_can_delete(id, servicesPrefix, context_prefix_length) false +#define thread_extension_addr_ntf_send(cur,destination_address,addr_data_ptr,bbr_status) ((void) 0) +#define thread_extension_dua_address_generate(cur, domain_prefix, domain_prefix_len) ((void) 0) #endif #ifdef __cplusplus diff --git a/source/6LoWPAN/Thread/thread_extension_bbr.h b/source/6LoWPAN/Thread/thread_extension_bbr.h index cad08464b09..153a82bac22 100644 --- a/source/6LoWPAN/Thread/thread_extension_bbr.h +++ b/source/6LoWPAN/Thread/thread_extension_bbr.h @@ -52,10 +52,12 @@ int8_t thread_extension_bbr_init(int8_t interface_id, int8_t backbone_interface_ void thread_extension_bbr_delete(int8_t interface_id); bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr, uint16_t rloc); void thread_extension_bbr_seconds_timer(int8_t interface_id, uint32_t seconds); +int thread_extension_bbr_sequence_number_set(int8_t interface_id, uint8_t seq_number); int thread_extension_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t timeout_b, uint32_t delay); int thread_extension_bbr_address_set(int8_t interface_id, const uint8_t *addr_ptr, uint16_t port); void thread_extension_bbr_route_update(protocol_interface_info_entry_t *cur); int thread_extension_bbr_prefix_set(int8_t interface_id, uint8_t *prefix); +void thread_extension_bbr_old_partition_data_clean(int8_t interface_id); #else @@ -67,7 +69,9 @@ int thread_extension_bbr_prefix_set(int8_t interface_id, uint8_t *prefix); #define thread_extension_bbr_timeout_set(interface_id, timeout_a, timeout_b, delay) #define thread_extension_bbr_address_set(interface_id, addr_ptr, port) (-1) #define thread_extension_bbr_route_update(cur) +#define thread_extension_bbr_sequence_number_set(interface_id, seq_number) (-1) #define thread_extension_bbr_prefix_set(interface_id, prefix) 0 +#define thread_extension_bbr_old_partition_data_clean(interface_id) #endif #ifdef __cplusplus diff --git a/source/6LoWPAN/Thread/thread_extension_bootstrap.h b/source/6LoWPAN/Thread/thread_extension_bootstrap.h index e83b3d359cd..e6132ccdd99 100644 --- a/source/6LoWPAN/Thread/thread_extension_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_extension_bootstrap.h @@ -45,6 +45,8 @@ extern "C" { #define thread_extension_bootstrap_thread_name_length_get(cur) (0) #define thread_extension_bootstrap_thread_name_ptr_get(cur) (NULL) #define thread_extension_bootstrap_network_certificate_enable(cur, coap_service_id) (NULL) +#define thread_extension_bootstrap_reenrollment_start(cur, service_id, pbbr_addr) (-1) +#define thread_extension_bootstrap_network_reattach(interface_id, timeout) (-1) #ifdef __cplusplus } diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.c b/source/6LoWPAN/Thread/thread_host_bootstrap.c index 50366616120..a6cb6b5dbf4 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.c @@ -121,11 +121,11 @@ static void thread_network_data_clean(protocol_interface_info_entry_t *cur) static void thread_merge_prepare(protocol_interface_info_entry_t *cur) { + thread_partition_data_purge(cur); thread_clean_old_16_bit_address_based_addresses(cur); mpl_clear_realm_scope_seeds(cur); ipv6_route_table_remove_info(cur->id, ROUTE_THREAD_PROXIED_HOST, NULL); ipv6_route_table_remove_info(cur->id, ROUTE_THREAD_PROXIED_DUA_HOST, NULL); - thread_partition_data_purge(cur); thread_network_data_clean(cur); cur->nwk_mode = ARM_NWK_GP_IP_MODE; } @@ -305,6 +305,7 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent uint16_t address16; uint32_t llFrameCounter; thread_leader_data_t leaderData; + mle_tlv_info_t addressRegisteredTlv; mac_neighbor_table_entry_t *entry_temp; bool new_entry_created; @@ -320,6 +321,7 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent // Address // MLE_TYPE_SRC_ADDRESS // MLE_TYPE_LEADER_DATA + // MLE_TYPE_ADDRESS_REGISTRATION if (!mle_tlv_read_8_bit_tlv(MLE_TYPE_MODE, ptr, data_length, &mode) || !mle_tlv_read_16_bit_tlv(MLE_TYPE_SRC_ADDRESS, ptr, data_length, &srcAddress) || !mle_tlv_read_16_bit_tlv(MLE_TYPE_ADDRESS16, ptr, data_length, &address16) || @@ -329,6 +331,25 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent return -1; } + if (!(mode & THREAD_DEVICE_FED)) { + // check for presence of Address registration TLV for MTDs + if (!mle_tlv_read_tlv(MLE_TYPE_ADDRESS_REGISTRATION, ptr, data_length, &addressRegisteredTlv) || + (addressRegisteredTlv.tlvLen == 0)) { + tr_debug("MTD missed address registration TLV - reattach"); + return -1; + } + } + + // check if the source address is a router address + if (!thread_is_router_addr(srcAddress)) { + return -1; + } + + // check if the address16 is a valid child address + if (!thread_addr_is_child(srcAddress, address16)) { + return -1; + } + if (securityHeader->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) { thread_management_key_synch_req(cur->id, common_read_32_bit(securityHeader->Keysource)); // if learning key sequence from link sync actual guard timer value is not known @@ -1103,7 +1124,7 @@ static int thread_attach_child_id_request_build(protocol_interface_info_entry_t //Add ML-EID if ((mode & MLE_FFD_DEV) == 0) { - ptr = thread_address_registration_tlv_write(ptr, cur); + ptr = thread_ml_address_tlv_write(ptr,cur); } reqTlvCnt = 2; diff --git a/source/6LoWPAN/Thread/thread_joiner_application.c b/source/6LoWPAN/Thread/thread_joiner_application.c index 5bc1b784936..65ecc0af52c 100644 --- a/source/6LoWPAN/Thread/thread_joiner_application.c +++ b/source/6LoWPAN/Thread/thread_joiner_application.c @@ -54,6 +54,7 @@ #include "thread_management_if.h" #include "thread_common.h" #include "thread_bootstrap.h" +#include "thread_router_bootstrap.h" #include "thread_network_synch.h" #include "thread_network_data_lib.h" #include "thread_joiner_application.h" @@ -1140,7 +1141,7 @@ void thread_joiner_pending_config_activate(int8_t interface_id) this->active_configuration_ptr->timestamp = pending_active_timestamp; // All information is copied from old configuration so if configuration is corrupt we dont change anything. this->pending_configuration_ptr = NULL; - (void)thread_nvm_store_pending_configuration_remove(); + thread_nvm_store_pending_configuration_remove(); configuration_set_copy_mandatory(this->active_configuration_ptr, this->old_active_configuration_ptr); link_configuration_update(this->configuration_ptr,this->active_configuration_ptr->data, this->active_configuration_ptr->length); link_configuration_trace(this->configuration_ptr); @@ -1922,6 +1923,8 @@ int thread_joiner_application_update_configuration(uint8_t interface_id, uint8_t } thread_meshcop_tlv_data_get_uint64(msg_ptr, msg_len, MESHCOP_TLV_ACTIVE_TIME_STAMP, &this->active_configuration_ptr->timestamp); link_configuration_update(this->configuration_ptr,msg_ptr,msg_len); + // allow 5 seconds delay before state change for data response propagation + thread_router_bootstrap_delay_reed_jitter(interface_id, 5); ns_dyn_mem_free(configuration_ptr); thread_joiner_application_configuration_nvm_save(interface_id); diff --git a/source/6LoWPAN/Thread/thread_leader_service.c b/source/6LoWPAN/Thread/thread_leader_service.c index d2be5fd3ebf..a244c9cedcf 100644 --- a/source/6LoWPAN/Thread/thread_leader_service.c +++ b/source/6LoWPAN/Thread/thread_leader_service.c @@ -41,7 +41,7 @@ #include "6LoWPAN/Thread/thread_config.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_bootstrap.h" -#include "6LoWPAN/Thread/thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/Thread/thread_discovery.h" #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_network_data_lib.h" @@ -305,7 +305,6 @@ static int thread_leader_service_commissioner_register(int8_t interface_id, uint protocol_interface_info_entry_t *cur; link_configuration_s *linkConfiguration; - tr_debug("Register interface %d commissioner: %s", interface_id, trace_ipv6(border_router_address)); linkConfiguration = thread_joiner_application_get_config(interface_id); if (!linkConfiguration) { @@ -341,6 +340,13 @@ static int thread_leader_service_commissioner_register(int8_t interface_id, uint *session_id = cur->thread_info->registered_commissioner.session_id; } + if (memcmp(border_router_address, linkConfiguration->mesh_local_ula_prefix, 8) == 0 && + memcmp(border_router_address + 8, ADDR_SHORT_ADR_SUFFIC, 6) == 0 && + border_router_address[14] == 0xfc) { + // source address is ALOC + common_write_16_bit(cur->thread_info->routerShortAddress, &border_router_address[14]); + } + tr_debug("Register interface %d commissioner: %s", interface_id, trace_ipv6(border_router_address)); //SET Border Router Locator memcpy(cur->thread_info->registered_commissioner.border_router_address, border_router_address, 16); cur->thread_info->registered_commissioner.commissioner_valid = true; @@ -1295,7 +1301,7 @@ static int thread_leader_service_leader_init(protocol_interface_info_entry_t *cu thread_routing_free(&thread_info->routing); ipv6_route_table_remove_info(cur->id, ROUTE_THREAD, NULL); ipv6_route_table_remove_info(cur->id, ROUTE_THREAD_BORDER_ROUTER, NULL); - thread_dhcp_client_delete(cur->id); + dhcp_client_delete(cur->id); thread_nd_service_delete(cur->id); mpl_clear_realm_scope_seeds(cur); ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache); @@ -1352,7 +1358,6 @@ static void thread_leader_service_interface_setup_activate(protocol_interface_in cur->lowpan_address_mode = NET_6LOWPAN_GP16_ADDRESS; thread_bootstrap_update_ml16_address(cur, cur->thread_info->routerShortAddress); thread_generate_ml64_address(cur); - thread_extension_address_generate(cur); thread_bootstrap_routing_activate(cur); thread_routing_update_id_set(cur, private->maskSeq, private->master_router_id_mask); thread_routing_activate(&cur->thread_info->routing); diff --git a/source/6LoWPAN/Thread/thread_management_api.c b/source/6LoWPAN/Thread/thread_management_api.c index ff364157b10..ac16c1f6066 100644 --- a/source/6LoWPAN/Thread/thread_management_api.c +++ b/source/6LoWPAN/Thread/thread_management_api.c @@ -287,7 +287,6 @@ int thread_management_register(int8_t interface_id) this->get_response_cb_ptr = NULL; if (thread_management_get_remote_addr(this)) { - ns_dyn_mem_free(this); return -1; } diff --git a/source/6LoWPAN/Thread/thread_management_client.c b/source/6LoWPAN/Thread/thread_management_client.c index 0ccae5a3ac3..a5d1646b3a0 100644 --- a/source/6LoWPAN/Thread/thread_management_client.c +++ b/source/6LoWPAN/Thread/thread_management_client.c @@ -45,6 +45,7 @@ #include "6LoWPAN/Thread/thread_constants.h" #include "6LoWPAN/Thread/thread_tmfcop_lib.h" #include "6LoWPAN/Thread/thread_management_internal.h" +#include "6LoWPAN/Thread/thread_management_server.h" #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_network_data_lib.h" #include "6LoWPAN/Thread/thread_bootstrap.h" @@ -58,9 +59,8 @@ typedef struct thread_management { thread_management_client_router_id_cb *router_id_release_cb_ptr; thread_management_client_network_data_set_cb *network_data_set_cb_ptr; thread_management_client_network_data_set_cb *neighbor_discovery_cb_ptr; - uint16_t coap_asd_msg_id; // COAP msg id for a/sd int8_t interface_id; - int8_t coap_service_id; + int8_t coap_service_id; // COAP service ID from Management server ns_list_link_t link; } thread_management_t; @@ -150,9 +150,12 @@ void thread_management_client_init(int8_t interface_id) this->neighbor_discovery_cb_ptr = NULL; this->router_id_cb_ptr = NULL; this->interface_id = interface_id; - this->coap_asd_msg_id = 0; //TODO: Check if to use ephemeral port here - this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); + + this->coap_service_id = thread_management_server_service_id_get(interface_id); + if (this->coap_service_id < 0) { + tr_error("Failed to init COAP service"); + } ns_list_add_to_start(&instance_list, this); } return; @@ -165,19 +168,10 @@ void thread_management_client_delete(int8_t interface_id) return; } - coap_service_delete(this->coap_service_id); ns_list_remove(&instance_list, this); ns_dyn_mem_free(this); return; } -int8_t thread_management_client_service_id_get(int8_t interface_id) -{ - thread_management_t *this = thread_management_find(interface_id); - if (!this) { - return -1; - } - return this->coap_service_id; -} int thread_management_client_router_id_get(int8_t interface_id, uint8_t mac[8], uint16_t router_id, thread_management_client_router_id_cb *id_cb, uint8_t status) { @@ -251,8 +245,6 @@ static int thread_management_client_register_cb(int8_t service_id, uint8_t sourc return -1; } - this->coap_asd_msg_id = 0; //clear the coap message id - if (this->network_data_set_cb_ptr) { if (response_ptr) { // If we get response status is OK @@ -281,10 +273,8 @@ int thread_management_client_network_data_register(int8_t interface_id, uint8_t this->network_data_set_cb_ptr = set_cb; tr_debug("thread network data send to %s", trace_ipv6(destination)); - this->coap_asd_msg_id = coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT, - COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, data_ptr, data_len, thread_management_client_register_cb); - - return 0; + return coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, data_ptr, data_len, thread_management_client_register_cb); } int thread_management_client_network_data_unregister(int8_t interface_id, uint16_t rloc16) @@ -306,8 +296,8 @@ int thread_management_client_network_data_unregister(int8_t interface_id, uint16 tr_debug("thread network data unregister"); - this->coap_asd_msg_id = coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT, - COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, payload, ptr - payload, thread_management_client_register_cb); + coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, destination, THREAD_MANAGEMENT_PORT, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_NETWORK_DATA, COAP_CT_OCTET_STREAM, payload, ptr - payload, thread_management_client_register_cb); return 0; } @@ -616,26 +606,29 @@ void thread_management_client_proactive_an(int8_t interface_id, const uint8_t ad payload, ptr - payload, thread_management_client_proactive_an_cb); } -void thread_management_client_pending_coap_request_kill(int8_t interface_id) +void thread_management_client_coap_message_delete(int8_t interface_id, uint16_t coap_message_id) { thread_management_t *this = thread_management_find(interface_id); - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!this || !cur) { + if (!this) { return; } - cur->thread_info->localServerDataBase.publish_active = false; + coap_service_request_delete(this->coap_service_id, coap_message_id); +} - if (this->coap_asd_msg_id != 0) { - coap_service_request_delete(this->coap_service_id, this->coap_asd_msg_id); - this->coap_asd_msg_id = 0; - } +void thread_management_client_old_partition_data_clean(int8_t interface_id) +{ + thread_management_t *this = thread_management_find(interface_id); + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (cur->thread_info->routerIdReqCoapID != 0) { - coap_service_request_delete(this->coap_service_id, cur->thread_info->routerIdReqCoapID); - cur->thread_info->routerIdReqCoapID = 0; + if (!this || !cur) { + return; } + + cur->thread_info->localServerDataBase.publish_coap_req_id = 0; + cur->thread_info->routerIdRequested = false; + coap_service_request_delete_by_service_id(this->coap_service_id); } #endif diff --git a/source/6LoWPAN/Thread/thread_management_client.h b/source/6LoWPAN/Thread/thread_management_client.h index 583b6fcec46..f2691278ab3 100644 --- a/source/6LoWPAN/Thread/thread_management_client.h +++ b/source/6LoWPAN/Thread/thread_management_client.h @@ -65,12 +65,6 @@ void thread_management_client_init(int8_t interface_id); */ void thread_management_client_delete(int8_t interface_id); -/** Get service id of management service. - * - * When using Coap Management port service this service is the only instance used to make client transactions. - */ -int8_t thread_management_client_service_id_get(int8_t interface_id); - /** Router id handler callback. * * callback to inform when new router id is received from leader. @@ -213,9 +207,20 @@ int thread_management_client_provision_request(int8_t interface_id, uint8_t *dst */ void thread_management_client_proactive_an(int8_t interface_id, const uint8_t address[16], const uint16_t rloc, const uint8_t ml_eid[8], const uint8_t dst_addr[16]); -/** Kill pending COAP requests. +/** Delete COAP message . + * + * Delete COAP message that is sent to COAP service. + * + * \param interface_id interface id of this Thread instance. + * \param coap_message_id COAP message to be deleted. + */ +void thread_management_client_coap_message_delete(int8_t interface_id, uint16_t coap_message_id); + +/** Clear old partition data. + * + * Clear data related to old partition, like pending COAP transactions. * * \param interface_id interface id of this Thread instance. */ -void thread_management_client_pending_coap_request_kill(int8_t interface_id); +void thread_management_client_old_partition_data_clean(int8_t interface_id); #endif /* THREAD_MANAGEMENT_CLIENT_H_ */ diff --git a/source/6LoWPAN/Thread/thread_management_if.c b/source/6LoWPAN/Thread/thread_management_if.c index 767bb355389..e22f94c9985 100644 --- a/source/6LoWPAN/Thread/thread_management_if.c +++ b/source/6LoWPAN/Thread/thread_management_if.c @@ -50,7 +50,7 @@ #include "6LoWPAN/Thread/thread_leader_service.h" #include "6LoWPAN/Thread/thread_nd.h" #include "thread_diagnostic.h" -#include "6LoWPAN/Thread/thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/Thread/thread_discovery.h" #include "6LoWPAN/Thread/thread_network_synch.h" #include "6LoWPAN/Thread/thread_management_internal.h" @@ -63,6 +63,7 @@ #include "6LoWPAN/Thread/thread_constants.h" #include "6LoWPAN/Thread/thread_extension_bootstrap.h" #include "6LoWPAN/Thread/thread_extension.h" +#include "6LoWPAN/Thread/thread_bbr_api_internal.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "RPL/rpl_control.h" // insanity - bootstraps shouldn't be doing each others' clean-up #include "MLE/mle.h" @@ -71,9 +72,8 @@ #include "thread_commissioning_if.h" #include "shalib.h" #include "Common_Protocols/icmpv6.h" -#include "libDHCPv6/libDHCPv6.h" -#include "libDHCPv6/libDHCPv6_server.h" #include "DHCPv6_Server/DHCPv6_server_service.h" +#include "6LoWPAN/Thread/thread_dhcpv6_server.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "Service_Libs/blacklist/blacklist.h" #include "6LoWPAN/MAC/mac_helper.h" @@ -606,7 +606,7 @@ int thread_management_get_ml_prefix_112(int8_t interface_id, uint8_t *prefix_ptr */ int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t max_client_cnt, bool stableData) { -#ifdef HAVE_DHCPV6_SERVER +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) protocol_interface_info_entry_t *cur; thread_prefix_tlv_t prefixTlv; thread_border_router_tlv_entry_t service; @@ -622,7 +622,7 @@ int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t return -1; } - if (DHCPv6_server_service_init(interface_id, prefix_ptr, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE) != 0) { + if (thread_dhcp6_server_init(interface_id, prefix_ptr, cur->mac, THREAD_MIN_PREFIX_LIFETIME) != 0) { tr_warn("SerVER alloc fail"); return -1; } @@ -637,14 +637,9 @@ int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t service.P_on_mesh = true; service.stableData = stableData; - //SET Timeout - DHCPv6_server_service_set_address_validlifetime(interface_id, prefix_ptr, THREAD_MIN_PREFIX_LIFETIME); - // SET maximum number of accepted clients DHCPv6_server_service_set_max_clients_accepts_count(interface_id, prefix_ptr, max_client_cnt); - //Enable Mapping - //DHCPv6_server_service_set_gua_address_mapping(interface_id,prefix_ptr, true, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix); tr_debug("GUA server Generate OK"); memcpy(ptr, prefix_ptr, 8); memset(ptr + 8, 0, 8); @@ -665,7 +660,7 @@ int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t int thread_dhcpv6_server_set_lifetime(int8_t interface_id, uint8_t *prefix_ptr, uint32_t valid_lifetime) { -#ifdef HAVE_DHCPV6_SERVER +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } @@ -681,7 +676,7 @@ int thread_dhcpv6_server_set_lifetime(int8_t interface_id, uint8_t *prefix_ptr, int thread_dhcpv6_server_set_max_client(int8_t interface_id, uint8_t *prefix_ptr, uint32_t max_client_count) { -#ifdef HAVE_DHCPV6_SERVER +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } @@ -697,7 +692,7 @@ int thread_dhcpv6_server_set_max_client(int8_t interface_id, uint8_t *prefix_ptr int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t *prefix_ptr, bool anonymous) { -#ifdef HAVE_DHCPV6_SERVER +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } @@ -715,7 +710,7 @@ int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t * int thread_dhcpv6_server_delete(int8_t interface_id, uint8_t *prefix_ptr) { -#ifdef HAVE_DHCPV6_SERVER +#if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) uint8_t temp[16]; protocol_interface_info_entry_t *cur; thread_prefix_tlv_t prefixTlv; diff --git a/source/6LoWPAN/Thread/thread_management_server.c b/source/6LoWPAN/Thread/thread_management_server.c index 8a4ae139fd6..8f0bc4a59d5 100644 --- a/source/6LoWPAN/Thread/thread_management_server.c +++ b/source/6LoWPAN/Thread/thread_management_server.c @@ -100,6 +100,9 @@ typedef struct announce { typedef struct thread_management_server { scan_query_t *scan_ptr; announce_t *announce_ptr; + timeout_t *join_ent_timer; + uint8_t destination_address[16]; + uint8_t one_time_key[16]; uint16_t relay_port_joiner; uint16_t external_commissioner_port; int8_t interface_id; @@ -994,7 +997,6 @@ static int thread_management_server_energy_scan_cb(int8_t service_id, uint8_t so return -1; } - static void thread_announce_timeout_cb(void* arg) { link_configuration_s *linkConfiguration; @@ -1132,6 +1134,9 @@ int thread_management_server_init(int8_t interface_id) this->relay_port_joiner = 0; this->scan_ptr = NULL; this->announce_ptr = NULL; + this->join_ent_timer = NULL; + memset(this->destination_address,0,16); + memset(this->one_time_key,0,16); this->external_commissioner_port = THREAD_COMMISSIONING_PORT; #ifdef HAVE_THREAD_ROUTER @@ -1147,13 +1152,13 @@ int thread_management_server_init(int8_t interface_id) #endif this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); if (this->coap_service_id < 0) { - tr_warn("Thread management init failed"); + tr_error("Thread management init failed"); ns_dyn_mem_free(this); return -3; } #ifdef HAVE_THREAD_ROUTER if (thread_leader_service_init(interface_id, this->coap_service_id) != 0) { - tr_warn("Thread leader service init failed"); + tr_error("Thread leader service init failed"); ns_dyn_mem_free(this); return -3; } @@ -1191,6 +1196,7 @@ void thread_management_server_delete(int8_t interface_id) coap_service_unregister_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_GET); coap_service_unregister_uri(this->coap_service_id, THREAD_URI_MANAGEMENT_SET); coap_service_delete(this->coap_service_id); + ns_list_remove(&instance_list, this); if (this->announce_ptr) { if (this->announce_ptr->timer) { @@ -1215,6 +1221,15 @@ void thread_management_server_delete(int8_t interface_id) return; } +int8_t thread_management_server_service_id_get(int8_t interface_id) +{ + thread_management_server_t *this = thread_management_server_find(interface_id); + if (!this) { + return -1; + } + return this->coap_service_id; +} + int8_t thread_management_server_interface_id_get(int8_t coap_service_id) { thread_management_server_t *this = thread_management_find_by_service(coap_service_id); @@ -1312,6 +1327,19 @@ static int thread_management_server_entrust_send(thread_management_server_t *thi ns_dyn_mem_free(response_ptr); return 0; } + +static void thread_join_ent_timeout_cb(void *arg) +{ + thread_management_server_t *this = arg; + if(!this || !this->join_ent_timer) { + return; + } + + this->join_ent_timer = NULL; + thread_management_server_entrust_send(this, this->destination_address, this->one_time_key); + return; +} + void joiner_router_recv_commission_msg(void *cb_res) { socket_callback_t *sckt_data = 0; @@ -1412,7 +1440,13 @@ static int thread_management_server_relay_tx_cb(int8_t service_id, uint8_t sourc if (0 < thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_JOINER_ROUTER_KEK, &kek_ptr)) { // KEK present in relay set pairwise key and send entrust tr_debug("Kek received"); - thread_management_server_entrust_send(this, destination_address.address, kek_ptr); + if (this->join_ent_timer) { + eventOS_timeout_cancel(this->join_ent_timer); + thread_management_server_entrust_send(this, this->destination_address, this->one_time_key); + } + memcpy(this->destination_address, destination_address.address, 16); + memcpy(this->one_time_key, kek_ptr, 16); + this->join_ent_timer = eventOS_timeout_ms(thread_join_ent_timeout_cb, THREAD_DELAY_JOIN_ENT, this); } tr_debug("Relay TX sendto addr:%s port:%d, length:%d", trace_ipv6(destination_address.address), port, udp_data_len); thci_trace("joinerrouterJoinerDataRelayedOutbound"); diff --git a/source/6LoWPAN/Thread/thread_management_server.h b/source/6LoWPAN/Thread/thread_management_server.h index 88be72814a0..b7ca9fb5c1b 100644 --- a/source/6LoWPAN/Thread/thread_management_server.h +++ b/source/6LoWPAN/Thread/thread_management_server.h @@ -99,6 +99,13 @@ int thread_management_server_joiner_router_init(int8_t interface_id); * */ void thread_management_server_joiner_router_deinit(int8_t interface_id); + +/** Get service id of management service. + * + * When using Coap Management port service this service is the only instance used to make client transactions. + */ +int8_t thread_management_server_service_id_get(int8_t interface_id); + int8_t thread_management_server_interface_id_get(int8_t coap_service_id); int thread_management_server_commisoner_data_get(int8_t interface_id, thread_management_server_data_t *server_data); diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index 2c108ee6e88..4ff0a64038d 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -30,6 +30,7 @@ #ifdef HAVE_THREAD #include "ns_trace.h" +#include "string.h" #include "common_functions.h" #include "NWK_INTERFACE/Include/protocol.h" #include @@ -53,6 +54,7 @@ #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/MAC/mac_data_poll.h" +#include "Common_Protocols/ipv6.h" #include "MLE/mle.h" #include "mac_api.h" #define TRACE_GROUP "thmh" @@ -699,6 +701,54 @@ static int thread_host_child_update_response_send(protocol_interface_info_entry_ return 0; } +static bool thread_address_registration_tlv_search(if_address_entry_t *entry, mle_tlv_info_t *tlv_info) +{ + uint8_t context; + uint16_t length = tlv_info->tlvLen; + uint8_t *ptr = tlv_info->dataPtr; + + while (length) { + context = *ptr++; + if (context & 0x80) { + if (memcmp(ptr, entry->address + 8, 8) == 0) { + return true; + } + ptr += 8; + length -= 9; + } else { + if (memcmp(ptr, entry->address, 16) == 0) { + return true; + } + ptr += 16; + length -= 17; + } + } + + return false; + +} + +static bool thread_address_registration_tlv_check(protocol_interface_info_entry_t *cur, mle_tlv_info_t *tlv_info) +{ + bool ret_val = true; + + ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) { + if (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_GLOBAL || (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_REALM_LOCAL && + !thread_addr_is_mesh_local_16(e->address, cur))) { + + if (thread_address_registration_tlv_search(e, tlv_info) == false) { + tr_debug("Address %s registration to parent failed", trace_ipv6(e->address)); + addr_set_preferred_lifetime(cur, e, 0); // deprecate address + ret_val = false; + } else if (e->preferred_lifetime == 0) { + addr_set_preferred_lifetime(cur, e, 0xffffffff); // set preferred lifetime to infinite + } + } + } + + return ret_val; +} + static void thread_host_child_update_request_process(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, uint8_t linkMargin) { thread_leader_data_t leaderData; @@ -710,6 +760,7 @@ static void thread_host_child_update_request_process(protocol_interface_info_ent uint64_t pending_timestamp = 0;// means no pending timestamp mac_neighbor_table_entry_t *entry_temp; bool data_request_needed = false; + mle_tlv_info_t tlv_info = {0}; tr_debug("Child update request"); entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); @@ -738,6 +789,11 @@ static void thread_host_child_update_request_process(protocol_interface_info_ent thread_bootstrap_network_data_update(cur); } + // Check Address Registration TLV + if (true == mle_tlv_read_tlv(MLE_TYPE_ADDRESS_REGISTRATION, mle_msg->data_ptr, mle_msg->data_length, &tlv_info)) { + thread_address_registration_tlv_check(cur, &tlv_info); + } + if (thread_info(cur)->thread_leader_data->stableDataVersion != leaderData.stableDataVersion || thread_info(cur)->thread_leader_data->dataVersion != leaderData.dataVersion) { // version numbers not in sync need to send data request @@ -776,6 +832,7 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * thread_leader_data_t leaderData = {0}; uint8_t status; bool leader_data_received; + mle_tlv_info_t tlv_info = {0}; if (cur->thread_info->thread_endnode_parent == NULL) { return; @@ -822,6 +879,10 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * tr_debug("Setting child timeout, value=%"PRIu32, timeout); } + if (true == mle_tlv_read_tlv(MLE_TYPE_ADDRESS_REGISTRATION, mle_msg->data_ptr, mle_msg->data_length, &tlv_info)) { + thread_address_registration_tlv_check(cur, &tlv_info); + } + tr_debug("Keep-Alive -->Respond from Parent"); mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), entry_temp, timeout); diff --git a/source/6LoWPAN/Thread/thread_nd.c b/source/6LoWPAN/Thread/thread_nd.c index 717e757bffd..85020a37705 100644 --- a/source/6LoWPAN/Thread/thread_nd.c +++ b/source/6LoWPAN/Thread/thread_nd.c @@ -294,7 +294,7 @@ static void thread_nd_address_error(int8_t interface_id, const uint8_t ip_addr[1 if_address_entry_t *addr_entry = addr_get_entry(cur, ip_addr); if (addr_entry && memcmp(ml_eid, cur->iid_slaac, 8)) { addr_duplicate_detected(cur, ip_addr); - thread_extension_address_generate(cur); + thread_extension_dua_address_generate(cur, ip_addr, 64); } /* Scan IPv6 neighbour cache for registered entries of children */ @@ -547,8 +547,7 @@ int thread_nd_address_registration(protocol_interface_info_entry_t *cur, const u } uint8_t *nce_eui64 = ipv6_neighbour_eui64(&cur->ipv6_neighbour_cache, neigh); - if (neigh->state != IP_NEIGHBOUR_NEW && memcmp(nce_eui64, mac64, 8) != 0) - { + if (neigh->type == IP_NEIGHBOUR_REGISTERED && memcmp(nce_eui64, mac64, 8) != 0) { return -2; } diff --git a/source/6LoWPAN/Thread/thread_network_data_storage.c b/source/6LoWPAN/Thread/thread_network_data_storage.c index 0947cf4564b..e5ef23aa26b 100755 --- a/source/6LoWPAN/Thread/thread_network_data_storage.c +++ b/source/6LoWPAN/Thread/thread_network_data_storage.c @@ -48,7 +48,7 @@ #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_network_data_lib.h" #include "6LoWPAN/Thread/thread_network_data_storage.h" -#include "6LoWPAN/Thread/thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/MAC/mac_helper.h" #include "thread_management_if.h" #include "thread_meshcop_lib.h" @@ -193,6 +193,7 @@ static uint16_t thread_nd_service_border_router_flags_read(thread_network_server flags |= (cur->P_default_route << THREAD_P_DEF_ROUTE_BIT_MOVE); flags |= (cur->P_on_mesh << THREAD_P_ON_MESH_BIT_MOVE); flags |= (cur->P_nd_dns << THREAD_P_ND_DNS_BIT_MOVE); + flags |= (cur->P_res1 << THREAD_P_ND_RES_BIT_MOVE); return flags; } @@ -872,6 +873,7 @@ static int thread_service_data_delete_mark_by_router_id(thread_network_data_serv static int thread_server_context_clean(int8_t id, thread_network_data_cache_entry_t *cachePtr, thread_data_context_list_t *listPtr, thread_network_data_prefix_cache_entry_t *prefixEntry, lowpan_context_list_t *context_list) { + (void) id; int retVal = -1; (void) prefixEntry; ns_list_foreach_safe(thread_network_data_context_entry_t, cur, listPtr) { @@ -881,9 +883,7 @@ static int thread_server_context_clean(int8_t id, thread_network_data_cache_entr cachePtr->stableUpdatePushed = true; } // Set context lifetime to 0 to delete - if (thread_extension_context_can_delete(id, prefixEntry->servicesPrefix, cur->contextPrefixLength)) { - lowpan_context_update(context_list, cur->cid, 0, NULL, 0, true); - } + lowpan_context_update(context_list, cur->cid, 0, NULL, 0, true); ns_list_remove(listPtr, cur); ns_dyn_mem_free(cur); retVal = 0; @@ -930,11 +930,18 @@ static bool thread_server_data_clean_by_router_id(thread_network_data_cache_entr if (cur->P_dhcp) { tr_debug("Delete DHCPv6 given address"); - thread_dhcp_client_global_address_delete(curInterface->id, addr, prefixEntry->servicesPrefix); - } else { + dhcp_client_global_address_delete(curInterface->id, addr, prefixEntry->servicesPrefix); + } + + if (cur->P_slaac) { tr_debug("Delete SLAAC address"); addr_delete_matching(curInterface, prefixEntry->servicesPrefix, 64, ADDR_SOURCE_SLAAC); } + + if (cur->P_res1) { + tr_debug("Delete thread domain address"); + addr_delete_matching(curInterface, prefixEntry->servicesPrefix, 64, ADDR_SOURCE_THREAD_DOMAIN); + } } ns_list_remove(listPtr, cur); @@ -995,7 +1002,7 @@ void thread_network_local_server_data_base_init(thread_network_local_data_cache_ ns_list_init(&cachePtr->service_list); cachePtr->registered_rloc16 = 0xffff; cachePtr->release_old_address = false; - cachePtr->publish_active = false; + cachePtr->publish_coap_req_id = 0; cachePtr->publish_pending = false; } @@ -1077,6 +1084,7 @@ bool thread_network_data_router_id_free(thread_network_data_cache_entry_t *cache void thread_network_data_context_re_use_timer_update(int8_t id, thread_network_data_cache_entry_t *cachePtr, uint32_t ticks, lowpan_context_list_t *context_list) { + (void) id; ns_list_foreach_safe(thread_network_data_prefix_cache_entry_t, cur, &cachePtr->localPrefixList) { ns_list_foreach_safe(thread_network_data_context_entry_t, curContext, &cur->contextList) { if (!curContext->compression) { @@ -1090,9 +1098,7 @@ void thread_network_data_context_re_use_timer_update(int8_t id, thread_network_d cachePtr->temporaryUpdatePushed = true; } // Set context lifetime to 0 to delete - if (thread_extension_context_can_delete(id, cur->servicesPrefix,curContext->contextPrefixLength)) { - lowpan_context_update(context_list, curContext->cid, 0, NULL, 0, true); - } + lowpan_context_update(context_list, curContext->cid, 0, NULL, 0, true); ns_dyn_mem_free(curContext); } } @@ -1162,7 +1168,7 @@ void thread_network_local_data_free_and_clean(thread_network_local_data_cache_en } cachePtr->publish_pending = false; - cachePtr->publish_active = false; + cachePtr->publish_coap_req_id = 0; cachePtr->release_old_address = false; } @@ -1628,6 +1634,7 @@ int thread_nd_local_list_add_on_mesh_prefix(thread_network_data_cache_entry_t *n server_entry->P_nd_dns = service->P_nd_dns; trigDataPropagate = true; } + } if (trigDataPropagate) { @@ -1707,9 +1714,9 @@ int thread_nd_local_list_del_on_mesh_server(thread_network_data_cache_entry_t *n int thread_local_server_list_add_on_mesh_server(thread_network_local_data_cache_entry_t *networkDataList, thread_prefix_tlv_t *prefixTlv, thread_border_router_tlv_entry_t *service) { int retVal = -1; - tr_debug("Add prefix: %s prf:%d %s%s%s%s%s", trace_ipv6_prefix(prefixTlv->Prefix, prefixTlv->PrefixLen), service->Prf, + tr_debug("Add prefix: %s prf:%d %s%s%s%s%s%s", trace_ipv6_prefix(prefixTlv->Prefix, prefixTlv->PrefixLen), service->Prf, service->P_default_route?"Default Route ":"",service->P_dhcp?"DHCPv6 Server ":"", service->P_configure?"DHCPv6 Configuration ":"", - service->P_slaac?"SLAAC ":"",service->P_preferred?"Preferred ":""); + service->P_slaac?"SLAAC ":"",service->P_preferred?"Preferred ":"",service->P_res1?"P_res1 ":""); if (networkDataList) { thread_network_local_data_entry_t *prefix_entry = thread_local_prefix_entry_get(&networkDataList->prefix_list, prefixTlv); @@ -2341,7 +2348,9 @@ bool thread_nd_service_anycast_address_mapping_from_network_data(thread_network_ if (curService->S_id != S_id) { continue; } - ns_list_foreach(thread_network_data_service_server_entry_t, curServiceServer, &curService->server_list) { + /* any server will do - take first from the list */ + thread_network_data_service_server_entry_t *curServiceServer = ns_list_get_first(&curService->server_list); + if (curServiceServer) { *rlocAddress = curServiceServer->router_id; return true; } @@ -2352,7 +2361,7 @@ bool thread_nd_service_anycast_address_mapping_from_network_data(thread_network_ bool thread_nd_on_mesh_address_valid(thread_network_server_data_entry_t *curRoute) { bool onMeshActive = false; - if (curRoute->P_dhcp || curRoute->P_slaac || curRoute->P_preferred) { + if (curRoute->P_dhcp || curRoute->P_slaac || curRoute->P_preferred || curRoute->P_on_mesh) { onMeshActive = true; } diff --git a/source/6LoWPAN/Thread/thread_network_data_storage.h b/source/6LoWPAN/Thread/thread_network_data_storage.h index 10dbd298f16..b5924535a62 100644 --- a/source/6LoWPAN/Thread/thread_network_data_storage.h +++ b/source/6LoWPAN/Thread/thread_network_data_storage.h @@ -187,8 +187,8 @@ typedef struct thread_network_local_data_cache_entry_s { thread_network_data_prefix_list_t prefix_list; /*!< Local parsed or generated service list */ thread_network_data_service_list_t service_list; uint16_t registered_rloc16;/*!< Address used for latest registration */ + uint16_t publish_coap_req_id;/*!< Non-zero when publish is active */ bool release_old_address:1;/*!< true if network data can be released from old address */ - bool publish_active:1;/*!< true when publish is active */ bool publish_pending:1;/*!< true when publish attempt made during active publish */ } thread_network_local_data_cache_entry_t; @@ -344,7 +344,7 @@ uint8_t *thread_network_data_prefix_set_write(thread_network_data_cache_entry_t uint8_t *thread_network_data_service_set_write(thread_network_data_cache_entry_t *networkDataList, uint8_t *ptr); bool thread_network_data_service_hosted_by_this_router_id(thread_network_data_service_cache_entry_t *dataList, uint16_t router_id); uint16_t thread_network_data_service_child_id_from_networkdata_get(thread_network_data_cache_entry_t *networkDataList, uint16_t router_short_addr); - +thread_network_data_prefix_cache_entry_t *thread_prefix_entry_find(thread_network_prefix_list_t *list, thread_prefix_tlv_t *prefixTlv); uint8_t * thread_nd_own_service_list_data_write(thread_network_local_data_cache_entry_t *serverDataList, uint8_t *ptr, uint16_t routerID); uint16_t thread_nd_own_service_list_data_size(thread_network_local_data_cache_entry_t *serverDataList); diff --git a/source/6LoWPAN/Thread/thread_nvm_store.c b/source/6LoWPAN/Thread/thread_nvm_store.c index 0aa4657f687..18a1918b04b 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.c +++ b/source/6LoWPAN/Thread/thread_nvm_store.c @@ -292,7 +292,11 @@ int thread_nvm_store_active_configuration_remove(void) } char ac_data_path[ACTIVE_CONF_STRING_LEN]; thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE); - return remove(ac_data_path); + int status = remove(ac_data_path); + if (status != 0) { + return THREAD_NVM_FILE_REMOVE_ERROR; + } + return THREAD_NVM_FILE_SUCCESS; } int thread_nvm_store_pending_configuration_remove(void) @@ -302,7 +306,11 @@ int thread_nvm_store_pending_configuration_remove(void) } char ac_data_path[PENDING_CONF_STRING_LEN]; thread_nvm_store_create_path(ac_data_path, THREAD_NVM_PENDING_CONF_FILE); - return remove(ac_data_path); + int status = remove(ac_data_path); + if (status != 0) { + return THREAD_NVM_FILE_REMOVE_ERROR; + } + return THREAD_NVM_FILE_SUCCESS; } diff --git a/source/6LoWPAN/Thread/thread_resolution_client.c b/source/6LoWPAN/Thread/thread_resolution_client.c index 9ea5aeaa63c..58bb6cf3255 100644 --- a/source/6LoWPAN/Thread/thread_resolution_client.c +++ b/source/6LoWPAN/Thread/thread_resolution_client.c @@ -39,6 +39,7 @@ #include "coap_service_api.h" #include "thread_config.h" +#include "thread_management_server.h" #include "thread_resolution_client.h" #define TRACE_GROUP TRACE_GROUP_THREAD_RESOLUTION_CLIENT @@ -294,7 +295,7 @@ void thread_resolution_client_init(int8_t interface_id) this->error_cb_ptr = NULL; ns_list_init(&this->queries); //TODO: Check if to use ephemeral port here - this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); + this->coap_service_id = thread_management_server_service_id_get(interface_id); ns_list_add_to_start(&instance_list, this); coap_service_register_uri(this->coap_service_id, THREAD_URI_ADDRESS_NOTIFICATION, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_resolution_client_notification_post_cb); @@ -309,7 +310,7 @@ void thread_resolution_client_delete(int8_t interface_id) } coap_service_unregister_uri(this->coap_service_id, THREAD_URI_ADDRESS_NOTIFICATION); - coap_service_delete(this->coap_service_id); + coap_service_unregister_uri(this->coap_service_id, THREAD_URI_ADDRESS_ERROR); ns_list_foreach_safe(address_query_t, query, &this->queries) { ns_list_remove(&this->queries, query); ns_dyn_mem_free(query); @@ -465,6 +466,7 @@ void thread_resolution_client_timer(int8_t interface_id, uint16_t seconds) } } } - } + #endif // HAVE_THREAD_NEIGHBOR_DISCOVERY + diff --git a/source/6LoWPAN/Thread/thread_resolution_server.c b/source/6LoWPAN/Thread/thread_resolution_server.c index 362f96aa7cd..e20541eb2bf 100644 --- a/source/6LoWPAN/Thread/thread_resolution_server.c +++ b/source/6LoWPAN/Thread/thread_resolution_server.c @@ -47,6 +47,7 @@ #include "thread_config.h" #include "thread_tmfcop_lib.h" #include "thread_management_if.h" +#include "thread_management_server.h" #include "thread_commissioning_if.h" @@ -170,9 +171,9 @@ int thread_resolution_server_init(int8_t interface_id, thread_resolution_server_ } this->interface_id = interface_id; - this->coap_service_id = coap_service_initialize(this->interface_id, THREAD_MANAGEMENT_PORT, COAP_SERVICE_OPTIONS_NONE, NULL, NULL); + this->coap_service_id = thread_management_server_service_id_get(interface_id); if (this->coap_service_id < 0) { - tr_warn("Thread resolution init failed"); + tr_warn("Thread resolution srv init failed"); ns_dyn_mem_free(this); return -3; } @@ -193,7 +194,6 @@ void thread_resolution_server_delete(int8_t interface_id) coap_service_unregister_uri(this->coap_service_id, THREAD_URI_ADDRESS_QUERY_REQUEST); - coap_service_delete(this->coap_service_id); ns_list_remove(&instance_list, this); ns_dyn_mem_free(this); } diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.c b/source/6LoWPAN/Thread/thread_router_bootstrap.c index 0c00650f7fd..b16287a042a 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.c @@ -78,7 +78,7 @@ #include "Service_Libs/nd_proxy/nd_proxy.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "Service_Libs/blacklist/blacklist.h" -#include "thread_dhcpv6_client.h" +#include "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/MAC/mac_helper.h" #include "mac_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" @@ -1027,10 +1027,10 @@ static void thread_bootstrap_client_router_id_cb(int8_t interface_id, int8_t sta if (!cur) { return; } - if (!cur->thread_info->routerIdReqCoapID) { + if (!cur->thread_info->routerIdRequested) { return; } - cur->thread_info->routerIdReqCoapID = 0; + cur->thread_info->routerIdRequested = false; if (cur->thread_info->thread_device_mode != THREAD_DEVICE_MODE_ROUTER || cur->thread_info->leader_private_data ) { @@ -1088,15 +1088,15 @@ void thread_router_bootstrap_router_id_request(protocol_interface_info_entry_t * { int router_id_req_status; tr_debug("Router ID Request"); - if (cur->thread_info->routerIdReqCoapID) { + if (cur->thread_info->routerIdRequested) { tr_warn("Router ID already requested"); return; } router_id_req_status = thread_management_client_router_id_get(cur->id, cur->mac, cur->thread_info->routerShortAddress, thread_bootstrap_client_router_id_cb, status); - tr_debug("Coap address req, ID=%d", router_id_req_status); + tr_debug("RouterIDReq COAP ID=%d", router_id_req_status); if (router_id_req_status > 0) { - cur->thread_info->routerIdReqCoapID = (uint16_t)router_id_req_status; + cur->thread_info->routerIdRequested = true; } } @@ -1196,6 +1196,32 @@ static int mle_attach_child_id_response_build(protocol_interface_info_entry_t *c } + +int thread_router_bootstrap_child_max_timeout_get(protocol_interface_info_entry_t *cur, uint32_t *max_child_timeout) +{ + uint16_t router_address = thread_info(cur)->routerShortAddress; + uint32_t max_timeout = 0; + if (router_address >= 0xfffe) { + router_address = mac_helper_mac16_address_get(cur); + } + if (router_address & THREAD_CHILD_MASK) { + return -1; //I am child + } + if (router_address >= 0xfffe) { + return -1; + } + mac_neighbor_table_list_t *mac_table_list = &mac_neighbor_info(cur)->neighbour_list; + + ns_list_foreach(mac_neighbor_table_entry_t, cur_entry, mac_table_list) { + if (thread_router_addr_from_addr(cur_entry->mac16) == router_address && + !cur_entry->ffd_device && cur_entry->lifetime > max_timeout) { + max_timeout = cur_entry->lifetime; + } + } + *max_child_timeout = max_timeout; + return 0; +} + uint16_t thread_router_bootstrap_child_count_get(protocol_interface_info_entry_t *cur) { uint16_t child_count = 0; @@ -1277,7 +1303,7 @@ void thread_router_bootstrap_child_id_handler(protocol_interface_info_entry_t *c bool new_neigbour = false; if (cur->thread_info->thread_attached_state == THREAD_STATE_CONNECTED) { - if (!cur->thread_info->routerIdReqCoapID) { + if (!cur->thread_info->routerIdRequested) { tr_info("Upgrade REED to Router"); thread_router_bootstrap_router_id_request(cur, THREAD_COAP_STATUS_TLV_HAVE_CHILD_ID_REQUEST); } @@ -1366,7 +1392,7 @@ static void thread_address_registration_tlv_parse(uint8_t *ptr, uint16_t data_le uint8_t tempIPv6Address[16]; uint8_t ctxId; bool new_neighbour_created; - + thread_child_mcast_entries_remove(cur,mac64); while (data_length) { //Read ctxId = *ptr++; @@ -1389,8 +1415,8 @@ static void thread_address_registration_tlv_parse(uint8_t *ptr, uint16_t data_le tr_debug("Register %s", trace_ipv6(ptr)); if (addr_is_ipv6_multicast(ptr)) { - // Register multicast address (higher scope than link-local) - if (addr_ipv6_multicast_scope(ptr) > IPV6_SCOPE_LINK_LOCAL) { + // Register multicast address (link-local & higher) + if (addr_ipv6_multicast_scope(ptr) >= IPV6_SCOPE_LINK_LOCAL) { addr_add_group(cur, ptr); if (thread_child_mcast_entry_get(cur, ptr, mac64)) { tr_debug("Added sleepy multicast registration entry."); @@ -1665,6 +1691,11 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * } } + if (!(id_req->mode & MLE_FFD_DEV) && addressRegisteredTlv.tlvLen == 0) { + tr_debug("No address registration TLV in MTD child id request"); + thread_child_id_request_entry_remove(cur, id_req); + return; + } id_req->keyId = security_headers->KeyIndex; id_req->keySeq = common_read_32_bit(security_headers->Keysource); @@ -1991,10 +2022,22 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * if (!entry_temp || !mle_tlv_read_tlv(MLE_TYPE_TLV_REQUEST, mle_msg->data_ptr, mle_msg->data_length, &requestTlv)) { return; } + + uint8_t mode = mle_mode_write_from_mac_entry(entry_temp); + /* check if thread neighbor class is not initialized */ + if ((thread_neighbor_entry_linkmargin_get(&cur->thread_info->neighbor_class, entry_temp->index) == 0) && + (thread_neighbor_last_communication_time_get(&cur->thread_info->neighbor_class, entry_temp->index) == 0)) { + /* + * Thread neighbor class is not yet initialized and we receive data_request from such child. + * Always send full network data in this case + */ + mode |= MLE_THREAD_REQ_FULL_DATA_SET | MLE_THREAD_SECURED_DATA_REQUEST; + } else { + mode |= thread_neighbor_class_mode_write_from_entry(&cur->thread_info->neighbor_class, entry_temp->index); + } + thread_neighbor_class_update_link(&cur->thread_info->neighbor_class, entry_temp->index,linkMargin, false); thread_neighbor_last_communication_time_update(&cur->thread_info->neighbor_class, entry_temp->index); - uint8_t mode = mle_mode_write_from_mac_entry(entry_temp); - mode |= thread_neighbor_class_mode_write_from_entry(&cur->thread_info->neighbor_class, entry_temp->index); mle_build_and_send_data_response_msg(cur, mle_msg->packet_src_address, mle_msg->data_ptr, mle_msg->data_length, &requestTlv, mode); } break; @@ -2026,8 +2069,9 @@ static int8_t thread_router_bootstrap_synch_request_send(protocol_interface_info tr_debug("Buffer overflow at message write"); } - timeout.retrans_max = THREAD_REQUEST_MAX_RETRY_CNT; - timeout.timeout_init = 1; + // timeout set to two seconds, no retries + timeout.retrans_max = 1; + timeout.timeout_init = 2; timeout.timeout_max = 3; timeout.delay = MLE_NO_DELAY; @@ -2325,7 +2369,6 @@ static uint32_t thread_reed_timeout_calculate(thread_router_select_t *routerSele static int thread_reed_advertise (protocol_interface_info_entry_t *cur) { uint32_t keySequence; - tr_debug("MLE REED ADVERTISEMENT STARTED"); struct link_configuration *linkConfiguration; linkConfiguration = thread_joiner_application_get_config(cur->id); if (!linkConfiguration) { @@ -2336,11 +2379,17 @@ static int thread_reed_advertise (protocol_interface_info_entry_t *cur) return -1; } + // FED not allowed to send advertisements + if (thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_FULL_END_DEVICE) { + return -1; + } + uint16_t bufId = mle_service_msg_allocate(cur->id, 16, false, MLE_COMMAND_ADVERTISEMENT); if (bufId == 0) { return -1; } + tr_debug("MLE REED ADVERTISEMENT STARTED"); thread_management_get_current_keysequence(cur->id, &keySequence); mle_service_msg_update_security_params(bufId, 5, 2, keySequence); @@ -2734,4 +2783,18 @@ void thread_router_bootstrap_address_change_notify_send(protocol_interface_info_ thread_info(cur)->proactive_an_timer = THREAD_PROACTIVE_AN_SEND_DELAY; } +void thread_router_bootstrap_delay_reed_jitter(int8_t interface_id, uint16_t delay) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; + } + if (cur->thread_info->thread_device_mode != THREAD_DEVICE_MODE_ROUTER) { + return; + } + // delay reed jitter timer to allow for settings changes to distribute + thread_info(cur)->reedJitterTimer += delay; + return; +} + #endif /* HAVE_THREAD_ROUTER */ diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.h b/source/6LoWPAN/Thread/thread_router_bootstrap.h index 0143ce1e30c..6874a01b0bb 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.h @@ -52,6 +52,9 @@ int thread_router_bootstrap_mle_advertise(struct protocol_interface_info_entry * void thread_router_bootstrap_child_information_clear(protocol_interface_info_entry_t *cur); int thread_router_bootstrap_reset_child_info(protocol_interface_info_entry_t *cur, struct mac_neighbor_table_entry *child); uint16_t thread_router_bootstrap_child_count_get(protocol_interface_info_entry_t *cur); + +// max_child_timeout is longest MLE Timeout a router has registered for all of its active MTD children +int thread_router_bootstrap_child_max_timeout_get(protocol_interface_info_entry_t *cur, uint32_t *max_child_timeout); void thread_router_bootstrap_child_id_handler(struct protocol_interface_info_entry *cur); void thread_router_bootstrap_child_id_reject(struct protocol_interface_info_entry *cur); void thread_router_bootstrap_router_id_request(struct protocol_interface_info_entry *cur, uint8_t status); @@ -73,6 +76,7 @@ void thread_router_bootstrap_anycast_address_register(protocol_interface_info_en void thread_router_bootstrap_network_data_distribute(protocol_interface_info_entry_t *cur); bool thread_router_bootstrap_routing_allowed(struct protocol_interface_info_entry *cur); void thread_router_bootstrap_address_change_notify_send(protocol_interface_info_entry_t *cur); +void thread_router_bootstrap_delay_reed_jitter(int8_t interface_id, uint16_t delay); #else @@ -81,6 +85,7 @@ void thread_router_bootstrap_address_change_notify_send(protocol_interface_info_ #define thread_router_bootstrap_child_information_clear(cur) #define thread_router_bootstrap_child_count_get(cur) 0 +#define thread_router_bootstrap_child_max_timeout_get(cur, max_child_timeout) 0 #define thread_router_bootstrap_child_id_handler(cur) #define thread_router_bootstrap_child_id_reject(cur) #define thread_router_bootstrap_router_id_request(cur, status) @@ -104,7 +109,7 @@ void thread_router_bootstrap_address_change_notify_send(protocol_interface_info_ #define thread_router_bootstrap_routing_allowed(cur) false #define thread_router_bootstrap_address_change_notify_send(cur) #define thread_router_bootstrap_reed_merge_advertisement(cur) - +#define thread_router_bootstrap_delay_reed_jitter(interface_id, delay) #endif/*HAVE_THREAD_ROUTER*/ #endif /* THREAD_ROUTER_BOOTSTRAP_H_ */ diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 226ed6f9642..4392f993ac1 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -43,7 +43,6 @@ #ifdef HAVE_RPL #include "RPL/rpl_data.h" #endif -#include "6LoWPAN/ws/ws_common.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/ws/ws_common.h" @@ -72,7 +71,7 @@ typedef struct { bool fragmented_data:1; bool first_fragment:1; bool indirect_data:1; - bool indirect_data_cached:1; /* Data cached for delayed transmission as mac request is already active */ + bool indirect_data_cached:1; /*!< Data cached for delayed transmission as mac request is already active */ buffer_t *buf; uint8_t *fragmenter_buf; ns_list_link_t link; /*!< List link entry */ @@ -132,7 +131,7 @@ static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr); /* Fragmentation local functions */ static int8_t lowpan_message_fragmentation_init(buffer_t *buf, fragmenter_tx_entry_t *frag_entry, protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr); static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry_t *frag_entry, mcps_data_req_t *dataReq); -static void lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr); +static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr); static fragmenter_tx_entry_t* lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr); @@ -613,40 +612,35 @@ buffer_t * lowpan_adaptation_data_process_tx_preprocess(protocol_interface_info_ { mac_neighbor_table_entry_t *neigh_entry_ptr = NULL; + //Validate is link known and set indirect, datareq and security key id mode if (buf->dst_sa.addr_type == ADDR_NONE) { goto tx_error_handler; } - /* If MLE is enabled, we will talk if we have an MLE association */ - if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG ) { - neigh_entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa.address + 2, buf->dst_sa.addr_type); + if (addr_check_broadcast(buf->dst_sa.address, buf->dst_sa.addr_type) == eOK ) { + buf->dst_sa.addr_type = ADDR_802_15_4_SHORT; + buf->dst_sa.address[2] = 0xff; + buf->dst_sa.address[3] = 0xff; + buf->link_specific.ieee802_15_4.indirectTxProcess = false; + buf->link_specific.ieee802_15_4.requestAck = false; + } else { - } else if(buf->dst_sa.addr_type == ADDR_802_15_4_SHORT && (common_read_16_bit(buf->dst_sa.address + 2)) != 0xffff) { neigh_entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa.address + 2, buf->dst_sa.addr_type); - } - //Validate neighbour - if (!buf->options.ll_security_bypass_tx && neigh_entry_ptr) { + //Validate neighbour + if (!buf->options.ll_security_bypass_tx && neigh_entry_ptr) { - if (neigh_entry_ptr->connected_device || neigh_entry_ptr->trusted_device) { + if (neigh_entry_ptr->connected_device || neigh_entry_ptr->trusted_device) { - } else { - //tr_warn("Drop TX to unassociated %s", trace_sockaddr(&buf->dst_sa, true)); + } else { + //tr_warn("Drop TX to unassociated %s", trace_sockaddr(&buf->dst_sa, true)); + goto tx_error_handler; + } + } else if (ws_info(cur) && !neigh_entry_ptr) { + //Do not accept to send unknow device goto tx_error_handler; } - } - - //Check indirect - - - if (addr_check_broadcast(buf->dst_sa.address, buf->dst_sa.addr_type) == eOK) { - buf->dst_sa.addr_type = ADDR_802_15_4_SHORT; - buf->dst_sa.address[2] = 0xff; - buf->dst_sa.address[3] = 0xff; - buf->link_specific.ieee802_15_4.indirectTxProcess = false; - buf->link_specific.ieee802_15_4.requestAck = false; - } else { buf->link_specific.ieee802_15_4.requestAck = true; buf->link_specific.ieee802_15_4.indirectTxProcess = lowpan_adaptation_indirect_data_request(neigh_entry_ptr); } @@ -755,7 +749,7 @@ static bool lowpan_adaptation_indirect_cache_trigger(protocol_interface_info_ent ns_list_foreach(fragmenter_tx_entry_t, fragmenter_tx_entry, &interface_ptr->indirect_tx_queue) { if (fragmenter_tx_entry->indirect_data_cached) { if (addr_ipv6_equal(tx_ptr->buf->dst_sa.address, fragmenter_tx_entry->buf->dst_sa.address)) { - tr_debug_extra("pushing seq %d to addr %s", fragmenter_tx_entry->buf->seq, trace_ipv6(fragmenter_tx_entry->buf->dst_sa.address)); + tr_debug_extra("Pushing seq %d to addr %s", fragmenter_tx_entry->buf->seq, trace_ipv6(fragmenter_tx_entry->buf->dst_sa.address)); fragmenter_tx_entry->indirect_data_cached = false; lowpan_data_request_to_mac(cur, fragmenter_tx_entry->buf, fragmenter_tx_entry, interface_ptr); return true; @@ -805,7 +799,12 @@ static void lowpan_adaptation_make_room_for_small_packet(protocol_interface_info mac_neighbor_table_entry_t *tx_neighbour = mac_neighbor_table_address_discover(mac_neighbor_info(cur), tx_entry->buf->dst_sa.address + 2, tx_entry->buf->dst_sa.addr_type); if (tx_neighbour == neighbour_to_count && buffer_data_length(tx_entry->buf) <= interface_ptr->indirect_big_packet_threshold) { if (++count >= interface_ptr->max_indirect_small_packets_per_child) { - lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry); + tr_debug_extra("Purge seq: %d", tx_entry->buf->seq); + if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry) == false) { + /* entry could not be purged from mac, try next entry */ + tr_debug_extra("Purge failed, try next"); + count--; + } } } } @@ -822,8 +821,12 @@ static void lowpan_adaptation_make_room_for_big_packet(struct protocol_interface ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) { if (buffer_data_length(tx_entry->buf) > interface_ptr->indirect_big_packet_threshold) { if (++count >= interface_ptr->max_indirect_big_packets_total) { - tr_debug_extra("free seq: %d", tx_entry->buf->seq); - lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry); + tr_debug_extra("Purge seq: %d", tx_entry->buf->seq); + if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry) == false) { + tr_debug("Purge failed, try next entry"); + /* entry could not be purged from mac, try next entry */ + count--; + } } } } @@ -911,6 +914,8 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff if (indirect) { ns_dyn_mem_free(tx_ptr->fragmenter_buf); ns_dyn_mem_free(tx_ptr); + } else { + tx_ptr->buf = NULL; } goto tx_error_handler; } @@ -1281,29 +1286,44 @@ static bool lowpan_tx_buffer_address_compare(sockaddr_t *dst_sa, uint8_t *addres return true; } -static void lowpan_adaptation_purge_from_mac(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, uint8_t msduhandle) +static bool lowpan_adaptation_purge_from_mac(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, uint8_t msduhandle) { mcps_purge_t purge_req; purge_req.msduHandle = msduhandle; + bool mac_purge_success = false; if (interface_ptr->mpx_api) { - interface_ptr->mpx_api->mpx_data_purge(interface_ptr->mpx_api, &purge_req, interface_ptr->mpx_user_id); + if (interface_ptr->mpx_api->mpx_data_purge(interface_ptr->mpx_api, &purge_req, interface_ptr->mpx_user_id) == 0) { + mac_purge_success = true; + } } else { if (cur->mac_api->mcps_purge_req) { - cur->mac_api->mcps_purge_req(cur->mac_api, &purge_req); + if (cur->mac_api->mcps_purge_req(cur->mac_api, &purge_req) == 0) { + mac_purge_success = true; + } } } + + return mac_purge_success; } -static void lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr) +static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr) { - tr_debug("Purge from indirect handle %u", tx_ptr->buf->seq); - lowpan_adaptation_purge_from_mac(cur, interface_ptr, tx_ptr->buf->seq); + tr_debug("Purge from indirect handle %u, cached %d", tx_ptr->buf->seq, tx_ptr->indirect_data_cached); + if (tx_ptr->indirect_data_cached == false) { + if (lowpan_adaptation_purge_from_mac(cur, interface_ptr, tx_ptr->buf->seq) == false) { + // MAC purge failed + return false; + } + } + lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, SOCKET_TX_FAIL); + + return true; } void lowpan_adaptation_remove_free_indirect_table(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr) { - //Free firts by defined short address + //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); @@ -1323,7 +1343,6 @@ int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct pr //Check first indirect queue ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->indirect_tx_queue) { - 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); @@ -1331,7 +1350,6 @@ int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct pr } 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) diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 4cd3316e5a8..c967b1c86c5 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -35,6 +35,8 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur); +int ws_bootstrap_restart(int8_t interface_id); + /*State machine transactions*/ void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur); @@ -50,12 +52,27 @@ void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *c void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); -void ws_bootstrap_trigle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); +void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); + +void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); + +void ws_secondary_parent_update(protocol_interface_info_entry_t *interface); + +void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor); + +void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); + +void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local); + +void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix); #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) #define ws_bootstrap_state_machine(cur) +#define ws_bootstrap_restart(cur) +#define ws_primary_parent_update(interface, neighbor) +#define ws_secondary_parent_update(interface) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index dc02f6938a8..70d48cb40a6 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -20,11 +20,13 @@ #include "ns_types.h" +#include "ns_list.h" #include "fhss_api.h" #include "fhss_config.h" #include "net_fhss.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_neighbor_class.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" struct ws_pan_information_s; struct ws_neighbor_class_s; @@ -40,6 +42,17 @@ typedef struct parent_info_s { uint32_t timestamp; /**< Timestamp when packet was received */ }parent_info_t; +typedef struct ws_nud_table_entry { + void *neighbor_info; + uint16_t timer; /*!< Timer which resolution is 100ms*/ + unsigned retry_count:2; + bool wait_response:1; /*!< True when NS is sended and wait NA, False when random timer is active*/ + bool nud_process; + ns_list_link_t link; +} ws_nud_table_entry_t; + +typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t; + typedef struct ws_info_s { char network_name[33]; // Network name max 32 octets + terminating 0. uint16_t network_pan_id; @@ -54,8 +67,24 @@ typedef struct ws_info_s { uint32_t pan_version_timer; /**< border router version udate timeout */ uint32_t pan_version_timeout_timer; /**< routers will fallback to previous state after this */ uint8_t gtkhash[32]; + bool address_registration_event_active : 1; bool configuration_learned:1; - + bool trickle_pas_running:1; + bool trickle_pa_running:1; + bool trickle_pcs_running:1; + bool trickle_pc_running:1; + // default fhss parameters for this device + uint8_t fhss_uc_dwell_interval; + uint8_t fhss_bc_dwell_interval; + uint32_t fhss_bc_interval; + uint8_t fhss_uc_channel_function; + uint8_t fhss_bc_channel_function; + uint16_t fhss_uc_fixed_channel; + uint16_t fhss_bc_fixed_channel; + uint32_t fhss_channel_mask[8]; + ws_nud_table_entry_t nud_table_entrys[ACTIVE_NUD_PROCESS_MAX]; + ws_nud_table_list_t active_nud_process; + ws_nud_table_list_t free_nud_entries; struct ws_pan_information_s pan_information; ws_hopping_schedule_t hopping_schdule; struct ws_neighbor_class_s neighbor_storage; @@ -65,6 +94,8 @@ typedef struct ws_info_s { #ifdef HAVE_WS +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain); + int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur); int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur); diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 4b4c067f70f..ae6fb036146 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -73,12 +73,14 @@ typedef struct ws_hopping_schedule_s { uint8_t operating_class; /**< PHY operating class default to 1 */ uint8_t operating_mode; /**< PHY operating mode default to "1b" symbol rate 50, modulation index 1 */ uint8_t channel_plan; /**< 0: use regulatory domain values 1: application defined plan */ - uint8_t channel_function; /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */ + uint8_t uc_channel_function; /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */ + uint8_t bc_channel_function; /**< 0: Fixed channel, 1:TR51CF, 2: Direct Hash, 3: Vendor defined */ uint8_t channel_spacing; /**< derived from regulatory domain. 0:200k, 1:400k, 2:600k, 3:100k */ uint8_t number_of_channels; /**< derived from regulatory domain */ uint8_t clock_drift; uint8_t timing_accurancy; - uint16_t fixed_channel; + uint16_t uc_fixed_channel; + uint16_t bc_fixed_channel; uint16_t fhss_bsi; uint32_t fhss_broadcast_interval; uint32_t channel_mask[8]; @@ -182,9 +184,19 @@ typedef struct ws_bs_ie { #define WS_FAN_VERSION_1_0 1 -#define WS_NEIGHBOR_LINK_TIMEOUT 240 +#define WS_NEIGHBOR_LINK_TIMEOUT 2200 #define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2 +#define WS_NEIGBOR_ETX_SAMPLE_MAX 3 + +#define WS_PROBE_INIT_BASE_SECONDS 8 + +#define WS_NUD_RAND_PROBABILITY 1 + +#define WS_NUD_RANDOM_SAMPLE_LENGTH WS_NEIGHBOR_NUD_TIMEOUT / 2 + +#define WS_NUD_RANDOM_COMPARE (WS_NUD_RAND_PROBABILITY*WS_NUD_RANDOM_SAMPLE_LENGTH) / 100 + /* * Threshold (referenced to DEVICE_MIN_SENS) above which a neighbor node may be considered for inclusion into candidate parent set */ @@ -203,4 +215,12 @@ typedef struct ws_bs_ie { */ #define WS_RPL_DIS_TIMEOUT 1800 +/* Default FHSS timing information + * + */ +#define WS_FHSS_UC_DWELL_INTERVAL 250; +#define WS_FHSS_BC_INTERVAL 800; +#define WS_FHSS_BC_DWELL_INTERVAL 200; + + #endif /* WS_COMMON_DEFINES_H_ */ diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index c05964f00b0..5be662f3a45 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -21,11 +21,16 @@ #include "fhss_ws_extension.h" #include "6LoWPAN/ws/ws_common_defines.h" +#define RSL_UNITITIALIZED 0x7fff + typedef struct ws_neighbor_class_entry { fhss_ws_neighbor_timing_info_t fhss_data; uint16_t rsl_in; /*!< RSL EWMA heard from neighbour*/ uint16_t rsl_out; /*!< RSL EWMA heard by neighbour*/ + uint16_t routing_cost; /*!< ETX to border Router. */ bool candidate_parent:1; + bool broadcast_timing_info_stored:1; + bool broadcast_shedule_info_stored:1; } ws_neighbor_class_entry_t; /** diff --git a/source/Common_Protocols/ipv6.c b/source/Common_Protocols/ipv6.c index af3ca814f49..ea441ea4490 100644 --- a/source/Common_Protocols/ipv6.c +++ b/source/Common_Protocols/ipv6.c @@ -583,6 +583,24 @@ buffer_t *ipv6_forwarding_down(buffer_t *buf) return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_NO_ROUTE, 0); } + /* Consider multicast forwarding /before/ calling routing code to modify + * extension headers - if that actually decides to tunnel it will + * overwrite the buffer's src_sa and dst_sa, when we want to consider + * forwarding the inner packet. This ordering works out for our only + * header-modifying multicast case of MPL: + * 1) We never want to forward packets with MPL headers, which means the + * outer packet in a tunnel gets ignored anyway. + * 2) This also means we don't have to worry that we're forwarding packets + * with the extension header not filled in yet. + * If we ever do have a multicast system where we are working with + * extension headers and forwarding those across interfaces, ipv6_get_exthdrs + * system will need a rework - probably split the "try MODIFY" call from the + * subsequent "give me tunnel parameters" part. + */ + if (!buf->ip_routed_up && addr_is_ipv6_multicast(buf->dst_sa.address)) { + buf = ipv6_consider_forwarding_multicast_packet(buf, buf->interface, true); + } + /* Allow routing code to update extension headers */ int16_t exthdr_result; buf = ipv6_get_exthdrs(buf, IPV6_EXTHDR_MODIFY, &exthdr_result); @@ -593,10 +611,6 @@ buffer_t *ipv6_forwarding_down(buffer_t *buf) goto drop; } - if (!buf->ip_routed_up && addr_is_ipv6_multicast(buf->dst_sa.address)) { - buf = ipv6_consider_forwarding_multicast_packet(buf, buf->interface, true); - } - /* Routing code may say it needs to tunnel to add headers - loop back to IP layer if requested */ if (exthdr_result == IPV6_EXTHDR_MODIFY_TUNNEL) { /* Avoid an infinite loop in the event of routing code failure - never diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index 26b7b3a7963..1049fe0cdd3 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -34,7 +34,6 @@ #include "DHCPv6_Server/DHCPv6_server_service.h" #include "common_functions.h" #include "NWK_INTERFACE/Include/protocol.h" -#include "6LoWPAN/Thread/thread_bbr_api_internal.h" #include "Common_Protocols/icmpv6.h" #include "dhcp_service_api.h" @@ -57,9 +56,6 @@ static int8_t dhcpv6_service_tasklet = -1; static arm_event_storage_t *dhcp_timer_storage = NULL; -static void DHCPV6_server_service_remove_GUA_from_neighcache(protocol_interface_info_entry_t *cur, uint8_t *targetAddress); - - static bool DHCP_server_service_timer_start(void) { if(!dhcp_timer_storage) { @@ -101,19 +97,16 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r nonTemporalAddress.validLifeTime = dhcp_allocated_address->lifetime; nonTemporalAddress.preferredLifeTime = dhcp_allocated_address->preferredLifetime; - // If this is solicit from existing address, flush ND cache. - if (allocateNew) { - // coverity[returned_null] for ignoring protocol_stack_interface_info_get_by_id NULL return - DHCPV6_server_service_remove_GUA_from_neighcache(protocol_stack_interface_info_get_by_id(serverBase->interfaceId), nonTemporalAddress.requestedAddress); - } - if (thread_bbr_nd_entry_add(serverBase->interfaceId,dhcp_allocated_address->nonTemporalAddress, nonTemporalAddress.validLifeTime, serverBase->guaPrefix) == -1) { - // No nanostack BBR present we will put entry for application implemented BBR - ipv6_route_t *route = ipv6_route_add_with_info(dhcp_allocated_address->nonTemporalAddress, 128, serverBase->interfaceId, NULL, ROUTE_THREAD_PROXIED_HOST,serverBase->guaPrefix,0, nonTemporalAddress.validLifeTime, 0); - if (!route) { + if (serverBase->addCb) { + dhcp_address_cache_update_t update_info; + update_info.allocatedAddress = dhcp_allocated_address->nonTemporalAddress; + update_info.allocatedNewAddress = allocateNew; + update_info.validLifeTime = nonTemporalAddress.validLifeTime; + + if (!serverBase->addCb(serverBase->interfaceId, &update_info, serverBase->guaPrefix)) { address_allocated = false; libdhcpv6_address_rm_from_allocated_list(serverBase,dhcp_allocated_address->nonTemporalAddress); } - } } @@ -213,30 +206,6 @@ void DHCPv6_server_service_tasklet(arm_event_s *event) } } -static void DHCPV6_server_service_remove_GUA_from_neighcache(protocol_interface_info_entry_t *cur, uint8_t *targetAddress) -{ - ipv6_neighbour_t *neighbour_entry; - - neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, targetAddress); - if (neighbour_entry) { - tr_debug("Remove from neigh Cache: %s", tr_ipv6(targetAddress)); - ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, neighbour_entry); - } -} - -void DHCPv6_server_service_address_preferred_timeout_handler(int8_t interfaceId, uint8_t *targetAddress) -{ - tr_warn("Address Preferred Timeout"); - protocol_interface_info_entry_t *cur = 0; - //allocate Socket Service - - cur = protocol_stack_interface_info_get_by_id(interfaceId); - if (cur) { - ipv6_route_delete(targetAddress, 128, interfaceId, NULL, ROUTE_THREAD_PROXIED_HOST); - DHCPV6_server_service_remove_GUA_from_neighcache(cur, targetAddress); - } -} - static int8_t dhcpv6_server_service_tasklet_generated(void) { if (dhcpv6_service_tasklet == -1) { @@ -267,28 +236,21 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u //allocate Socket Service socketInstance = dhcp_service_init(interface, DHCP_INSTANCE_SERVER, DHCPV6_server_service_request_handler); cur = protocol_stack_interface_info_get_by_id(interface); - if (cur) { - if (dhcpv6_server_service_tasklet_generated() < 0) { - retVal = -2; - } else if (!DHCP_server_service_timer_start()) { - retVal = -2; - } else { - //allocate server - dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_gua_server_allocate(guaPrefix, interface, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE, DHCPv6_server_service_address_preferred_timeout_handler); - if (serverInfo) { - //if_address_entry_t *def_address = NULL; - uint8_t temp[16]; - uint8_t *ptr = temp; - //define address & Route advert's - memcpy(ptr, guaPrefix, 8); - ptr += 8; - memcpy(ptr, cur->iid_slaac, 8); - - serverInfo->socketInstance_id = socketInstance; - socketInstance = 0; - //Generate Address for current interface - retVal = 0; - } + if (!cur) { + return -1; + } + + if (dhcpv6_server_service_tasklet_generated() < 0) { + retVal = -2; + } else if (!DHCP_server_service_timer_start()) { + retVal = -2; + } else { + //allocate server + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_gua_server_allocate(guaPrefix, interface, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE); + if (serverInfo) { + serverInfo->socketInstance_id = socketInstance; + socketInstance = 0; + retVal = 0; } } if (socketInstance > 0) { @@ -303,25 +265,6 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds) libdhcpv6_gua_servers_time_update(timeUpdateInSeconds); } -void DHCPv6_GUA64_ML64_route_control(int8_t interfaceId, uint8_t *allocatedGuaAddress, uint8_t *clientEUID64, uint8_t *meshLocalPrefix, bool deleteMapping) -{ - uint8_t ml64[16]; - uint8_t *ptr = ml64; - memcpy(ptr, meshLocalPrefix, 8); - ptr += 8; - memcpy(ptr, clientEUID64, 8); - *ptr ^= 2; - //Generate Route Info - if (deleteMapping) { - ipv6_route_delete(allocatedGuaAddress, 128, interfaceId, ml64, ROUTE_STATIC); - } else if (ipv6_route_add(allocatedGuaAddress, 128, interfaceId, ml64, ROUTE_STATIC, 0xffffffff, 0) == 0) { - tr_debug("Route ADD OK"); - } else { - tr_warn("Route Add fail"); - } - -} - /* Delete dhcp thread dhcp router ID server. * * When this is called it close selected service and free all allocated memory. @@ -332,30 +275,32 @@ void DHCPv6_GUA64_ML64_route_control(int8_t interfaceId, uint8_t *allocatedGuaAd */ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses) { - protocol_interface_info_entry_t *curPtr = 0; - //allocate Socket Service - - curPtr = protocol_stack_interface_info_get_by_id(interface); - if (curPtr) { - 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) { - //Delete Server data base - DHCPV6_server_service_remove_GUA_from_neighcache(curPtr, cur->nonTemporalAddress); + 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) { + //Delete Server data base + if (serverInfo->removeCb) { + serverInfo->removeCb(interface, cur->nonTemporalAddress, NULL); } + } + if (serverInfo->removeCb) { // Clean all /128 'Thread Proxy' routes to self and others added when acting as a DHCP server - ipv6_route_table_remove_info(curPtr->id, ROUTE_THREAD_PROXIED_HOST,serverInfo->guaPrefix); - dhcp_service_delete(serverInfo->socketInstance_id); + serverInfo->removeCb(interface, NULL, serverInfo->guaPrefix); } + dhcp_service_delete(serverInfo->socketInstance_id); + } - if (delete_gua_addresses) { + if (delete_gua_addresses) { + protocol_interface_info_entry_t *curPtr = protocol_stack_interface_info_get_by_id(interface); + if (curPtr) { protocol_core_dhcpv6_allocated_address_remove(curPtr, guaPrefix); } + } - libdhcpv6_gua_server_free_by_prefix_and_interfaceid(guaPrefix, interface); + libdhcpv6_gua_server_free_by_prefix_and_interfaceid(guaPrefix, interface); + + DHCP_server_service_timer_stop(); - DHCP_server_service_timer_stop(); - } } /* Control GUA address for client by DUI.Default value is true @@ -379,33 +324,15 @@ int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t gu return retVal; } -/* Enable or disable GUA64 Address mapping to ML64 - * - * - * /param interface interface id of this thread instance. - * /param guaPrefix Prefix which will be removed - * /param mode - * /param meshLocalPrefix mesh local prefix for generate ML6 from client EUID64 - */ -int DHCPv6_server_service_set_gua_address_mapping(int8_t interface, uint8_t guaPrefix[static 16], bool mode, uint8_t meshLocalPrefix[8]) +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) { - int retVal = -1; - dhcpv6_gua_server_entry_s *serverInfo; - - serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); - if (serverInfo) { - if (mode == true && meshLocalPrefix == NULL) { - retVal = -2; - } else { - serverInfo->enableAddressMapping = mode; - if (meshLocalPrefix) { - memcpy(serverInfo->meshLocalPrefix, meshLocalPrefix, 8); - } - retVal = 0; - } + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return; } - return retVal; + serverInfo->addCb = add_cb; + serverInfo->removeCb = remove_cb; } /* SET max accepted clients to server, Default is 200 @@ -453,21 +380,6 @@ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t gu } return retVal; } - -int DHCPv6_server_service_gua_target_mac_check(int8_t interfaceId, const uint8_t *targetGUA, uint8_t *targetEUI64) -{ - dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, targetGUA); - if (serverInfo) { - dhcpv6_alloacted_address_entry_t *entry = libdhcpv6_address_get_from_allocated_list(serverInfo, targetGUA); - if (entry) { - if (entry->preferredLifetime && (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE)) { - memcpy(targetEUI64, entry->linkId, 8); - return 0; - } - } - } - return -1; -} #else int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], uint8_t serverDUID[static 8], uint16_t serverDUIDType) @@ -497,15 +409,6 @@ int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t gu return -1; } -int DHCPv6_server_service_set_gua_address_mapping(int8_t interface, uint8_t guaPrefix[static 16], bool mode, uint8_t meshLocalPrefix[8]) -{ - (void) interface; - (void) guaPrefix; - (void) mode; - (void) meshLocalPrefix; - - return -1; -} int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_t guaPrefix[static 16], uint32_t maxClientCount) { (void) interface; @@ -522,13 +425,5 @@ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t gu return -1; } -int DHCPv6_server_service_gua_target_mac_check(int8_t interfaceId, const uint8_t *targetGUA, uint8_t *targetEUI64) -{ - (void) interfaceId; - (void) targetGUA; - (void) targetEUI64; - - return -1; -} #endif diff --git a/source/DHCPv6_Server/DHCPv6_server_service.h b/source/DHCPv6_Server/DHCPv6_server_service.h index 50f535f7a74..d2ba01068f4 100644 --- a/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/source/DHCPv6_Server/DHCPv6_server_service.h @@ -23,6 +23,10 @@ #ifndef DHCPV6_SERVER_SERVICE_H_ #define DHCPV6_SERVER_SERVICE_H_ +#ifdef HAVE_DHCPV6_SERVER +#include "libDHCPv6/libDHCPv6.h" +#include "libDHCPv6/libDHCPv6_server.h" + /* Initialize dhcp Global address server. * * This instance needs to bee initialized once for each thread network interface. @@ -38,6 +42,10 @@ */ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], uint8_t serverDUID[static 8], uint16_t serverDUIDType); + +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); + + /* Delete dhcp thread dhcp router ID server. * * When this is called it close selected service and free all allocated memory. @@ -51,8 +59,6 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16] void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds); -//void DHCPv6_GUA64_ML64_route_control(int8_t interfaceId, uint8_t *allocatedGuaAddress, uint8_t *clientEUID64, uint8_t *meshLocalPrefix, bool deleteMapping); - /* Control GUA address for client by DUI.Default value is true * * @@ -63,16 +69,6 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds); int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode); -/* Enable or disable GUA64 Address mapping to ML64 - * - * - * /param interface interface id of this thread instance. - * /param guaPrefix Prefix which will be removed - * /param mode - * /param meshLocalPrefix mesh local prefix for generate ML6 from client EUID64 - */ -int DHCPv6_server_service_set_gua_address_mapping(int8_t interface, uint8_t guaPrefix[static 16], bool mode, uint8_t meshLocalPrefix[8]); - /* SET max accepted clients to server, Default is 200 * * @@ -91,7 +87,7 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_ * /param validLifeTimne in seconds */ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t guaPrefix[static 16], uint32_t validLifeTimne); - - -int DHCPv6_server_service_gua_target_mac_check(int8_t interfaceId, const uint8_t *targetGUA, uint8_t *targetEUI64); +#else +#define DHCPv6_server_service_delete(interface, guaPrefix, delete_gua_addresses) +#endif #endif /* DHCPV6_SERVER_SERVICE_H_ */ diff --git a/source/DHCPv6_client/dhcpv6_client_api.h b/source/DHCPv6_client/dhcpv6_client_api.h new file mode 100644 index 00000000000..69ae1ddd20d --- /dev/null +++ b/source/DHCPv6_client/dhcpv6_client_api.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DHCPV6_CLIENT_API_H_ +#define DHCPV6_CLIENT_API_H_ +#include + +/* DHCP client implementation. + * + * Responsibilities of this module are: + * - handle Global address queries and refresh inside network. + * + */ + +/* Initialize dhcp client. + * + * This instance needs to bee initialized once for each network interface. + * if only one thread instance is supported this is needed to call only once. + * + * /param interface interface id of this instance. + * + */ + +void dhcp_client_init(int8_t interface); + +/* Delete dhcp client. + * + * When this is called all addressed assigned by this module are removed from stack. + */ +void dhcp_client_delete(int8_t interface); + +/* Global address handler. + * + * This module updates the addresses from dhcp server and sets them in stack. + * this module makes refresh of address when needed. + * + */ + + +/* give dhcp server and prefix for global address assignment + * + * /param interface interface where address is got + * /param dhcp_addr dhcp server ML16 address where address is registered. + * /param prefix dhcp server ML16 address where address is registered. + * /param mac64 64 bit mac address for identifieng client. + * /param error_cb error callback that is called if address cannot be created or becomes invalid. + * /param register_status true if address registered. + * + */ +typedef void (dhcp_client_global_adress_cb)(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status); + +int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], dhcp_client_global_adress_cb *error_cb); + +/* Renew all leased adddresses might be used when short address changes + * + * /param interface interface where address is got + */ +void dhcp_client_global_address_renew(int8_t interface); + +/* Delete address from device + * if prefix is NULL all are deleted + * + * /param interface interface where address is got + * /param prefix dhcp server ML16 address where address is registered. + * + */ +void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]); + + +void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]); + + + +#endif /* DHCPV6_CLIENT_API_H_ */ diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_client.c b/source/DHCPv6_client/dhcpv6_client_service.c similarity index 74% rename from source/6LoWPAN/Thread/thread_dhcpv6_client.c rename to source/DHCPv6_client/dhcpv6_client_service.c index a49054e3ed0..06be8c8374c 100644 --- a/source/6LoWPAN/Thread/thread_dhcpv6_client.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -1,34 +1,21 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. - * SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * 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 * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. + * http://www.apache.org/licenses/LICENSE-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * 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" -#ifdef HAVE_THREAD #include #include #include @@ -36,31 +23,30 @@ #include "ns_list.h" #include "common_functions.h" - +#ifdef HAVE_DHCPV6 #include "dhcp_service_api.h" -#include "thread_dhcpv6_client.h" +#include "dhcpv6_client_api.h" #include "libDHCPv6/libDHCPv6.h" #include "NWK_INTERFACE/Include/protocol.h" -#include "6LoWPAN/Thread/thread_common.h" -#include "6LoWPAN/Thread/thread_bootstrap.h" -#define TRACE_GROUP "TDHP" +#define TRACE_GROUP "DHP" typedef struct { - thread_dhcp_client_global_adress_cb *global_address_cb; + dhcp_client_global_adress_cb *global_address_cb; uint16_t service_instance; + uint16_t relay_instance; uint8_t libDhcp_instance; int8_t interface; -} thread_dhcp_client_class_t; +} dhcp_client_class_t; -thread_dhcp_client_class_t dhcp_client; +static dhcp_client_class_t dhcp_client; -void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr); +void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr); -void thread_dhcp_client_init(int8_t interface) +void dhcp_client_init(int8_t interface) { - // No support for multible thread instances yet. + // No support for multible instances yet. dhcp_client.service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL); dhcp_client.interface = interface; dhcp_client.libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id(); @@ -68,7 +54,13 @@ void thread_dhcp_client_init(int8_t interface) return; } -void thread_dhcp_client_delete(int8_t interface) +void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]) +{ + dhcp_client.relay_instance = dhcp_service_init(interface, DHCP_INTANCE_RELAY_AGENT, NULL); + dhcp_service_relay_instance_enable(dhcp_client.relay_instance, border_router_address); +} + +void dhcp_client_delete(int8_t interface) { protocol_interface_info_entry_t *cur = NULL; dhcpv6_client_server_data_t *srv_data_ptr; @@ -96,7 +88,7 @@ void thread_dhcp_client_delete(int8_t interface) } -void thread_dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr) +void dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr) { if (srv_data_ptr != NULL) { @@ -159,12 +151,11 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin srv_data_ptr->iaNontemporalAddress.validLifetime = dhcp_ia_non_temporal_params.validLifeTime; memcpy(srv_data_ptr->serverLinkId, serverId.linkID, 8); srv_data_ptr->serverLinkType = serverId.linkType; - srv_data_ptr->serverLinkType = serverId.linkType; srv_data_ptr->T0 = dhcp_ia_non_temporal_params.T0; srv_data_ptr->T1 = dhcp_ia_non_temporal_params.T1; srv_data_ptr->iaNonTemporalStructValid = true; - thread_dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr); + dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr); if (dhcp_client.global_address_cb) { @@ -172,11 +163,11 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin } return RET_MSG_ACCEPTED; error_exit: - thread_dhcpv6_client_send_error_cb(srv_data_ptr); + dhcpv6_client_send_error_cb(srv_data_ptr); return RET_MSG_ACCEPTED; } -int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], thread_dhcp_client_global_adress_cb *error_cb) +int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], dhcp_client_global_adress_cb *error_cb) { dhcpv6_solication_base_packet_s solPacket = {0}; dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; @@ -190,16 +181,19 @@ int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[st } srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, DHCPV6_DUID_HARDWARE_EUI64_TYPE, prefix, dhcp_addr); + if (!srv_data_ptr) { + tr_error("OOM srv_data_ptr"); + return -1; + } payload_len = libdhcpv6_solication_message_length(DHCPV6_DUID_HARDWARE_EUI64_TYPE, true, 0); payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); - - if (payload_ptr == NULL || srv_data_ptr == NULL) { - ns_dyn_mem_free(payload_ptr); + if (!payload_ptr) { libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); - tr_error("Out of memory"); + tr_error("OOM payload_ptr"); return -1; } + dhcp_client.global_address_cb = error_cb; //TODO Only supporting one instance globaly if we need more for different instances needs code. srv_data_ptr->GlobalAddress = true; // Build solicit @@ -214,17 +208,22 @@ int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[st // send solicit srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr , dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb); - return srv_data_ptr->transActionId ? 0 : -1; + if (srv_data_ptr->transActionId == 0) { + ns_dyn_mem_free(payload_ptr); + libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); + return -1; + } + + return 0; } -void thread_dhcp_client_global_address_renew(int8_t interface) +void dhcp_client_global_address_renew(int8_t interface) { - // only prepared for changes in thread specifications (void)interface; return; } -void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]) +void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]) { protocol_interface_info_entry_t *cur; dhcpv6_client_server_data_t *srv_data_ptr; @@ -249,7 +248,7 @@ void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_add return; } -void thread_dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason) +void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason) { dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; dhcp_link_options_params_t serverLink; @@ -275,7 +274,7 @@ void thread_dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_ payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0); payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); if (payload_ptr == NULL) { - addr->state_timer = 200;//Retry after? should there be maximum 20 second retry + addr->state_timer = 200; //Retry after 20 seconds tr_error("Out of memory"); return ; } @@ -299,9 +298,14 @@ void thread_dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_ libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink); // send solicit srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, srv_data_ptr->server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb); + if (srv_data_ptr->transActionId == 0) { + ns_dyn_mem_free(payload_ptr); + addr->state_timer = 200; //Retry after 20 seconds + tr_error("DHCP renew send failed"); + } } -void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) +void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) { protocol_interface_info_entry_t *cur = NULL; if_address_entry_t *address_entry = NULL; @@ -335,6 +339,7 @@ void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_ } } address_entry->state_timer = renewTimer; - address_entry->cb = thread_dhcpv6_renew; + address_entry->cb = dhcpv6_renew; } + #endif diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 9315d36e95c..8a1c2edc9d6 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -37,7 +37,9 @@ typedef enum mac_event_t { MAC_TIMER_ACK, MAC_TIMER_CCA, MAC_TX_FAIL, - MAC_TX_TIMEOUT + MAC_TX_TIMEOUT, + MAC_UNKNOWN_DESTINATION, + MAC_TX_PRECOND_FAIL } mac_event_t; typedef enum mac_tx_status_type_t { @@ -89,8 +91,12 @@ typedef enum arm_nwk_mlme_event_type { ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL_AFTER_DATA = 5, } arm_nwk_mlme_event_type_e; +#define ENHANCED_ACK_MAX_LENGTH 255 + typedef struct dev_driver_tx_buffer { uint8_t *buf; + uint8_t *enhanced_ack_buf; + uint16_t ack_len; uint16_t len; unsigned priority:2; } dev_driver_tx_buffer_s; @@ -134,6 +140,11 @@ typedef struct mac_tx_status_t { uint8_t retry; } mac_tx_status_t; +typedef struct mac_mcps_data_conf_fail_s { + uint8_t msduHandle; /**< Handle associated with MSDU */ + uint8_t status; /**< Status of the failing MSDU transmission */ +} mac_mcps_data_conf_fail_t; + typedef struct protocol_interface_rf_mac_setup { int8_t mac_interface_id; bool macUpState; @@ -229,6 +240,7 @@ typedef struct protocol_interface_rf_mac_setup { uint8_t max_ED; uint16_t mlme_ED_counter; mac_tx_status_t mac_tx_status; + mac_mcps_data_conf_fail_t mac_mcps_data_conf_fail; struct cca_structure_s *cca_structure; /* MAC Security components */ struct mlme_device_descriptor_s *device_description_table; diff --git a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c index d326aaa078a..3f09ca01baf 100644 --- a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c +++ b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c @@ -65,13 +65,24 @@ uint32_t mac_read_phy_datarate(const fhss_api_t *fhss_api) return datarate; } +uint32_t mac_read_phy_timestamp(const fhss_api_t *fhss_api) +{ + protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_fhss_api(fhss_api); + if (!mac_setup) { + return 0; + } + uint32_t timestamp; + mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_TIMESTAMP, (uint8_t *)×tamp); + return timestamp; +} + int mac_set_channel(const fhss_api_t *fhss_api, uint8_t channel_number) { protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_fhss_api(fhss_api); if (!mac_setup) { return -1; } - if (mac_setup->mac_ack_tx_active || (mac_setup->active_pd_data_request && mac_setup->active_pd_data_request->asynch_request)) { + if (mac_setup->mac_ack_tx_active || (mac_setup->active_pd_data_request && (mac_setup->active_pd_data_request->asynch_request || mac_setup->timer_mac_event == MAC_TIMER_ACK))) { return -1; } return mac_mlme_rf_channel_change(mac_setup, channel_number); diff --git a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h index 431cd9cd1ae..364c94339f7 100644 --- a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h +++ b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h @@ -21,6 +21,7 @@ uint16_t mac_read_tx_queue_sizes(const fhss_api_t *fhss_api, bool broadcast_queue); int mac_read_64bit_mac_address(const fhss_api_t *fhss_api, uint8_t *mac_address); uint32_t mac_read_phy_datarate(const fhss_api_t *fhss_api); +uint32_t mac_read_phy_timestamp(const fhss_api_t *fhss_api); int mac_set_channel(const fhss_api_t *fhss_api, uint8_t channel_number); int mac_fhss_frame_tx(const fhss_api_t *fhss_api, int frame_type); int mac_synch_lost(const fhss_api_t *fhss_api); diff --git a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c index 2867513170f..39711c22b54 100644 --- a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c +++ b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c @@ -337,16 +337,16 @@ void mac_header_security_components_read(mac_pre_parsed_frame_t *buffer, mlme_se } -uint16_t mac_header_get_src_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr) +static bool mac_header_pan_full_compressed(const mac_fcf_sequence_t *header) { - - if (!header->SrcPanPresents) { - if (!header->DstPanPresents) { - return 0xffff; - } - return mac_header_get_dst_panid(header, ptr); + if (header->frameVersion == MAC_FRAME_VERSION_2015 && (!header->DstPanPresents && !header->SrcPanPresents) && header->intraPan) { + return true; } + return false; +} +static uint16_t mac_header_read_src_pan(const mac_fcf_sequence_t *header, const uint8_t *ptr) +{ ptr += mac_fcf_lenght(header);//Skip FCF + DSN ptr += mac_dst_address_length_with_panid(header); //Skip Dst panID & Address @@ -354,15 +354,42 @@ uint16_t mac_header_get_src_panid(const mac_fcf_sequence_t *header, const uint8_ return common_read_16_bit_inverse(ptr); } -uint16_t mac_header_get_dst_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr) +static uint16_t mac_header_read_dst_pan(const mac_fcf_sequence_t *header, const uint8_t *ptr) +{ + ptr += mac_fcf_lenght(header);//Skip FCF + DSN + + return common_read_16_bit_inverse(ptr); +} + +uint16_t mac_header_get_src_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint16_t configured_pan_id) +{ + if (mac_header_pan_full_compressed(header)) { + return configured_pan_id; + } + + if (!header->SrcPanPresents) { + if (!header->DstPanPresents) { + return 0xffff; + } + return mac_header_read_dst_pan(header, ptr); + } + + return mac_header_read_src_pan(header, ptr); +} + +uint16_t mac_header_get_dst_panid(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint16_t configured_pan_id) { + if (mac_header_pan_full_compressed(header)) { + return configured_pan_id; + } if (!header->DstPanPresents) { + if (header->SrcPanPresents && header->frameVersion == MAC_FRAME_VERSION_2015 && header->DstAddrMode == MAC_ADDR_MODE_NONE) { + return mac_header_read_src_pan(header, ptr); + } return 0xffff; } - ptr += mac_fcf_lenght(header);//Skip FCF + DSN - - return common_read_16_bit_inverse(ptr); + return mac_header_read_dst_pan(header, ptr); } void mac_header_get_src_address(const mac_fcf_sequence_t *header, const uint8_t *ptr, uint8_t *address_ptr) diff --git a/source/MAC/IEEE802_15_4/mac_header_helper_functions.h b/source/MAC/IEEE802_15_4/mac_header_helper_functions.h index 4231f398209..5ce872323f8 100644 --- a/source/MAC/IEEE802_15_4/mac_header_helper_functions.h +++ b/source/MAC/IEEE802_15_4/mac_header_helper_functions.h @@ -59,8 +59,8 @@ uint16_t mac_buffer_total_payload_length(struct mac_pre_build_frame *buffer); /** * Next function should only call when address mode is not MAC_ADDR_MODE_NONE and parsed proper header! */ -uint16_t mac_header_get_src_panid(const struct mac_fcf_sequence_s *header, const uint8_t *ptr); -uint16_t mac_header_get_dst_panid(const struct mac_fcf_sequence_s *header, const uint8_t *ptr); +uint16_t mac_header_get_src_panid(const struct mac_fcf_sequence_s *header, const uint8_t *ptr, uint16_t configured_pan_id); +uint16_t mac_header_get_dst_panid(const struct mac_fcf_sequence_s *header, const uint8_t *ptr, uint16_t configured_pan_id); void mac_header_get_src_address(const struct mac_fcf_sequence_s *header, const uint8_t *ptr, uint8_t *address_ptr); void mac_header_get_dst_address(const struct mac_fcf_sequence_s *header, const uint8_t *ptr, uint8_t *address_ptr); uint8_t mac_address_length(uint8_t address_mode); diff --git a/source/MAC/IEEE802_15_4/mac_indirect_data.c b/source/MAC/IEEE802_15_4/mac_indirect_data.c index 3820c16e8d2..db09d73f1be 100644 --- a/source/MAC/IEEE802_15_4/mac_indirect_data.c +++ b/source/MAC/IEEE802_15_4/mac_indirect_data.c @@ -134,7 +134,7 @@ uint8_t mac_indirect_data_req_handle(mac_pre_parsed_frame_t *buf, protocol_inter comm_status.status = MLME_DATA_POLL_NOTIFICATION; //Call com status - comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf)); + comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), mac_ptr->pan_id); comm_status.DstAddrMode = buf->fcf_dsn.DstAddrMode;; mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.DstAddr); comm_status.SrcAddrMode = buf->fcf_dsn.SrcAddrMode; diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index cfe56837606..f118770c330 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -70,6 +70,7 @@ static void mac_set_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup static void mac_clear_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type); static bool mac_read_active_event(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t event_type); static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer); +static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup); static int8_t mac_tasklet_event_handler = -1; @@ -87,47 +88,18 @@ static uint32_t mac_mcps_sap_get_phy_timestamp(protocol_interface_rf_mac_setup_s return timestamp; } -static void mac_data_request_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) -{ - rf_mac_setup->active_pd_data_request = buffer; - if (buffer->asynch_request) { - buffer->asynch_channel = rf_mac_setup->mac_channel; //Store Original channel - uint16_t channel = mlme_scan_analyze_next_channel(&buffer->asynch_channel_list); - if (channel <= 0xff) { - uint8_t switch_channel = channel; - if (rf_mac_setup->mac_channel != switch_channel) { - mac_mlme_mac_radio_disabled(rf_mac_setup); - rf_mac_setup->mac_channel = channel; - mac_mlme_mac_radio_enable(rf_mac_setup); - } - } - } -} - static bool mac_data_request_confirmation_finnish(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { if (!buffer->asynch_request) { return true; } - uint16_t channel = mlme_scan_analyze_next_channel(&buffer->asynch_channel_list); - uint8_t switch_channel; - bool return_value; - - if (channel > 0x00ff) { - return_value = true; - switch_channel = buffer->asynch_channel; - } else { - switch_channel = channel; - return_value = false; - } - //Set original Channel back if channel is switched - if (rf_mac_setup->mac_channel != switch_channel) { - mac_mlme_mac_radio_disabled(rf_mac_setup); - rf_mac_setup->mac_channel = switch_channel; - mac_mlme_mac_radio_enable(rf_mac_setup); + if (mlme_scan_analyze_next_channel(&buffer->asynch_channel_list, false) > 0x00ff) { + mac_mlme_rf_channel_change(rf_mac_setup, buffer->asynch_channel); + return true; } - return return_value; + + return false; } @@ -145,7 +117,6 @@ static void mac_data_poll_radio_disable_check(protocol_interface_rf_mac_setup_s static void mcps_data_confirm_cb(protocol_interface_rf_mac_setup_s *rf_mac_setup, mcps_data_conf_t *confirm, mac_pre_parsed_frame_t *ack_buf) { - mac_data_poll_radio_disable_check(rf_mac_setup); if( get_sw_mac_api(rf_mac_setup) ) { @@ -363,13 +334,14 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set verify_status: if (status != MLME_SUCCESS){ - mcps_data_conf_t confirm; - memset(&confirm, 0, sizeof(mcps_data_conf_t)); - confirm.msduHandle = data_req->msduHandle; - confirm.status = status; tr_debug("DATA REQ Fail %u", status); + rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = data_req->msduHandle; + rf_mac_setup->mac_mcps_data_conf_fail.status = status; mcps_sap_prebuild_frame_buffer_free(buffer); - mcps_data_confirm_cb(rf_mac_setup, &confirm, NULL); + if (mcps_sap_pd_confirm_failure(rf_mac_setup) != 0) { + // event sending failed, calling handler directly + mac_pd_data_confirm_failure_handle(rf_mac_setup); + } } } @@ -568,7 +540,7 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme //READ SRC Address - uint16_t SrcPANId = mac_header_get_src_panid(&b->fcf_dsn, mac_header_message_start_pointer(b)); + uint16_t SrcPANId = mac_header_get_src_panid(&b->fcf_dsn, mac_header_message_start_pointer(b), rf_mac_setup->pan_id); mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address); neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode; neighbour_validation.keyId = security_params->KeyIndex; @@ -670,10 +642,11 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme static void mcps_comm_status_indication_generate(uint8_t status, mac_pre_parsed_frame_t *buf, mac_api_t * mac) { mlme_comm_status_t comm_status; + protocol_interface_rf_mac_setup_s *rf_ptr = buf->mac_class_ptr; memset(&comm_status,0 ,sizeof(mlme_comm_status_t) ); comm_status.status = status; //Call com status - comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf)); + comm_status.PANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_ptr->pan_id); comm_status.DstAddrMode = buf->fcf_dsn.DstAddrMode;; mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), comm_status.DstAddr); comm_status.SrcAddrMode = buf->fcf_dsn.SrcAddrMode; @@ -723,12 +696,14 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte //Parse data data_ind->DSN = buf->fcf_dsn.DSN; data_ind->DstAddrMode = buf->fcf_dsn.DstAddrMode; - data_ind->DstPANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf)); mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->DstAddr); data_ind->SrcAddrMode = buf->fcf_dsn.SrcAddrMode; - data_ind->SrcPANId = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf)); + mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->SrcAddr); + data_ind->SrcPANId = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id); + data_ind->DstPANId = mac_header_get_dst_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id); + data_ind->mpduLinkQuality = buf->LQI; data_ind->signal_dbm = buf->dbm; data_ind->timestamp = buf->timestamp; @@ -739,7 +714,6 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte if (buf->fcf_dsn.securityEnabled) { status = mac_data_interface_decrypt_packet(buf, &data_ind->Key); if (status != MLME_SUCCESS) { - tr_debug("Decrypt fail, %d", status); mcps_comm_status_indication_generate(status, buf, mac); goto DROP_PACKET; } @@ -772,6 +746,12 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte ie_list.payloadIeListLength = buf->payloadsIeLength; ie_list.headerIeList = buf->headerIePtr; ie_list.headerIeListLength = buf->headerIeLength; + //Swap compressed address to broadcast when dst Address is elided + if (buf->fcf_dsn.DstAddrMode == MAC_ADDR_MODE_NONE) { + data_ind->DstAddrMode = MAC_ADDR_MODE_16_BIT; + data_ind->DstAddr[0] = 0xff; + data_ind->DstAddr[1] = 0xff; + } mac->data_ind_ext_cb(mac, data_ind, &ie_list); } else { @@ -796,7 +776,7 @@ static void mac_lib_res_no_data_to_req(mac_pre_parsed_frame_t *buffer, protocol_ buf->fcf_dsn.SrcAddrMode = buffer->fcf_dsn.DstAddrMode; buf->fcf_dsn.DstAddrMode = buffer->fcf_dsn.SrcAddrMode; //SET PANID - buf->SrcPANId = mac_header_get_dst_panid(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer)); + buf->SrcPANId = mac_header_get_dst_panid(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer), rf_mac_setup->pan_id); buf->DstPANId = buf->SrcPANId; mac_header_get_dst_address(&buffer->fcf_dsn, mac_header_message_start_pointer(buffer), buf->SrcAddr); @@ -910,7 +890,7 @@ static void mac_data_interface_parse_beacon(mac_pre_parsed_frame_t *buf, protoco uint8_t *pending_address_list = NULL; uint8_t SuperframeSpec[2]; - uint16_t src_pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf)); + uint16_t src_pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id); //validate beacon pan-id and filter other network out if (rf_mac_setup->pan_id < 0xffff && (rf_mac_setup->pan_id != src_pan_id && !rf_mac_setup->macAcceptAnyBeacon)) { @@ -1045,6 +1025,14 @@ static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf) } +static void mac_mcps_asynch_finish(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) +{ + if (buffer->asynch_request && rf_mac_setup->fhss_api) { + // Must return to scheduled channel after asynch process by calling TX done + rf_mac_setup->fhss_api->data_tx_done(rf_mac_setup->fhss_api, false, true, buffer->msduHandle); + } +} + void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_setup) { if (!rf_mac_setup) { @@ -1064,9 +1052,10 @@ void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_s buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, is_bc_queue, false); if (buffer) { - mac_data_request_init(rf_mac_setup, buffer); + rf_mac_setup->active_pd_data_request = buffer; if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) { rf_mac_setup->active_pd_data_request = NULL; + mac_mcps_asynch_finish(rf_mac_setup, buffer); mcps_data_confirm_handle(rf_mac_setup, buffer, NULL); } else { return; @@ -1077,7 +1066,6 @@ void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_s } } - static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_interface_rf_mac_setup_s *rf_mac_setup) { //allocate Data ind primitiv and parse packet to that @@ -1106,20 +1094,18 @@ static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inter return 0; } -static void mac_pd_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup) { - +static void mac_pd_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup) +{ if (rf_mac_setup->active_pd_data_request) { mac_pre_build_frame_t *buffer = rf_mac_setup->active_pd_data_request; if (mac_data_request_confirmation_finnish(rf_mac_setup, buffer) ) { rf_mac_setup->active_pd_data_request = NULL; - if (buffer->asynch_request && rf_mac_setup->fhss_api) { - // Must return to scheduled channel after asynch process by calling TX done - rf_mac_setup->fhss_api->data_tx_done(rf_mac_setup->fhss_api, false, true, buffer->msduHandle); - } + mac_mcps_asynch_finish(rf_mac_setup, buffer); mcps_data_confirm_handle(rf_mac_setup, buffer, NULL); } else { if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) { rf_mac_setup->active_pd_data_request = NULL; + mac_mcps_asynch_finish(rf_mac_setup, buffer); mcps_data_confirm_handle(rf_mac_setup, buffer, NULL); } else { return; @@ -1130,9 +1116,17 @@ static void mac_pd_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_mac mac_mcps_trig_buffer_from_queue(rf_mac_setup); } +static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s *rf_mac_setup) +{ + mcps_data_conf_t mcps_data_conf; + memset(&mcps_data_conf, 0, sizeof(mcps_data_conf_t)); + mcps_data_conf.msduHandle = rf_mac_setup->mac_mcps_data_conf_fail.msduHandle; + mcps_data_conf.status = rf_mac_setup->mac_mcps_data_conf_fail.status; + mcps_data_confirm_cb(rf_mac_setup, &mcps_data_conf, NULL); +} -static void mac_pd_data_ack_handler(mac_pre_parsed_frame_t *buf) { - +static void mac_pd_data_ack_handler(mac_pre_parsed_frame_t *buf) +{ protocol_interface_rf_mac_setup_s *rf_mac_setup = buf->mac_class_ptr; if (!rf_mac_setup->active_pd_data_request) { @@ -1147,10 +1141,6 @@ static void mac_pd_data_ack_handler(mac_pre_parsed_frame_t *buf) { } rf_mac_setup->active_pd_data_request = NULL; - if (buffer->asynch_request && rf_mac_setup->fhss_api) { - // Must return to scheduled channel after asynch process by calling TX done - rf_mac_setup->fhss_api->data_tx_done(rf_mac_setup->fhss_api, false, true, buffer->msduHandle); - } mcps_data_confirm_handle(rf_mac_setup, buffer, buf); mcps_sap_pre_parsed_frame_buffer_free(buf); @@ -1177,6 +1167,10 @@ static void mac_mcps_sap_data_tasklet(arm_event_s *event) mac_pd_data_confirm_handle((protocol_interface_rf_mac_setup_s*)event->data_ptr); break; + case MCPS_SAP_DATA_CNF_FAIL_EVENT: + mac_pd_data_confirm_failure_handle((protocol_interface_rf_mac_setup_s*)event->data_ptr); + break; + case MCPS_SAP_DATA_ACK_CNF_EVENT: mac_pd_data_ack_handler((mac_pre_parsed_frame_t*)event->data_ptr); break; @@ -1277,14 +1271,8 @@ static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_ if (buffer->fcf_dsn.DstAddrMode && buffer->fcf_dsn.ackRequested) { device_description = mac_sec_mib_device_description_get(rf_ptr, buffer->DstAddr, buffer->fcf_dsn.DstAddrMode); if (!device_description) { - - if (rf_ptr->mac_security_bypass_unknow_device && (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT - && buffer->aux_header.securityLevel > AES_SECURITY_LEVEL_ENC)) { - - } else { - buffer->status = MLME_UNAVAILABLE_KEY; - return false; - } + buffer->status = MLME_UNAVAILABLE_KEY; + return false; } } nonce_ext_64_ptr = rf_ptr->mac64; @@ -1350,7 +1338,11 @@ static void mac_common_data_confirmation_handle (protocol_interface_rf_mac_setup //Enable Radio mac_mlme_mac_radio_enable(rf_mac_setup); buf->status = MLME_TRANSACTION_EXPIRED; - } + } else if (m_event == MAC_UNKNOWN_DESTINATION) { + buf->status = MLME_UNAVAILABLE_KEY; + }/** else if (m_event == MAC_TX_PRECOND_FAIL) { + * Nothing to do, status already set to buf->status. + }**/ } } @@ -1419,7 +1411,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, sw_mac_stats_update(rf_ptr, STAT_MAC_TX_CCA_ATT, rf_ptr->mac_tx_status.cca_cnt); sw_mac_stats_update(rf_ptr, STAT_MAC_TX_RETRY, rf_ptr->mac_tx_status.retry); mcps_data_conf_t confirm; - if (rf_ptr->fhss_api) { + 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) { @@ -1615,6 +1607,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m buffer->fcf_dsn.frameVersion = fcf->frameVersion; buffer->fcf_dsn.framePending = rf_ptr->mac_frame_pending; buffer->fcf_dsn.DSN = fcf->DSN; + buffer->fcf_dsn.intraPan = fcf->intraPan; buffer->fcf_dsn.sequenceNumberSuppress = fcf->sequenceNumberSuppress; buffer->fcf_dsn.DstPanPresents = fcf->DstPanPresents; buffer->fcf_dsn.SrcAddrMode = fcf->DstAddrMode; @@ -1628,9 +1621,8 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn); - buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr); - buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr); - + buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr, rf_ptr->pan_id); + buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr, rf_ptr->pan_id); mac_header_get_src_address(fcf, data_ptr, buffer->DstAddr); mac_header_get_dst_address(fcf, data_ptr, buffer->SrcAddr); @@ -1696,7 +1688,15 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m //Add MHR length to total length frame_length += buffer->mac_header_length_with_security + buffer->security_mic_len; - if ((frame_length) > dev_driver->phy_MTU - 2) { + uint16_t ack_mtu_size; + if (ENHANCED_ACK_MAX_LENGTH > dev_driver->phy_MTU) { + ack_mtu_size = dev_driver->phy_MTU; + } else { + ack_mtu_size = ENHANCED_ACK_MAX_LENGTH; + } + + + if ((frame_length) > ack_mtu_size - 2) { buffer->status = MLME_FRAME_TOO_LONG; if (buffer->fcf_dsn.securityEnabled) { @@ -1708,14 +1708,14 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m } rf_ptr->mac_tx_status.length = frame_length; - uint8_t *ptr = tx_buf->buf; + uint8_t *ptr = tx_buf->enhanced_ack_buf; if (dev_driver->phy_header_length) { ptr += dev_driver->phy_header_length; } - tx_buf->len = frame_length; + tx_buf->ack_len = frame_length; uint8_t *mhr_start = ptr; - buffer->tx_time = rx_time + 196; //Send 196 us later + buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later ptr = mac_generic_packet_write(rf_ptr, ptr, buffer); @@ -1731,9 +1731,9 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m csma_params.cca_enabled = false; rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t*) &csma_params); if (rf_ptr->active_pd_data_request) { + timer_mac_stop(rf_ptr); mac_pd_sap_set_phy_tx_time(rf_ptr, 0, false); } - return mcps_pd_data_cca_trig(rf_ptr, buffer); } @@ -1803,6 +1803,7 @@ static int8_t mcps_generic_packet_rebuild(protocol_interface_rf_mac_setup_s *rf_ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) { + platform_enter_critical(); mac_mlme_mac_radio_enable(rf_ptr); rf_ptr->macTxProcessActive = true; if (rf_ptr->rf_csma_extension_supported) { @@ -1810,18 +1811,35 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m bool cca_enabled; if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) { cca_enabled = false; + rf_ptr->mac_ack_tx_active = true; } else { + if (rf_ptr->mac_ack_tx_active) { + mac_csma_backoff_start(rf_ptr); + platform_exit_critical(); + return -1; + } cca_enabled = true; } mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled); if (mac_plme_cca_req(rf_ptr) != 0) { - rf_ptr->macTxProcessActive = false; - return -1; + if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) { + rf_ptr->mac_ack_tx_active = false; + // For Ack, stop the active TX process + rf_ptr->macTxProcessActive = false; + // If MAC had TX process active before Ack transmission, + // the TX process has to be restarted in case the Ack transmission failed. + if (rf_ptr->active_pd_data_request) { + mac_csma_backoff_start(rf_ptr); + } + platform_exit_critical(); + return -1; + } + mac_csma_backoff_start(rf_ptr); } } else { timer_mac_start(rf_ptr, MAC_TIMER_CCA, (uint16_t)(buffer->tx_time / 50)); } - + platform_exit_critical(); return 0; } @@ -1891,19 +1909,18 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup } } //Start TX process immediately - mac_data_request_init(rf_mac_setup, buffer); + rf_mac_setup->active_pd_data_request = buffer; if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) { - rf_mac_setup->active_pd_data_request = NULL; - mcps_data_conf_t confirm; - memset(&confirm, 0, sizeof(mcps_data_conf_t)); - confirm.msduHandle = buffer->msduHandle; - confirm.status = buffer->status; - bool requested_from_up = buffer->upper_layer_request; - mcps_sap_prebuild_frame_buffer_free(buffer); - if (requested_from_up) { - mcps_data_confirm_cb(rf_mac_setup, &confirm, NULL); + rf_mac_setup->mac_tx_result = MAC_TX_PRECOND_FAIL; + rf_mac_setup->macTxRequestAck = false; + if (mcps_sap_pd_confirm(rf_mac_setup) != 0) { + // can't send event, try calling error handler directly + rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = buffer->msduHandle; + rf_mac_setup->mac_mcps_data_conf_fail.status = buffer->status; + mcps_sap_prebuild_frame_buffer_free(buffer); + rf_mac_setup->active_pd_data_request = NULL; + mac_pd_data_confirm_failure_handle(rf_mac_setup); } - //Call } return; @@ -1981,7 +1998,7 @@ static mac_pre_build_frame_t * mcps_sap_pd_req_queue_read(protocol_interface_rf_ // With FHSS, check TX conditions if (rf_mac_setup->fhss_api) { while (buffer) { - if ((flush == true) || (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), + if (buffer->asynch_request || (flush == true) || (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), buffer->mac_payload_length, rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == true)) { break; @@ -2083,10 +2100,10 @@ int8_t mcps_sap_pd_ind(mac_pre_parsed_frame_t *buffer) return eventOS_event_send(&event); } -void mcps_sap_pd_confirm(void *mac_ptr) +int8_t mcps_sap_pd_confirm(void *mac_ptr) { if (mac_tasklet_event_handler < 0 || !mac_ptr) { - return; + return -2; } arm_event_s event = { .receiver = mac_tasklet_event_handler, @@ -2097,8 +2114,24 @@ void mcps_sap_pd_confirm(void *mac_ptr) .priority = ARM_LIB_HIGH_PRIORITY_EVENT, }; - eventOS_event_send(&event); + return eventOS_event_send(&event); +} +int8_t mcps_sap_pd_confirm_failure(void *mac_ptr) +{ + if (mac_tasklet_event_handler < 0 || !mac_ptr) { + return -2; + } + arm_event_s event = { + .receiver = mac_tasklet_event_handler, + .sender = 0, + .event_id = 0, + .data_ptr = mac_ptr, + .event_type = MCPS_SAP_DATA_CNF_FAIL_EVENT, + .priority = ARM_LIB_HIGH_PRIORITY_EVENT, + }; + + return eventOS_event_send(&event); } void mcps_sap_pd_ack(void *ack_ptr) @@ -2226,17 +2259,14 @@ static bool mcps_sap_purge_req_from_queue(protocol_interface_rf_mac_setup_s *rf_ uint8_t status = false; rf_mac_setup->pd_data_request_queue_to_go = mcps_sap_purge_from_list(rf_mac_setup->pd_data_request_queue_to_go, msduhandle, &status); - if (status) { - return true; + if (!status) { + rf_mac_setup->indirect_pd_data_request_queue = mcps_sap_purge_from_list(rf_mac_setup->indirect_pd_data_request_queue, msduhandle, &status); } - rf_mac_setup->indirect_pd_data_request_queue = mcps_sap_purge_from_list(rf_mac_setup->indirect_pd_data_request_queue, msduhandle, &status); - return status; - } -void mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_purge_t *purge_req) +uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_purge_t *purge_req) { mcps_purge_conf_t confirmation; confirmation.msduHandle = purge_req->msduHandle; @@ -2250,4 +2280,6 @@ void mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, if( get_sw_mac_api(rf_mac_setup) ) { get_sw_mac_api(rf_mac_setup)->purge_conf_cb(get_sw_mac_api(rf_mac_setup), &confirmation); } + + return confirmation.status; } diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 59d14cdbf76..2e88e69c53f 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -48,14 +48,14 @@ typedef enum { #define MAC_PD_DATA_MEDIUM_PRIORITY 1 //Indirect Data which is polled #define MAC_PD_DATA_HIGH_PRIOTITY 2 //Beacon request Beacon response -#define MCPS_SAP_DATA_IND_EVENT 1 -#define MCPS_SAP_DATA_CNF_EVENT 2 -#define MAC_MLME_EVENT_HANDLER 3 -#define MAC_MCPS_INDIRECT_TIMER_CB 4 -#define MAC_MLME_SCAN_CONFIRM_HANDLER 5 -#define MAC_SAP_TRIG_TX 6 -#define MCPS_SAP_DATA_ACK_CNF_EVENT 7 - +#define MCPS_SAP_DATA_IND_EVENT 1 +#define MCPS_SAP_DATA_CNF_EVENT 2 +#define MCPS_SAP_DATA_CNF_FAIL_EVENT 3 +#define MAC_MLME_EVENT_HANDLER 4 +#define MAC_MCPS_INDIRECT_TIMER_CB 5 +#define MAC_MLME_SCAN_CONFIRM_HANDLER 6 +#define MAC_SAP_TRIG_TX 7 +#define MCPS_SAP_DATA_ACK_CNF_EVENT 8 /** * @brief struct mac_aux_security_header_t MAC auxiliarity security header structure @@ -180,7 +180,9 @@ int8_t mcps_sap_pd_ind(mac_pre_parsed_frame_t *buffer); /** * MAC MCPS SAP layer data confirmation event trig */ -void mcps_sap_pd_confirm(void *mac_ptr); +int8_t mcps_sap_pd_confirm(void *mac_ptr); + +int8_t mcps_sap_pd_confirm_failure(void *mac_ptr); void mcps_sap_pd_ack(void *ack_ptr); @@ -200,7 +202,7 @@ int mac_convert_frame_type_to_fhss(uint8_t frame_type); void mcps_sap_trig_tx(void *mac_ptr); -void mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_purge_s *purge_req); +uint8_t mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_purge_s *purge_req); int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer); diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index bdf1c049690..51c63f329f0 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -85,7 +85,7 @@ static void mac_mlme_energy_scan_start(protocol_interface_rf_mac_setup_s *rf_mac rf_mac_setup->macRfRadioTxActive = false; } -uint16_t mlme_scan_analyze_next_channel(channel_list_s *mac_channel_list) +uint16_t mlme_scan_analyze_next_channel(channel_list_s *mac_channel_list, bool clear_channel) { uint8_t i, j = 0, k = 1; uint32_t mask = 1; @@ -101,7 +101,9 @@ uint16_t mlme_scan_analyze_next_channel(channel_list_s *mac_channel_list) { if (*channel_mask & mask) { - *channel_mask &= ~mask; + if (clear_channel) { + *channel_mask &= ~mask; + } return (i+j*32); } mask <<= 1; @@ -280,7 +282,7 @@ static void mac_mlme_scan_start(protocol_interface_rf_mac_setup_s *rf_mac_setup) { uint8_t channel; - channel = (uint8_t) mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list); + channel = (uint8_t) mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list, true); mac_mlme_scan_init(channel, rf_mac_setup); } @@ -400,14 +402,14 @@ int8_t mac_mlme_start_req(const mlme_start_t *s, struct protocol_interface_rf_ma tr_debug("MAC: Start network %u channel %x panid", s->LogicalChannel, s->PANId); mac_mlme_set_panid(rf_mac_setup, s->PANId); + // Synchronize FHSS if (rf_mac_setup->fhss_api) { - rf_mac_setup->fhss_api->synch_state_set(rf_mac_setup->fhss_api, FHSS_SYNCHRONIZED, s->PANId); - } - - if (!rf_mac_setup->fhss_api) { + rf_mac_setup->mac_channel = rf_mac_setup->fhss_api->synch_state_set(rf_mac_setup->fhss_api, FHSS_SYNCHRONIZED, s->PANId); + } else { rf_mac_setup->mac_channel = s->LogicalChannel; } + mac_mlme_start_request(rf_mac_setup); if (s->PANCoordinator) { //tr_debug("Cordinator"); @@ -795,7 +797,7 @@ static void mlme_scan_operation(protocol_interface_rf_mac_setup_s *rf_mac_setup) resp->ResultListSize++; } - channel = mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list); + channel = mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list, true); if (channel > 0xff || rf_mac_setup->mac_mlme_scan_resp->ResultListSize == MLME_MAC_RES_SIZE_MAX) { resp->status = MLME_SUCCESS; tr_debug("Scan Complete..Halt MAC"); @@ -981,6 +983,7 @@ void mac_mlme_data_base_deallocate(struct protocol_interface_rf_mac_setup *rf_ma eventOS_callback_timer_unregister(rf_mac->mac_mcps_timer); ns_dyn_mem_free(rf_mac->dev_driver_tx_buffer.buf); + ns_dyn_mem_free(rf_mac->dev_driver_tx_buffer.enhanced_ack_buf); ns_dyn_mem_free(rf_mac->mac_beacon_payload); mac_sec_mib_deinit(rf_mac); @@ -1510,8 +1513,9 @@ int8_t mac_mlme_rf_channel_change(protocol_interface_rf_mac_setup_s *rf_mac_setu return 0; } platform_enter_critical(); - rf_mac_setup->mac_channel = new_channel; - rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL, &rf_mac_setup->mac_channel); + if (rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL, &new_channel) == 0) { + rf_mac_setup->mac_channel = new_channel; + } platform_exit_critical(); return 0; } diff --git a/source/MAC/IEEE802_15_4/mac_mlme.h b/source/MAC/IEEE802_15_4/mac_mlme.h index 41f29601596..5878f702707 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.h +++ b/source/MAC/IEEE802_15_4/mac_mlme.h @@ -125,6 +125,6 @@ int8_t mac_mlme_beacon_tx(struct protocol_interface_rf_mac_setup *rf_ptr); uint8_t mac_mlme_beacon_req_tx(struct protocol_interface_rf_mac_setup *rf_ptr); int8_t mac_mlme_virtual_confirmation_handle(int8_t driver_id, const uint8_t *data_ptr, uint16_t length); -uint16_t mlme_scan_analyze_next_channel(struct channel_list_s *mac_channel_list); +uint16_t mlme_scan_analyze_next_channel(struct channel_list_s *mac_channel_list, bool clear_channel); #endif /* MAC_MLME_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 98586cf813a..8f71f73b309 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -38,8 +38,13 @@ /* Define TX Timeot Period */ // Hardcoded to 1200ms. Should be changed dynamic: (FHSS) channel retries needs longer timeout #define NWKTX_TIMEOUT_PERIOD (1200*20) +// Measured 3750us with 1280 byte secured packet from calculating TX time to starting CSMA timer on PHY. +// Typically varies from 500us to several milliseconds depending on packet size and the platform. +// MAC should learn and make this dynamic by sending first few packets with predefined CSMA period. +#define MIN_FHSS_CSMA_PERIOD_US 4000 static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry); +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr); void mac_csma_param_init(protocol_interface_rf_mac_setup_s *rf_mac_setup) { @@ -64,7 +69,7 @@ static uint16_t mac_csma_backoff_period_convert_to50us(uint8_t random, uint8_t b return (random * backoff_period_in_10us) / 5; } -static void mac_csma_backoff_start(protocol_interface_rf_mac_setup_s *rf_mac_setup) +void mac_csma_backoff_start(protocol_interface_rf_mac_setup_s *rf_mac_setup) { uint8_t backoff = mac_csma_random_backoff_get(rf_mac_setup); uint16_t backoff_slots = mac_csma_backoff_period_convert_to50us(backoff, rf_mac_setup->backoff_period_in_10us); @@ -90,6 +95,13 @@ uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (backoff_in_us == 0) { backoff_in_us = 1; } + if (rf_mac_setup->fhss_api) { + // Synchronization error when backoff time is shorter than allowed. + // TODO: Make this dynamic. + if (backoff_in_us < MIN_FHSS_CSMA_PERIOD_US) { + backoff_in_us += MIN_FHSS_CSMA_PERIOD_US; + } + } return backoff_in_us; } @@ -136,21 +148,31 @@ int8_t mac_plme_cca_req(protocol_interface_rf_mac_setup_s *rf_mac_setup) { dev_driver_tx_buffer_s *tx_buf = &rf_mac_setup->dev_driver_tx_buffer; phy_device_driver_s *dev_driver = rf_mac_setup->dev_driver->phy_driver; - + rf_mac_setup->macRfRadioTxActive = true; if (dev_driver->arm_net_virtual_tx_cb) { if (dev_driver->tx(tx_buf->buf, tx_buf->len, 1, PHY_LAYER_PAYLOAD) == 0) { - rf_mac_setup->macRfRadioTxActive = true; timer_mac_start(rf_mac_setup, MAC_TX_TIMEOUT, NWKTX_TIMEOUT_PERIOD); /*Start Timeout timer for virtual packet loss*/ } else { + rf_mac_setup->macRfRadioTxActive = false; mac_data_interface_tx_to_cb(rf_mac_setup); } return 0; } - if (dev_driver->tx(tx_buf->buf, tx_buf->len, 1, PHY_LAYER_PAYLOAD) == 0) { - rf_mac_setup->macRfRadioTxActive = true; + uint8_t *buffer; + uint16_t length; + if (rf_mac_setup->mac_ack_tx_active) { + buffer = tx_buf->enhanced_ack_buf; + length = tx_buf->ack_len; + } else { + buffer = tx_buf->buf; + length = tx_buf->len; + } + if (dev_driver->tx(buffer, length, 1, PHY_LAYER_PAYLOAD) == 0) { return 0; } + + rf_mac_setup->macRfRadioTxActive = false; return -1; } @@ -219,6 +241,12 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (rf_mac_setup->macUpState && rf_mac_setup->macTxProcessActive) { if (rf_mac_setup->mac_tx_result == MAC_TIMER_CCA) { + + if (rf_mac_setup->rf_csma_extension_supported) { + mac_sap_cca_fail_cb(rf_mac_setup); + return; + } + if (rf_mac_setup->fhss_api) { uint8_t *synch_info = NULL; mac_pre_build_frame_t *active_buf = rf_mac_setup->active_pd_data_request; @@ -254,6 +282,9 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (tx_handle_retval == -3) { mac_tx_done_state_set(rf_mac_setup, MAC_CCA_FAIL); return; + } else if (tx_handle_retval == -2) { + mac_tx_done_state_set(rf_mac_setup, MAC_UNKNOWN_DESTINATION); + return; } } if (mac_plme_cca_req(rf_mac_setup) != 0) { @@ -267,16 +298,24 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) } } -static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) { - rf_ptr->macRfRadioTxActive = false; - if (rf_ptr->mac_cca_retry > rf_ptr->macMaxCSMABackoffs || (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->asynch_request)) { - //Send MAC_CCA_FAIL - mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + if (rf_ptr->mac_ack_tx_active) { + if (rf_ptr->active_pd_data_request) { + mac_csma_backoff_start(rf_ptr); + } } else { - timer_mac_stop(rf_ptr); - mac_csma_BE_update(rf_ptr); - if (mcps_pd_data_rebuild(rf_ptr, rf_ptr->active_pd_data_request) ) { + + rf_ptr->macRfRadioTxActive = false; + if (rf_ptr->mac_cca_retry > rf_ptr->macMaxCSMABackoffs || (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->asynch_request)) { + //Send MAC_CCA_FAIL mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + } else { + timer_mac_stop(rf_ptr); + mac_csma_BE_update(rf_ptr); + if (mcps_pd_data_rebuild(rf_ptr, rf_ptr->active_pd_data_request) ) { + mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + } } } } @@ -322,6 +361,20 @@ static bool mac_data_counter_too_small(uint32_t current_counter, uint32_t packet } +static bool mac_data_asynch_channel_switch(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *active_buf) +{ + if (!active_buf || !active_buf->asynch_request) { + return false; + } + active_buf->asynch_channel = rf_ptr->mac_channel; //Store Original channel + uint16_t channel = mlme_scan_analyze_next_channel(&active_buf->asynch_channel_list, true); + if (channel <= 0xff) { + mac_mlme_rf_channel_change(rf_ptr, channel); + + } + return true; +} + static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry) { @@ -330,10 +383,16 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r } if (status == PHY_LINK_CCA_PREPARE) { + + if (rf_ptr->mac_ack_tx_active) { + return 0; + } + + if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request) ) { + return 0; + } + if (rf_ptr->fhss_api) { - if (rf_ptr->mac_ack_tx_active) { - return 0; - } mac_pre_build_frame_t *active_buf = rf_ptr->active_pd_data_request; if (!active_buf) { return -1; @@ -345,25 +404,28 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r uint8_t *synch_info = tx_buf->buf + rf_ptr->dev_driver->phy_driver->phy_header_length + tx_buf->len - FHSS_SYNCH_INFO_LENGTH; rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, synch_info, 0, FHSS_SYNCH_FRAME, 0); } - if (active_buf->asynch_request == false) { - // Change to destination channel and write synchronization info to Beacon frames here - int tx_handle_retval = rf_ptr->fhss_api->tx_handle(rf_ptr->fhss_api, !mac_is_ack_request_set(active_buf), - active_buf->DstAddr, mac_convert_frame_type_to_fhss(active_buf->fcf_dsn.frametype), - active_buf->mac_payload_length, rf_ptr->dev_driver->phy_driver->phy_header_length, - rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time); - // When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer - if (tx_handle_retval == -1) { - mac_sap_cca_fail_cb(rf_ptr); - return -2; - } - // When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back - // to queue by using CCA fail event - if (tx_handle_retval == -3) { - mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); - return -3; - } + + // Change to destination channel and write synchronization info to Beacon frames here + int tx_handle_retval = rf_ptr->fhss_api->tx_handle(rf_ptr->fhss_api, !mac_is_ack_request_set(active_buf), + active_buf->DstAddr, mac_convert_frame_type_to_fhss(active_buf->fcf_dsn.frametype), + active_buf->mac_payload_length, rf_ptr->dev_driver->phy_driver->phy_header_length, + rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time); + // When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer + if (tx_handle_retval == -1) { + mac_sap_cca_fail_cb(rf_ptr); + return -2; + } + // When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back + // to queue by using CCA fail event + if (tx_handle_retval == -3) { + mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + return -3; + } else if (tx_handle_retval == -2) { + mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION); + return -2; } } + return 0; } @@ -373,6 +435,10 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r if (rf_ptr->mac_ack_tx_active) { rf_ptr->mac_ack_tx_active = false; + if (rf_ptr->fhss_api) { + //SET tx completed false because ack isnot never queued + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0xff); + } if (rf_ptr->active_pd_data_request) { if (rf_ptr->active_pd_data_request->fcf_dsn.securityEnabled) { @@ -450,7 +516,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_parsed_frame_t *buf) { - if (!rf_ptr->macRfRadioTxActive) { + if (!rf_ptr->macRfRadioTxActive || !rf_ptr->active_pd_data_request || rf_ptr->active_pd_data_request->fcf_dsn.DSN != buf->fcf_dsn.DSN) { return -1; } @@ -465,9 +531,7 @@ static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_set mcps_sap_pd_ack(buf); if (rf_ptr->fhss_api) { - if (rf_ptr->active_pd_data_request->asynch_request == false) { - rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, true, rf_ptr->active_pd_data_request->msduHandle); - } + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, true, rf_ptr->active_pd_data_request->msduHandle); } return 0; } @@ -611,8 +675,6 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) if (mcps_generic_ack_build(rf_ptr, &fcf_read, pd_data_ind->data_ptr, &ack_payload, time_stamp) !=0) { return -1; } - - rf_ptr->mac_ack_tx_active = true; } } diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.h b/source/MAC/IEEE802_15_4/mac_pd_sap.h index f975f039522..d6364ba5274 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.h +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.h @@ -48,6 +48,8 @@ int8_t mac_pd_sap_data_cb(void *identifier, struct arm_phy_sap_msg_s *message); void mac_csma_param_init(struct protocol_interface_rf_mac_setup *rf_mac_setup); uint32_t mac_csma_backoff_get(struct protocol_interface_rf_mac_setup *rf_mac_setup); + +void mac_csma_backoff_start(struct protocol_interface_rf_mac_setup *rf_mac_setup); /** * Run Mac data interface state Machine. * diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 45fbfc2ca06..3c8dee0721c 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -54,7 +54,7 @@ static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication static void mlme_req(const mac_api_t* api, mlme_primitive id, const void *data); static void mcps_req(const mac_api_t* api, const mcps_data_req_t *data); static void mcps_req_ext(const mac_api_t* api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list); -static void purge_req(const mac_api_t* api, const mcps_purge_t *data); +static uint8_t purge_req(const mac_api_t* api, const mcps_purge_t *data); static int8_t macext_mac64_address_set( const mac_api_t* api, const uint8_t *mac64); static int8_t macext_mac64_address_get( const mac_api_t* api, mac_extended_address_type type, uint8_t *mac64_buf); @@ -176,6 +176,7 @@ int ns_sw_mac_fhss_register(mac_api_t *mac_api, fhss_api_t *fhss_api) fhss_callback_t callbacks; callbacks.read_tx_queue_size = &mac_read_tx_queue_sizes; callbacks.read_datarate = &mac_read_phy_datarate; + callbacks.read_timestamp = &mac_read_phy_timestamp; callbacks.read_mac_address = &mac_read_64bit_mac_address; callbacks.change_channel = &mac_set_channel; callbacks.send_fhss_frame = &mac_fhss_frame_tx; @@ -251,6 +252,22 @@ static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication cur->data_ind_ext_cb = data_ind_cb; cur->enhanced_ack_data_req_cb = ack_data_req_cb; if (data_cnf_cb && data_ind_cb && ack_data_req_cb) { + arm_device_driver_list_s *dev_driver = mac_store.setup->dev_driver; + ns_dyn_mem_free(mac_store.setup->dev_driver_tx_buffer.enhanced_ack_buf); + + uint16_t total_length; + if (ENHANCED_ACK_MAX_LENGTH > dev_driver->phy_driver->phy_MTU) { + total_length = dev_driver->phy_driver->phy_MTU; + } else { + total_length = ENHANCED_ACK_MAX_LENGTH; + } + + total_length += (dev_driver->phy_driver->phy_header_length + dev_driver->phy_driver->phy_tail_length); + mac_store.setup->dev_driver_tx_buffer.enhanced_ack_buf = ns_dyn_mem_alloc(total_length); + if (!mac_store.setup->dev_driver_tx_buffer.enhanced_ack_buf) { + return -2; + } + mac_store.setup->mac_extension_enabled = true; } else { mac_store.setup->mac_extension_enabled = false; @@ -509,11 +526,12 @@ void mcps_req_ext(const mac_api_t* api, const mcps_data_req_t *data, const mcps_ } -static void purge_req(const mac_api_t* api, const mcps_purge_t *data) +static uint8_t purge_req(const mac_api_t* api, const mcps_purge_t *data) { if (mac_store.mac_api == api) { - mcps_sap_purge_reg_handler(mac_store.setup , data ); + return mcps_sap_purge_reg_handler(mac_store.setup , data ); } + return MLME_INVALID_HANDLE; } static int8_t macext_mac64_address_set( const mac_api_t* api, const uint8_t *mac64) @@ -587,8 +605,7 @@ static int8_t sw_mac_net_phy_tx_done(int8_t driver_id, uint8_t tx_handle, phy_li phy_msg.message.mac15_4_pd_sap_confirm.cca_retry = cca_retry; phy_msg.message.mac15_4_pd_sap_confirm.tx_retry = tx_retry; - mac_pd_sap_data_cb(driver->phy_sap_identifier, &phy_msg); - return 0; + return mac_pd_sap_data_cb(driver->phy_sap_identifier, &phy_msg); } static void bc_enable_timer_cb(int8_t timer_id, uint16_t slots) diff --git a/source/MPL/mpl.c b/source/MPL/mpl.c index 13ad35e10e6..f1c809fb9dd 100644 --- a/source/MPL/mpl.c +++ b/source/MPL/mpl.c @@ -1011,17 +1011,41 @@ void mpl_clear_realm_scope_seeds(protocol_interface_info_entry_t *cur) static buffer_t *mpl_exthdr_provider(buffer_t *buf, ipv6_exthdr_stage_t stage, int16_t *result) { mpl_domain_t *domain = mpl_domain_lookup_with_realm_check(buf->interface, buf->dst_sa.address); - if (!domain) { - // We need to tunnel - if (stage != IPV6_EXTHDR_MODIFY) { - *result = 0; + /* Deal with simpler modify-already-created-header case first. Note that no error returns. */ + if (stage == IPV6_EXTHDR_MODIFY) { + if (!domain) { + *result = IPV6_EXTHDR_MODIFY_TUNNEL; + memcpy(buf->dst_sa.address, ADDR_ALL_MPL_FORWARDERS, 16); + buf->src_sa.addr_type = ADDR_NONE; // force auto-selection return buf; } - *result = IPV6_EXTHDR_MODIFY_TUNNEL; - memcpy(buf->dst_sa.address, ADDR_ALL_MPL_FORWARDERS, 16); - buf->src_sa.addr_type = ADDR_NONE; // force auto-selection + if (buf->options.ip_extflags & IPEXT_HBH_MPL_UNFILLED) { + /* We assume we created this, therefore our option is in place + * in the expected place. Sequence is set now, AFTER + * fragmentation. + */ + uint8_t *iphdr = buffer_data_pointer(buf); + uint8_t *ext = iphdr + IPV6_HDRLEN; + if (iphdr[IPV6_HDROFF_NH] != IPV6_NH_HOP_BY_HOP || ext[2] != IPV6_OPTION_MPL) { + tr_err("modify"); + return buffer_free(buf); + } + /* We don't bother setting the M flag on these initial packets. Setting to 0 is always acceptable. */ + ext[5] = domain->sequence++; + buf->options.ip_extflags &=~ IPEXT_HBH_MPL_UNFILLED; + buf->mpl_option_data_offset = IPV6_HDRLEN + 4; + mpl_forwarder_process_message(buf, domain, true); + } + *result = 0; + return buf; + } + + /* Rest of code deals with header insertion */ + if (!domain) { + // We will need to tunnel - do nothing on the inner packet + *result = 0; return buf; } @@ -1112,26 +1136,6 @@ static buffer_t *mpl_exthdr_provider(buffer_t *buf, ipv6_exthdr_stage_t stage, i buf->options.ip_extflags |= IPEXT_HBH_MPL | IPEXT_HBH_MPL_UNFILLED; return buf; } - case IPV6_EXTHDR_MODIFY: - if (buf->options.ip_extflags & IPEXT_HBH_MPL_UNFILLED) { - /* We assume we created this, therefore our option is in place - * in the expected place. Sequence is set now, AFTER - * fragmentation. - */ - uint8_t *iphdr = buffer_data_pointer(buf); - uint8_t *ext = iphdr + IPV6_HDRLEN; - if (iphdr[IPV6_HDROFF_NH] != IPV6_NH_HOP_BY_HOP || ext[2] != IPV6_OPTION_MPL) { - tr_err("modify"); - return buffer_free(buf); - } - /* We don't bother setting the M flag on these initial packets. Setting to 0 is always acceptable. */ - ext[5] = domain->sequence++; - buf->options.ip_extflags &=~ IPEXT_HBH_MPL_UNFILLED; - buf->mpl_option_data_offset = IPV6_HDRLEN + 4; - mpl_forwarder_process_message(buf, domain, true); - } - *result = 0; - return buf; default: return buffer_free(buf); } diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index e95865bfad7..8239bc0fdd2 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -348,9 +348,10 @@ void rpl_control_remove_domain_from_interface(protocol_interface_info_entry_t *c } } -void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, void *cb_handle) +void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, void *cb_handle) { domain->callback = callback; + domain->prefix_cb = prefix_learn_cb; domain->cb_handle = cb_handle; } @@ -677,28 +678,22 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t * const uint8_t *prefix = ptr + 16; if (!pref_parent || neighbour == pref_parent) { - //Check is L Flag active - if (flags & PIO_L) { - //define ONLink Route Information - //tr_debug("Register On Link Prefix to routing table"); - ipv6_route_add(prefix, prefix_len, cur->id, NULL, ROUTE_RADV, valid, 0); - } - /* Check if A-Flag. - * A RPL node may use this option for the purpose of Stateless Address Autoconfiguration (SLAAC) - * from a prefix advertised by a parent. - */ - if (pref_parent && (flags & PIO_A)) { - if (icmpv6_slaac_prefix_update(cur, prefix, prefix_len, valid, preferred) != 0) { - ipv6_interface_slaac_handler(cur, prefix, prefix_len, valid, preferred); - } - } /* Store prefixes for possible forwarding */ /* XXX if leaf - don't bother? Or do we want to remember them for * when we switch DODAG, as mentioned above? */ - rpl_dodag_update_dio_prefix(dodag, prefix, prefix_len, flags, valid, preferred, false, true); + prefix_entry_t *prefix_entry = rpl_dodag_update_dio_prefix(dodag, prefix, prefix_len, flags, valid, preferred, false, true); + if (prefix_entry && pref_parent) { + rpl_control_process_prefix_option(prefix_entry, cur); + rpl_domain_t *domain = cur->rpl_domain; + if (domain && domain->prefix_cb) { + uint8_t ll_address[16]; + memcpy(ll_address, rpl_neighbour_ll_address(pref_parent), 16); + domain->prefix_cb(prefix_entry, domain->cb_handle,ll_address); + } + } } if ((flags & PIO_R) && !router_addr_set) { @@ -715,6 +710,18 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t * } } +void rpl_control_process_prefix_option(prefix_entry_t *prefix, protocol_interface_info_entry_t *cur) +{ + //Check is L Flag active + if (prefix->options & PIO_L) { + //define ONLink Route Information + //tr_debug("Register On Link Prefix to routing table"); + ipv6_route_add(prefix->prefix, prefix->prefix_len, cur->id, NULL, ROUTE_RADV, prefix->lifetime, 0); + } + +} + + /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -1004,7 +1011,7 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r rpl_instance_consistent_rx(instance); } - rpl_instance_neighbours_changed(instance); + rpl_instance_neighbours_changed(instance, dodag); return buffer_free(buf); diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 72f77885514..c924750d796 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -29,15 +29,19 @@ struct rpl_dodag; struct buffer; struct protocol_interface_info_entry; struct rpl_dodag_info_t; +struct prefix_entry_t; typedef enum rpl_event { RPL_EVENT_DAO_DONE, /* Simplistic trigger for bootstrap advance - a DAO registration completed */ RPL_EVENT_LOCAL_REPAIR_START, /* RPL start scanning new parent by multicast DIS user can disable beacon request responser here*/ RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS, /* RPL not sending DIS anymore user can report bootstrap error */ + RPL_EVENT_DAO_PARENT_SWITCH, /* RPL indicate that DAO downward Parent state have been updated */ } rpl_event_t; 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 struct rpl_domain { NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances; @@ -50,6 +54,7 @@ typedef struct rpl_domain /* As part of shutdown, we can force entering leaf mode */ bool force_leaf; rpl_domain_callback_t *callback; + rpl_prefix_callback_t *prefix_cb; void *cb_handle; } rpl_domain_t; @@ -100,6 +105,7 @@ void rpl_control_transmit_dio(struct rpl_domain *domain, struct protocol_interfa bool rpl_control_transmit_dao(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, struct rpl_instance *instance, uint8_t instance_id, uint8_t dao_sequence, const uint8_t dodagid[16], const uint8_t *opts, uint16_t opts_size, const uint8_t *dst); void rpl_control_disable_ra_routes(struct rpl_domain *domain); void rpl_control_event(struct rpl_domain *domain, rpl_event_t event); +void rpl_control_process_prefix_option(struct prefix_entry_t *prefix, struct protocol_interface_info_entry *cur); /*********************** RPL control API to rest of system *******************/ @@ -138,7 +144,7 @@ rpl_domain_t *rpl_control_create_domain(void); 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_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, void *cb_handle); +void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, void *cb_handle); /* Target publishing */ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime); @@ -160,7 +166,6 @@ const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_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); - #else /* HAVE_RPL */ #define rpl_control_fast_timer(ticks) ((void) 0) diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 8e040e5c67e..d99c3e1c2fe 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -243,6 +243,8 @@ void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance) } } } + //GENERATE PARENT Update event + rpl_control_event(instance->domain, RPL_EVENT_DAO_PARENT_SWITCH); rpl_instance_dao_trigger(instance, 0); } } @@ -588,7 +590,7 @@ void rpl_instance_send_address_registration(protocol_interface_info_entry_t *int aro.status = ARO_SUCCESS; aro.present = true; - aro.lifetime = addr->preferred_lifetime; + aro.lifetime = addr->valid_lifetime; memcpy(aro.eui64, interface->mac, 8); // go through neighbour list, and send to all assigned parents. diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index 0e518d029f9..4210442fdf8 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -134,6 +134,7 @@ typedef struct rpl_dao_non_root uint32_t refresh_timer; /* Refresh timer (seconds) - 0xFFFFFFFF = infinite, 0 = not yet set */ } rpl_dao_non_root_t; + /* Descriptor for a RPL DAO target */ struct rpl_dao_target { diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index 126e195312e..fdc5f341bd4 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -427,7 +427,7 @@ void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour) } if (neighbour->dodag_parent) { rpl_instance_remove_system_routes_through_parent(instance, neighbour); - rpl_instance_neighbours_changed(instance); + rpl_instance_neighbours_changed(instance, NULL); } rpl_free(neighbour, sizeof *neighbour); @@ -1171,13 +1171,18 @@ bool rpl_instance_purge(rpl_instance_t *instance) return false; } -void rpl_instance_neighbours_changed(rpl_instance_t *instance) +void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag) { instance->neighbours_changed = true; - if (!rpl_instance_preferred_parent(instance)) { - rpl_instance_set_local_repair(instance, 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, rpl_policy_dio_parent_selection_delay(instance->domain)); + rpl_instance_trigger_parent_selection(instance, delay); } static void rpl_instance_remove_parents(rpl_instance_t *instance) @@ -1366,7 +1371,18 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) } } - rpl_instance_set_local_repair(instance, preferred_parent == NULL); + //Control Local repair state + if (preferred_parent) { + // Always stop repair if we find a parent + rpl_instance_set_local_repair(instance, false); + } else if (original_preferred) { + // Only start repair if we just lost a parent + rpl_instance_set_local_repair(instance, true); + } else { + // !preferred_parent && !original_preferred - didn't have a parent, + // still don't. Leave repair flag as-is (would be off on initial start + // up, may be on if having problems mid-session). + } if (rpl_instance_mop(instance) != RPL_MODE_NO_DOWNWARD) { rpl_downward_process_dao_parent_changes(instance); @@ -1384,6 +1400,20 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) rpl_control_print(trace_info_print); /* Changing DODAG version is an inconsistency */ if (original_version != instance->current_dodag_version) { + //learn Routes an Prefixes + if (preferred_parent && instance->current_dodag_version) { + rpl_dodag_t *dodag = instance->current_dodag_version->dodag; + protocol_interface_info_entry_t *rpl_interface = protocol_stack_interface_info_get_by_id(preferred_parent->interface_id); + if (rpl_interface) { + ns_list_foreach(prefix_entry_t, prefix, &dodag->prefixes) { + rpl_control_process_prefix_option(prefix, rpl_interface); + if (instance->domain->prefix_cb) { + instance->domain->prefix_cb(prefix, rpl_interface, preferred_parent->ll_address); + } + } + } + } + rpl_instance_inconsistency(instance); return; } @@ -1536,6 +1566,7 @@ void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds) } } + void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) { rpl_dodag_version_t *dodag_version = instance->current_dodag_version; diff --git a/source/RPL/rpl_upward.h b/source/RPL/rpl_upward.h index 1718d753739..1225e285495 100644 --- a/source/RPL/rpl_upward.h +++ b/source/RPL/rpl_upward.h @@ -135,7 +135,7 @@ void rpl_neighbour_update_dodag_version(rpl_neighbour_t *neighbour, rpl_dodag_ve 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); +void rpl_instance_neighbours_changed(rpl_instance_t *instance, const 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); diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 981ab71ad8e..084ffaafed6 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -81,6 +81,9 @@ 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++; + } accumulated_failures = entry->accumulated_failures; diff --git a/source/Service_Libs/etx/etx.h b/source/Service_Libs/etx/etx.h index 12b1ee6117c..a0216b4a382 100644 --- a/source/Service_Libs/etx/etx.h +++ b/source/Service_Libs/etx/etx.h @@ -38,6 +38,7 @@ typedef struct etx_storage_s { unsigned accumulated_failures: 5; unsigned tmp_etx: 1; unsigned linkIdr: 4; + unsigned etx_samples: 3; } etx_storage_t; /** diff --git a/source/Service_Libs/fhss/channel_functions.h b/source/Service_Libs/fhss/channel_functions.h index 990a7ac90e6..f6ceab73bb8 100644 --- a/source/Service_Libs/fhss/channel_functions.h +++ b/source/Service_Libs/fhss/channel_functions.h @@ -17,25 +17,44 @@ #ifndef CHANNEL_FUNC_H_ #define CHANNEL_FUNC_H_ +/** + * @brief Function calculates nearest (higher) prime number for given start value. + * @param start_value Start value. + * @return Calculated prime number. + */ +uint16_t tr51_calc_nearest_prime_number(uint16_t start_value); + +/** + * @brief Initialize channel table for TR51 channel function. + * @param channel_table Channel table to be initialized. + * @param number_of_channels Number of channels. + * @return 0 Success, -1 Failure. + */ +int tr51_init_channel_table(int16_t *channel_table, int16_t number_of_channels); + /** * @brief Compute the unicast schedule channel index using tr51 channel function. + * @param channel_table Channel table. + * @param output_table Table used to generate output channel. * @param slot_number Current slot number. * @param mac MAC address of the node for which the index is calculated. * @param number_of_channels Number of channels. * @param excluded_channels Excluded channels. * @return Channel index. */ -int32_t tr51_get_uc_channel_index(uint16_t slot_number, uint8_t *mac, int16_t number_of_channels, uint32_t *excluded_channels); +int32_t tr51_get_uc_channel_index(int16_t *channel_table, uint8_t *output_table, uint16_t slot_number, uint8_t *mac, int16_t number_of_channels, uint32_t *excluded_channels); /** * @brief Compute the broadcast schedule channel index using tr51 channel function. + * @param channel_table Channel table. + * @param output_table Table used to generate output channel. * @param slot_number Current slot number. * @param bsi Broadcast schedule identifier of the node for which the index is calculated. * @param number_of_channels Number of channels. * @param excluded_channels Excluded channels. * @return Channel index. */ -int32_t tr51_get_bc_channel_index(uint16_t slot_number, uint16_t bsi, int16_t number_of_channels, uint32_t *excluded_channels); +int32_t tr51_get_bc_channel_index(int16_t *channel_table, uint8_t *output_table, uint16_t slot_number, uint16_t bsi, int16_t number_of_channels, uint32_t *excluded_channels); /** * @brief Compute the unicast schedule channel index using direct hash channel function. diff --git a/source/Service_Libs/fhss/channel_list.c b/source/Service_Libs/fhss/channel_list.c index 7d22696bd95..eab1e85c65d 100644 --- a/source/Service_Libs/fhss/channel_list.c +++ b/source/Service_Libs/fhss/channel_list.c @@ -88,6 +88,19 @@ uint8_t channel_list_get_channel(const uint32_t* list, int current_index) return found_index; } +void channel_list_set_channel(uint32_t* list, int channel, bool active) +{ + if (channel >= CHANNEL_LIST_SIZE_IN_BITS) { + return; + } + if (active) { + list[channel/32] |= (1 << channel % 32); + } else { + list[channel/32] &= ~(1 << channel % 32); + } + return; +} + // count the amount of channels enabled in a list int channel_list_count_channels(const uint32_t* list) { diff --git a/source/Service_Libs/fhss/channel_list.h b/source/Service_Libs/fhss/channel_list.h index 5e3a2139e0d..65a16c68089 100644 --- a/source/Service_Libs/fhss/channel_list.h +++ b/source/Service_Libs/fhss/channel_list.h @@ -31,6 +31,16 @@ extern "C" { * @return channel number */ uint8_t channel_list_get_channel(const uint32_t* list, int current_index); +/** + * set matching bit on in in channel mask. + * + * @param list channel mask + * @param channel channel number + * @param active set the channel on if true, disable channel if false. + * + * @return channel number + */ +void channel_list_set_channel(uint32_t* list, int channel, bool active); /** * Count the amount of channels enabled in a list. diff --git a/source/Service_Libs/fhss/fhss.c b/source/Service_Libs/fhss/fhss.c index 5e898153a46..bf4e763b038 100644 --- a/source/Service_Libs/fhss/fhss.c +++ b/source/Service_Libs/fhss/fhss.c @@ -34,6 +34,7 @@ #define TRACE_GROUP "fhss" +static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots); static int fhss_reset(fhss_structure_t *fhss_structure); static bool fhss_is_bc_sending_superframe(fhss_structure_t *fhss_structure); static bool fhss_check_remaining_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length); @@ -67,6 +68,7 @@ fhss_structure_t *fhss_enable(fhss_api_t *fhss_api, const fhss_configuration_t * } memset(fhss_struct->bs, 0, sizeof(fhss_bs_t)); + fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); fhss_struct->bs->fhss_configuration = *fhss_configuration; fhss_struct->bs->fhss_stats_ptr = fhss_statistics; fhss_struct->number_of_channels = channel_count; @@ -99,6 +101,15 @@ bool fhss_is_synch_root(fhss_structure_t *fhss_structure) return true; } +static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) +{ + (void) slots; + fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id); + if (fhss_structure) { + fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); + } +} + static bool fhss_is_bc_sending_superframe(fhss_structure_t *fhss_structure) { if (fhss_structure->bs->current_superframe >= fhss_structure->bs->broadcast_start_superframe) { @@ -689,16 +700,16 @@ static void fhss_update_beacon_info_lifetimes(fhss_structure_t *fhss_structure, } } -static void fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id) +static int16_t fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id) { fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); if (!fhss_structure) { - return; + return -1; } // State is already set if (fhss_structure->fhss_state == fhss_state) { tr_debug("Synch same state %u", fhss_state); - return; + return -1; } if (fhss_state == FHSS_UNSYNCHRONIZED) { @@ -712,7 +723,7 @@ static void fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states fhs // Do not synchronize to current pan if (fhss_structure->bs->synch_panid == pan_id) { tr_debug("Synch same panid %u", pan_id); - return; + return -1; } fhss_generate_scramble_table(fhss_structure); @@ -737,11 +748,11 @@ static void fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states fhs fhss_start_timer(fhss_structure, fhss_structure->bs->synch_configuration.fhss_superframe_length, fhss_superframe_handler); } else { tr_error("Synch info not found"); - return; + return -1; } } fhss_structure->fhss_state = fhss_state; - return; + return fhss_structure->rx_channel; } static void fhss_beacon_decode_raw(fhss_synchronization_beacon_payload_s* dest, const uint8_t* buffer) diff --git a/source/Service_Libs/fhss/fhss_common.c b/source/Service_Libs/fhss/fhss_common.c index 592a0b557da..583f87e241d 100644 --- a/source/Service_Libs/fhss/fhss_common.c +++ b/source/Service_Libs/fhss/fhss_common.c @@ -34,8 +34,6 @@ static fhss_structure_t *fhss_struct = NULL; -static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots); -static fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id); static void fhss_set_active_event(fhss_structure_t *fhss_structure, uint8_t event_type); static bool fhss_read_active_event(fhss_structure_t *fhss_structure, uint8_t event_type); @@ -52,7 +50,6 @@ fhss_structure_t *fhss_allocate_instance(fhss_api_t *fhss_api, const fhss_timer_ memset(fhss_struct, 0, sizeof(fhss_structure_t)); fhss_struct->fhss_api = fhss_api; fhss_struct->platform_functions = *fhss_timer; - fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); if (!fhss_struct->platform_functions.fhss_resolution_divider) { fhss_struct->platform_functions.fhss_resolution_divider = 1; } @@ -69,16 +66,7 @@ int8_t fhss_free_instance(fhss_api_t *fhss_api) return 0; } -static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) -{ - (void) slots; - fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id); - if (fhss_structure) { - fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); - } -} - -static fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id) +fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id) { if (timer_id < 0 || !fhss_struct) { return NULL; @@ -142,6 +130,13 @@ void fhss_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*ca } } +void fhss_stop_timer(fhss_structure_t *fhss_structure, void (*callback)(const fhss_api_t *fhss_api, uint16_t)) +{ + if (callback){ + fhss_structure->platform_functions.fhss_timer_stop(callback, fhss_structure->fhss_api); + } +} + int fhss_timeout_start(fhss_structure_t *fhss_structure, uint32_t time) { if (!fhss_structure) { diff --git a/source/Service_Libs/fhss/fhss_common.h b/source/Service_Libs/fhss/fhss_common.h index 144e089019a..1c635d2062d 100644 --- a/source/Service_Libs/fhss/fhss_common.h +++ b/source/Service_Libs/fhss/fhss_common.h @@ -54,6 +54,7 @@ struct fhss_structure uint8_t synch_parent[8]; }; +fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id); fhss_structure_t *fhss_allocate_instance(fhss_api_t *fhss_api, const fhss_timer_t *fhss_timer); int8_t fhss_free_instance(fhss_api_t *fhss_api); int8_t fhss_set_datarate(fhss_structure_t *fhss_structure, uint32_t datarate); @@ -61,6 +62,7 @@ fhss_structure_t *fhss_get_object_with_api(const fhss_api_t *fhss_api); void fhss_clear_active_event(fhss_structure_t *fhss_structure, uint8_t event_type); int8_t fhss_disable(fhss_structure_t *fhss_structure); void fhss_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*callback)(const fhss_api_t *fhss_api, uint16_t)); +void fhss_stop_timer(fhss_structure_t *fhss_structure, void (*callback)(const fhss_api_t *fhss_api, uint16_t)); int fhss_timeout_start(fhss_structure_t *fhss_structure, uint32_t time); int fhss_timeout_stop(fhss_structure_t *fhss_structure); int fhss_update_synch_parent_address(fhss_structure_t *fhss_structure); diff --git a/source/Service_Libs/fhss/fhss_configuration_interface.c b/source/Service_Libs/fhss/fhss_configuration_interface.c index 0c7567e5169..c1acfc38ac3 100644 --- a/source/Service_Libs/fhss/fhss_configuration_interface.c +++ b/source/Service_Libs/fhss/fhss_configuration_interface.c @@ -62,13 +62,13 @@ fhss_api_t *ns_fhss_ws_create(const fhss_ws_configuration_t *fhss_configuration, return this; } -int ns_fhss_ws_set_parent(const fhss_api_t *fhss_api, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info) +int ns_fhss_ws_set_parent(const fhss_api_t *fhss_api, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info, const bool force_synch) { fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); if (!fhss_structure || !eui64 || !bc_timing_info) { return -1; } - return fhss_ws_set_parent(fhss_structure, eui64, bc_timing_info); + return fhss_ws_set_parent(fhss_structure, eui64, bc_timing_info, force_synch); } int ns_fhss_ws_remove_parent(const fhss_api_t *fhss_api, const uint8_t eui64[8]) diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index 03befff9f8f..cf4af1040cb 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -23,6 +23,8 @@ #define WS_NUMBER_OF_CHANNEL_RETRIES 4 //TX/RX slot length in milliseconds #define WS_MAX_TXRX_SLOT_LEN_MS 100 +// Default minimum broadcast synchronization interval in seconds +#define DEFAULT_MIN_SYNCH_INTERVAL 60 typedef struct fhss_ws fhss_ws_t; struct fhss_ws @@ -30,6 +32,12 @@ struct fhss_ws uint8_t bc_channel; uint16_t uc_slot; uint16_t bc_slot; + uint16_t min_synch_interval; + uint32_t txrx_slot_length_ms; + uint32_t synchronization_time; + int16_t *tr51_channel_table; + uint8_t *tr51_output_table; + bool unicast_timer_running; bool is_on_bc_channel; struct fhss_ws_configuration fhss_configuration; const struct broadcast_timing_info *parent_bc_info; @@ -38,7 +46,7 @@ struct fhss_ws fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer); int fhss_ws_set_callbacks(fhss_structure_t *fhss_structure); -int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info); +int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info, const bool force_synch); 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); diff --git a/source/Service_Libs/fhss/fhss_ws_empty_functions.c b/source/Service_Libs/fhss/fhss_ws_empty_functions.c index df6bc4813cf..07597662f93 100644 --- a/source/Service_Libs/fhss/fhss_ws_empty_functions.c +++ b/source/Service_Libs/fhss/fhss_ws_empty_functions.c @@ -46,7 +46,7 @@ int fhss_ws_set_callbacks(fhss_structure_t *fhss_structure) return -1; } -int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info) +int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info, const bool force_synch) { (void) fhss_structure; (void) eui64; diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c index 6b1e548212c..60352bec4fd 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c @@ -192,6 +192,9 @@ void mac_neighbor_table_neighbor_connected(mac_neighbor_table_t *table_class, ma void mac_neighbor_table_trusted_neighbor(mac_neighbor_table_t *table_class, mac_neighbor_table_entry_t *neighbor_entry, bool trusted_device) { (void)table_class; + if (!neighbor_entry->trusted_device && trusted_device) { + neighbor_entry->lifetime = neighbor_entry->link_lifetime; + } neighbor_entry->trusted_device = trusted_device; } @@ -271,4 +274,13 @@ mac_neighbor_table_entry_t *mac_neighbor_entry_get_by_mac64(mac_neighbor_table_t return mac_neighbor_table_entry_allocate(table_class, mac64); } +mac_neighbor_table_entry_t* mac_neighbor_entry_get_priority(mac_neighbor_table_t *table_class) +{ + ns_list_foreach(mac_neighbor_table_entry_t, entry, &table_class->neighbour_list) { + if (entry->link_role == PRIORITY_PARENT_NEIGHBOUR) { + return entry; + } + } + return NULL; +} diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.h b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.h index edd10a974d9..c2bd7ef4f7a 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.h +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.h @@ -202,4 +202,6 @@ mac_neighbor_table_entry_t *mac_neighbor_entry_get_by_ll64(mac_neighbor_table_t mac_neighbor_table_entry_t *mac_neighbor_entry_get_by_mac64(mac_neighbor_table_t *table_class, const uint8_t *mac64, bool allocateNew, bool *new_entry_allocated); +mac_neighbor_table_entry_t* mac_neighbor_entry_get_priority(mac_neighbor_table_t *table_class); + #endif /* MAC_NEIGHBOR_TABLE_H_ */ diff --git a/source/Service_Libs/mdns/ns_fnet_port.c b/source/Service_Libs/mdns/ns_fnet_port.c index 63e904b1911..346f6f3f8b4 100644 --- a/source/Service_Libs/mdns/ns_fnet_port.c +++ b/source/Service_Libs/mdns/ns_fnet_port.c @@ -72,10 +72,9 @@ fnet_bool_t fnet_netif_get_ip6_addr (fnet_netif_desc_t netif_desc, fnet_index_t addr_info->type = FNET_NETIF_IP_ADDR_TYPE_AUTOCONFIGURABLE; /* How the address was acquired.*/ result = FNET_TRUE; } + FNET_DEBUG("fnet_netif_get_ip6_addr(), if=%d: %s", (int8_t)netif->scope_id, trace_ipv6(addr_info->address.addr)); } - FNET_DEBUG("fnet_netif_get_ip6_addr(), if=%d: %s", (int8_t)netif->scope_id, trace_ipv6(addr_info->address.addr)); - return result; } diff --git a/source/ipv6_stack/ipv6_routing_table.c b/source/ipv6_stack/ipv6_routing_table.c index 0b47ed5b72c..484a41097b6 100644 --- a/source/ipv6_stack/ipv6_routing_table.c +++ b/source/ipv6_stack/ipv6_routing_table.c @@ -1589,6 +1589,7 @@ ipv6_route_t *ipv6_route_add_metric(const uint8_t *prefix, uint8_t prefix_len, i route->metric = metric; changed_info = UPDATED; } + } if (changed_info != UNCHANGED) { diff --git a/source/ipv6_stack/protocol_ipv6.c b/source/ipv6_stack/protocol_ipv6.c index 7f01fbbe51f..59394310443 100644 --- a/source/ipv6_stack/protocol_ipv6.c +++ b/source/ipv6_stack/protocol_ipv6.c @@ -394,14 +394,14 @@ void ipv6_stack_route_advert_update(uint8_t *address, uint8_t prefixLength, uint return; } + if (addr_interface_gp_prefix_compare(cur, address) == 0) { + return; + } - - if (addr_interface_gp_prefix_compare(cur, address) != 0) { - ns_list_foreach(ipv6_interface_route_on_link_t, cur_prefix, &route_on_link) { - if ((cur_prefix->prefix_len == prefixLength) && bitsequal(cur_prefix->prefix, address, prefixLength)) { - cur_prefix->routePrefer = routePrefer; - return; - } + ns_list_foreach(ipv6_interface_route_on_link_t, cur_prefix, &route_on_link) { + if ((cur_prefix->prefix_len == prefixLength) && bitsequal(cur_prefix->prefix, address, prefixLength)) { + cur_prefix->routePrefer = routePrefer; + return; } } diff --git a/source/libDHCPv6/dhcp_service_api.c b/source/libDHCPv6/dhcp_service_api.c index 3027046fcc8..c000b581e17 100644 --- a/source/libDHCPv6/dhcp_service_api.c +++ b/source/libDHCPv6/dhcp_service_api.c @@ -53,6 +53,16 @@ typedef struct { } server_instance_t; typedef NS_LIST_HEAD(server_instance_t, link) server_instance_list_t; + +typedef struct { + uint16_t instance_id; + int8_t interface_id; + uint8_t server_address[16]; + bool relay_activated; + ns_list_link_t link; +} relay_instance_t; +typedef NS_LIST_HEAD(relay_instance_t, link) relay_instance_list_t; + typedef struct { ns_address_t addr; dhcp_service_receive_resp_cb *recv_resp_cb; @@ -71,6 +81,7 @@ typedef struct { uint8_t retrans; uint8_t *msg_ptr; uint16_t msg_len; + uint8_t *relay_start; ns_list_link_t link; } msg_tr_t; typedef NS_LIST_HEAD(msg_tr_t, link) tr_list_t; @@ -78,9 +89,11 @@ typedef NS_LIST_HEAD(msg_tr_t, link) tr_list_t; typedef struct { ns_address_t src_address; server_instance_list_t srv_list; + relay_instance_list_t relay_list; tr_list_t tr_list; int8_t dhcp_server_socket; int8_t dhcp_client_socket; + int8_t dhcp_relay_socket; int8_t dhcpv6_socket_service_tasklet; } dhcp_service_class_t; @@ -120,9 +133,11 @@ bool dhcp_service_allocate(void) dhcp_service = ns_dyn_mem_alloc(sizeof(dhcp_service_class_t)); if (dhcp_service) { ns_list_init(&dhcp_service->srv_list); + ns_list_init(&dhcp_service->relay_list); ns_list_init(&dhcp_service->tr_list); dhcp_service->dhcp_client_socket = -1; dhcp_service->dhcp_server_socket = -1; + dhcp_service->dhcp_relay_socket = -1; dhcp_service->dhcpv6_socket_service_tasklet = eventOS_event_handler_create(DHCPv6_socket_service_tasklet, DHCPV6_SOCKET_SERVICE_TASKLET_INIT); if (dhcp_service->dhcpv6_socket_service_tasklet < 0) { ns_dyn_mem_free(dhcp_service); @@ -229,13 +244,50 @@ server_instance_t *dhcp_service_client_find(uint16_t instance_id) } +static uint16_t dhcp_service_relay_interface_get(int8_t interface_id) +{ + ns_list_foreach(server_instance_t, cur_ptr, &dhcp_service->srv_list) { + if (cur_ptr->interface_id == interface_id && cur_ptr->instance_type == DHCP_INTANCE_RELAY_AGENT) { + return cur_ptr->instance_id; + } + } + + return 0; +} + + + +static relay_instance_t *dhcp_service_relay_find(uint16_t instance_id) +{ + relay_instance_t *result = NULL; + ns_list_foreach(relay_instance_t, cur_ptr, &dhcp_service->relay_list) { + if (cur_ptr->instance_id == instance_id) { + result = cur_ptr; + } + } + return result; +} + +static relay_instance_t *dhcp_service_relay_interface(int8_t interface_id) +{ + relay_instance_t *result = NULL; + ns_list_foreach(relay_instance_t, cur_ptr, &dhcp_service->relay_list) { + if (cur_ptr->interface_id == interface_id) { + result = cur_ptr; + } + } + return result; +} + + void recv_dhcp_server_msg(void *cb_res) { socket_callback_t *sckt_data; server_instance_t *srv_ptr = NULL; msg_tr_t *msg_tr_ptr; - uint8_t *msg_ptr; + uint8_t *msg_ptr, *allocated_ptr; uint16_t msg_len; + dhcpv6_relay_msg_t relay_msg; sckt_data = cb_res; @@ -245,12 +297,33 @@ void recv_dhcp_server_msg(void *cb_res) tr_debug("dhcp Server recv request"); msg_tr_ptr = dhcp_tr_create(); msg_ptr = ns_dyn_mem_temporary_alloc(sckt_data->d_len); + allocated_ptr = msg_ptr; if (msg_ptr == NULL || msg_tr_ptr == NULL) { // read actual message tr_error("Out of resources"); goto cleanup; } msg_len = socket_read(sckt_data->socket_id, &msg_tr_ptr->addr, msg_ptr, sckt_data->d_len); + + uint8_t msg_type = *msg_ptr; + if (msg_type == DHCPV6_RELAY_FORWARD) { + if ( !libdhcpv6_relay_msg_read(msg_ptr, msg_len, &relay_msg) ) { + tr_error("Relay forward not correct"); + goto cleanup; + } + //Update Source and data + msg_tr_ptr->relay_start = msg_ptr; + memcpy(msg_tr_ptr->addr.address,relay_msg.peer_address , 16); + msg_ptr = relay_msg.relay_options.msg_ptr; + msg_len = relay_msg.relay_options.len; + msg_type = *msg_ptr; + + + } else if (msg_type == DHCPV6_RELAY_REPLY) { + tr_error("Relay reply drop at server"); + goto cleanup; + } + //TODO use real function from lib also call validity check msg_tr_ptr->message_tr_id = common_read_24_bit(&msg_ptr[1]); @@ -265,7 +338,7 @@ void recv_dhcp_server_msg(void *cb_res) msg_tr_ptr->instance_id = cur_ptr->instance_id; msg_tr_ptr->interface_id = sckt_data->interface_id; if ((RET_MSG_ACCEPTED == - cur_ptr->recv_req_cb(cur_ptr->instance_id, msg_tr_ptr->msg_tr_id, *msg_ptr, msg_ptr + 4, msg_len - 4))) { + cur_ptr->recv_req_cb(cur_ptr->instance_id, msg_tr_ptr->msg_tr_id, msg_type, msg_ptr + 4, msg_len - 4))) { // should not modify pointers but library requires. msg_tr_ptr = NULL; srv_ptr = cur_ptr; @@ -276,7 +349,7 @@ void recv_dhcp_server_msg(void *cb_res) cleanup: dhcp_tr_delete(msg_tr_ptr); - ns_dyn_mem_free(msg_ptr); + ns_dyn_mem_free(allocated_ptr); if (srv_ptr == NULL) { //no owner found tr_warn("No handler for this message found"); @@ -285,6 +358,118 @@ void recv_dhcp_server_msg(void *cb_res) return; } +void recv_dhcp_relay_msg(void *cb_res) +{ + socket_callback_t *sckt_data; + uint16_t msg_len; + + sckt_data = cb_res; + + if (sckt_data->event_type != SOCKET_DATA || sckt_data->d_len < 4) { + return; + } + + protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(sckt_data->interface_id); + + relay_instance_t *relay_srv =dhcp_service_relay_interface(sckt_data->interface_id); + + if (!interface_ptr || !relay_srv || !relay_srv->relay_activated) { + return; + } + ns_address_t src_address; + + uint8_t relay_frame[DHCPV6_RELAY_LENGTH + 4]; + ns_iovec_t msg_iov[2]; + msg_iov[0].iov_base = relay_frame; + msg_iov[0].iov_len = 34; + msg_iov[1].iov_base = ns_dyn_mem_temporary_alloc(sckt_data->d_len); + msg_iov[1].iov_len = sckt_data->d_len; + if (msg_iov[1].iov_base == NULL ) { + // read actual message + tr_error("Out of resources"); + goto cleanup; + } + + ns_msghdr_t msghdr; + //Set messages name buffer + msghdr.msg_name = &src_address; + msghdr.msg_namelen = sizeof(src_address); + msghdr.msg_iov = &msg_iov[1]; + msghdr.msg_iovlen = 1; + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + + msg_len = socket_recvmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0); + + + tr_debug("dhcp Relay recv msg"); + + //Parse type + uint8_t *ptr = msg_iov[1].iov_base; + uint8_t msg_type = *ptr; + + + if (msg_type == DHCPV6_RELAY_FORWARD) { + tr_error("Drop not supported DHCPv6 forward at Agent"); + goto cleanup; + + } else if (msg_type == DHCPV6_RELAY_REPLY) { + //Parse and validate Relay + dhcpv6_relay_msg_t relay_msg; + if (!libdhcpv6_relay_msg_read(ptr, msg_len, &relay_msg) ) { + tr_error("Not valid relay"); + goto cleanup; + } + if (0 != libdhcpv6_message_malformed_check(relay_msg.relay_options.msg_ptr, relay_msg.relay_options.len)) { + tr_error("Malformed packet"); + goto cleanup; + } + //Copy DST address + memcpy(src_address.address, relay_msg.peer_address, 16); + src_address.type = ADDRESS_IPV6; + src_address.identifier = DHCPV6_CLIENT_PORT; + msghdr.msg_iov = &msg_iov[0]; + msghdr.msg_iovlen = 1; + msg_iov[0].iov_base = relay_msg.relay_options.msg_ptr; + msg_iov[0].iov_len = relay_msg.relay_options.len; + tr_debug("Forward Original relay msg to client"); + + } else { + if (0 != libdhcpv6_message_malformed_check(ptr, msg_len)) { + tr_error("Malformed packet"); + goto cleanup; + } + uint8_t gp_address[16]; + //Get blobal address from interface + if (arm_net_address_get(sckt_data->interface_id, ADDR_IPV6_GP, gp_address) != 0) { + // No global prefix available + tr_error("No GP address"); + goto cleanup; + } + + //Build + libdhcpv6_dhcp_relay_msg_write(relay_frame, DHCPV6_RELAY_FORWARD, 0, src_address.address, gp_address); + libdhcpv6_dhcp_option_header_write(relay_frame + 34, msg_len); + + //Copy DST address + memcpy(src_address.address, relay_srv->server_address, 16); + src_address.type = ADDRESS_IPV6; + src_address.identifier = DHCPV6_SERVER_PORT; + //ADD relay frame vector front of original data + msghdr.msg_iov = &msg_iov[0]; + msghdr.msg_iovlen = 2; + msg_iov[0].iov_base = relay_frame; + msg_iov[0].iov_len = 38; + msg_iov[1].iov_len = msg_len; + tr_debug("Forward Client msg to server"); + } + socket_sendmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0); +cleanup: + ns_dyn_mem_free(msg_iov[1].iov_base); + + return; +} + void recv_dhcp_client_msg(void *cb_res) { ns_address_t address; @@ -351,8 +536,19 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty return 0; } if (instance_type == DHCP_INSTANCE_SERVER && dhcp_service->dhcp_server_socket < 0) { + if (dhcp_service->dhcp_relay_socket >= 0) { + tr_error("dhcp Server socket can't open because Agent open already"); + } dhcp_service->dhcp_server_socket = socket_open(SOCKET_UDP, DHCPV6_SERVER_PORT, recv_dhcp_server_msg); } + + if (instance_type == DHCP_INTANCE_RELAY_AGENT && dhcp_service->dhcp_relay_socket < 0) { + if (dhcp_service->dhcp_server_socket >= 0) { + tr_error("dhcp Relay agent can't open because server open already"); + } + dhcp_service->dhcp_relay_socket = socket_open(SOCKET_UDP, DHCPV6_SERVER_PORT, recv_dhcp_relay_msg); + } + if (instance_type == DHCP_INSTANCE_CLIENT && dhcp_service->dhcp_client_socket < 0) { dhcp_service->dhcp_client_socket = socket_open(SOCKET_UDP, DHCPV6_CLIENT_PORT, recv_dhcp_client_msg); } @@ -364,6 +560,18 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty tr_error("No sockets available for DHCP client"); return 0; } + + if (instance_type == DHCP_INTANCE_RELAY_AGENT) { + if (dhcp_service->dhcp_relay_socket < 0) { + tr_error("No sockets available for DHCP server"); + } + + uint16_t temp_id = dhcp_service_relay_interface_get(interface_id); + if (temp_id) { + return temp_id; + } + } + for (; id < MAX_SERVERS; id++) { if (dhcp_service_client_find(id) == NULL) { break; @@ -375,6 +583,22 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty ns_dyn_mem_free(srv_ptr); return 0; } + + if (instance_type == DHCP_INTANCE_RELAY_AGENT) { + //Allocate Realay Agent + relay_instance_t *relay_srv = ns_dyn_mem_alloc(sizeof(relay_instance_t)); + if (!relay_srv) { + tr_error("Out of realy instances"); + ns_dyn_mem_free(srv_ptr); + return 0; + } + ns_list_add_to_start(&dhcp_service->relay_list, relay_srv); + relay_srv->instance_id = id; + relay_srv->interface_id = interface_id; + relay_srv->relay_activated = false; + + } + ns_list_add_to_start(&dhcp_service->srv_list, srv_ptr); srv_ptr->instance_id = id; srv_ptr->instance_type = instance_type; @@ -383,6 +607,15 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty return srv_ptr->instance_id; } +void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address) +{ + relay_instance_t * realay_srv = dhcp_service_relay_find(instance); + if (realay_srv) { + realay_srv->relay_activated = true; + memcpy(realay_srv->server_address, server_address, 16); + } +} + void dhcp_service_delete(uint16_t instance) { server_instance_t *srv_ptr; @@ -393,7 +626,16 @@ void dhcp_service_delete(uint16_t instance) //TODO delete all transactions if (srv_ptr != NULL) { ns_list_remove(&dhcp_service->srv_list, srv_ptr); + if (srv_ptr->instance_type == DHCP_INTANCE_RELAY_AGENT) { + //Free relay service + relay_instance_t *relay = dhcp_service_relay_find(instance); + if (relay) { + ns_list_remove(&dhcp_service->relay_list, relay); + ns_dyn_mem_free(relay); + } + } ns_dyn_mem_free(srv_ptr); + } ns_list_foreach_safe(msg_tr_t, cur_ptr, &dhcp_service->tr_list) { if (cur_ptr->instance_id == instance) { @@ -401,17 +643,19 @@ void dhcp_service_delete(uint16_t instance) } } - int8_t server_instances = 0, client_instances = 0; + int8_t server_instances = 0, client_instances = 0, relay_instances = 0; ns_list_foreach(server_instance_t, srv, &dhcp_service->srv_list) { if (srv->instance_type == DHCP_INSTANCE_SERVER) { ++server_instances; } else if (srv->instance_type == DHCP_INSTANCE_CLIENT) { ++client_instances; + } else if (srv->instance_type == DHCP_INTANCE_RELAY_AGENT) { + ++relay_instances; } } - if (server_instances == 0 && dhcp_service->dhcp_server_socket > -1) { + if ((server_instances == 0 && relay_instances == 0) && dhcp_service->dhcp_server_socket > -1) { socket_close(dhcp_service->dhcp_server_socket); dhcp_service->dhcp_server_socket = -1; } @@ -458,7 +702,7 @@ uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr, msg_tr_ptr = dhcp_tr_create(); if (msg_tr_ptr == NULL || srv_ptr == NULL || msg_ptr == NULL || receive_resp_cb == NULL || msg_len < 5) { - tr_error("request sending failed"); + tr_error("Request sending failed"); return 0; } @@ -530,7 +774,38 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr) } socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &multicast_hop_limit, sizeof multicast_hop_limit); socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_INTERFACE_SELECT, &msg_tr_ptr->interface_id, sizeof(int8_t)); - retval = socket_sendto(msg_tr_ptr->socket, &msg_tr_ptr->addr, msg_tr_ptr->msg_ptr, msg_tr_ptr->msg_len); + + if (msg_tr_ptr->relay_start) { + //Build Relay Reply only server do this + ns_iovec_t data_vector[2]; + ns_msghdr_t msghdr; + memcpy(msg_tr_ptr->addr.address, msg_tr_ptr->relay_start + 2, 16); + msg_tr_ptr->addr.identifier = DHCPV6_SERVER_PORT; + //SET IOV vectors + //Relay Reply + data_vector[0].iov_base = (void *) msg_tr_ptr->relay_start; + data_vector[0].iov_len = DHCPV6_RELAY_LENGTH + 4; + //DHCPV normal message vector + data_vector[1].iov_base = (void *) msg_tr_ptr->msg_ptr; + data_vector[1].iov_len = msg_tr_ptr->msg_len; + + //Set message name + msghdr.msg_name = (void *) &msg_tr_ptr->addr; + msghdr.msg_namelen = sizeof(ns_address_t); + msghdr.msg_iov = &data_vector[0]; + msghdr.msg_iovlen = 2; + //No ancillary data + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + + uint8_t *ptr = msg_tr_ptr->relay_start; + *ptr = DHCPV6_RELAY_REPLY; + libdhcpv6_dhcp_option_header_write(ptr +34, msg_tr_ptr->msg_len); + retval = socket_sendmsg(msg_tr_ptr->socket, &msghdr, NS_MSG_LEGACY0); + + } else { + retval = socket_sendto(msg_tr_ptr->socket, &msg_tr_ptr->addr, msg_tr_ptr->msg_ptr, msg_tr_ptr->msg_len); + } if (retval != 0) { tr_warn("dhcp service socket_sendto fails: %i", retval); } @@ -588,6 +863,12 @@ void dhcp_service_delete(uint16_t instance) (void)instance; } +void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address) +{ + (void)instance; + (void)server_address; +} + int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr, uint16_t msg_len) { (void)msg_tr_id; @@ -626,4 +907,5 @@ bool dhcp_service_timer_tick(uint16_t ticks) (void)ticks; return false; } + #endif diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index f89f66e5e3c..780d40afe8e 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/source/libDHCPv6/libDHCPv6.c @@ -795,4 +795,43 @@ uint16_t libdhcpv6_solication_message_length(uint16_t clientLinkType, bool addre return length; } + +uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_limit, uint8_t *peer_addres, uint8_t *link_address) +{ + *ptr++ = type; + *ptr++ = hop_limit; + memcpy(ptr, link_address, 16); + ptr += 16; + memcpy(ptr, peer_addres, 16); + ptr += 16; + return ptr; +} + +uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length) +{ + ptr = common_write_16_bit(DHCPV6_OPTION_RELAY, ptr); + ptr = common_write_16_bit(length, ptr); + return ptr; +} + +bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t *relay_msg) +{ + if (length < DHCPV6_RELAY_LENGTH + 4) { + return false; + } + // Relay message base first + relay_msg->type = *ptr++; + relay_msg->hop_limit = *ptr++; + relay_msg->link_address = ptr; + relay_msg->peer_address = ptr + 16; + ptr += 32; + //Discover + if (libdhcpv6_message_option_discover(ptr, length - 34, DHCPV6_OPTION_RELAY, &relay_msg->relay_options) != 0) { + return false; + } + + + return true; +} + #endif diff --git a/source/libDHCPv6/libDHCPv6.h b/source/libDHCPv6/libDHCPv6.h index f13a24887d5..d5a522a6cb5 100644 --- a/source/libDHCPv6/libDHCPv6.h +++ b/source/libDHCPv6/libDHCPv6.h @@ -112,6 +112,14 @@ typedef struct dhcpv6_client_server_entry_s { typedef NS_LIST_HEAD(dhcpv6_client_server_data_t, link) dhcpv6_client_server_entry_s; +typedef struct dhcpv6_relay_msg { + uint8_t type; + uint8_t hop_limit; + uint8_t *link_address; + uint8_t *peer_address; + dhcp_options_msg_t relay_options; +} dhcpv6_relay_msg_t; + /** UDP Port Number definition */ #define DHCPV6_SERVER_PORT 547 #define DHCPV6_CLIENT_PORT 546 @@ -123,6 +131,8 @@ typedef NS_LIST_HEAD(dhcpv6_client_server_data_t, link) dhcpv6_client_server_ent #define DHCPV6_RENEW_TYPE 5 #define DHCPV6_REPLY_TYPE 7 #define DHCPV6_RELEASE_TYPE 8 +#define DHCPV6_RELAY_FORWARD 12 +#define DHCPV6_RELAY_REPLY 13 #define DHCPV6_LEASEQUERY_TYPE 14 #define DHCPV6_LEASEQUERY_REPLY_TYPE 15 @@ -209,6 +219,11 @@ typedef NS_LIST_HEAD(dhcpv6_client_server_data_t, link) dhcpv6_client_server_ent #define DHCPV6_OPTION_CLT_TIME 0x002e +#define DHCPV6_RELAY_LENGTH 34 +#define DHCPV6_OPTION_RELAY 0x0009 + + + /** DHCPv6 client Nontemporal address and server data allocate, free and search */ dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *duiId, uint16_t duiLinkType, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address); void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *removedEntry); @@ -259,7 +274,8 @@ uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t s uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_link_options_params_t *serverLink); uint8_t *libdhcpv6_reply_message_write(uint8_t *ptr, dhcpv6_reply_packet_s *replyPacket, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcpv6_vendor_data_packet_s *vendorData); - +uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_limit, uint8_t *peer_addres, uint8_t *link_address); +uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length); int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params); int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type , dhcp_link_options_params_t *params); @@ -347,5 +363,6 @@ int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_le int libdhcpv6_advertisment_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length); bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length); bool libdhcpv6_time_elapsed_option_at_packet(uint8_t *ptr, uint16_t length); +bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t *relay_msg); #endif /* LIBDHCPV6_H_ */ diff --git a/source/libDHCPv6/libDHCPv6_server.c b/source/libDHCPv6/libDHCPv6_server.c index a70fd001da1..bac446af7a9 100644 --- a/source/libDHCPv6/libDHCPv6_server.c +++ b/source/libDHCPv6/libDHCPv6_server.c @@ -43,11 +43,12 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void) dhcpv6_gua_server_entry_s *entry = ns_dyn_mem_alloc(sizeof(dhcpv6_gua_server_entry_s)); if (entry) { entry->clientIdSequence = 0; - entry->enableAddressMapping = false; entry->enableAddressAutonous = true; entry->clientIdDefaultSuffics = 0x0000000; entry->maxSuppertedClients = 200; entry->validLifetime = 7200; + entry->removeCb = NULL; + entry->addCb = NULL; ns_list_init(&entry->allocatedAddressList); } return entry; @@ -62,7 +63,7 @@ static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dh if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { memcpy(ptr, entry->linkId, 8); *ptr ^= 2; - } else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { + } else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { *ptr++ = entry->linkId[0] ^ 2; *ptr++ = entry->linkId[1]; *ptr++ = entry->linkId[2]; @@ -96,7 +97,9 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) //Stop use this address for leasequery and delete Route or address map address->preferredLifetime = 0; - cur->timeoutCb(cur->interfaceId, address->nonTemporalAddress); + if (cur->removeCb) { + cur->removeCb(cur->interfaceId, address->nonTemporalAddress, cur->guaPrefix); + } } else { address->preferredLifetime -= timeUpdateInSeconds; } @@ -137,17 +140,16 @@ dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstanc } -dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType, dhcp_address_prefer_timeout_cb *prefered_timeout_cb) +dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType) { - dhcpv6_gua_server_entry_s *entry = NULL; - if (libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix) == NULL) { + dhcpv6_gua_server_entry_s *entry = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix); + if (entry == NULL) { entry = libdhcpv6_server_entry_allocate(); if (entry) { memcpy(entry->guaPrefix, prefix, 8); memcpy(entry->serverDUID, serverDUID, 8); entry->serverLinkType = serverDUIDType; entry->interfaceId = interfaceId; - entry->timeoutCb = prefered_timeout_cb; ns_list_add_to_end(&dhcpv6_gua_server_list, entry); } } diff --git a/source/libDHCPv6/libDHCPv6_server.h b/source/libDHCPv6/libDHCPv6_server.h index 9f47aff2437..6e9412e4789 100644 --- a/source/libDHCPv6/libDHCPv6_server.h +++ b/source/libDHCPv6/libDHCPv6_server.h @@ -26,7 +26,7 @@ #ifdef HAVE_DHCPV6_SERVER #include "ns_list.h" -typedef void (dhcp_address_prefer_timeout_cb)(int8_t interfaceId, uint8_t *targetAddress); +typedef void (dhcp_address_prefer_remove_cb)(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info); typedef struct dhcpv6_alloacted_address_entry_s { uint8_t nonTemporalAddress[16]; @@ -50,10 +50,16 @@ typedef struct thread_dhcpv6_server_data_s { ns_list_link_t link; /*!< List link entry */ } dhcpv6_server_data_entry_t; +typedef struct dhcp_address_cache_update{ + uint8_t *allocatedAddress; + bool allocatedNewAddress; + uint32_t validLifeTime; +} dhcp_address_cache_update_t; + +typedef bool (dhcp_address_add_notify_cb)(int8_t interfaceId, dhcp_address_cache_update_t *address_info, void *route_src); + typedef struct dhcpv6_gua_server_entry_s { int8_t interfaceId; - bool enableAddressMapping; - uint8_t meshLocalPrefix[8]; bool enableAddressAutonous; uint16_t socketInstance_id; uint8_t guaPrefix[8]; @@ -63,13 +69,14 @@ typedef struct dhcpv6_gua_server_entry_s { uint32_t clientIdDefaultSuffics; uint32_t clientIdSequence; /*!< Define */ uint32_t validLifetime; - dhcp_address_prefer_timeout_cb *timeoutCb; + dhcp_address_prefer_remove_cb *removeCb; + dhcp_address_add_notify_cb *addCb; dhcpv6_alloacted_address_list_t allocatedAddressList; ns_list_link_t link; /*!< List link entry */ } dhcpv6_gua_server_entry_s; bool libdhcpv6_gua_server_list_empty(void); -dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType, dhcp_address_prefer_timeout_cb *prefered_timeout_cb); +dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType); 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); @@ -81,7 +88,7 @@ dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_g #define libdhcpv6_gua_server_list_empty() true #define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL #define libdhcpv6_server_data_get_by_prefix_and_socketinstance(socketInstance, prefixPtr) NULL -#define libdhcpv6_gua_server_allocate(prefix, interfaceId, serverDUID, serverDUIDType, prefered_timeout_cb) NULL +#define libdhcpv6_gua_server_allocate(prefix, interfaceId, serverDUID, serverDUIDType) NULL #define libdhcpv6_gua_server_free_by_prefix_and_interfaceid(prefix, interfaceId) ((void)0) #define libdhcpv6_gua_servers_time_update(timeUpdateInSeconds) ((void)0) #define libdhcpv6_gua_server_free_by_interfaceid(interfaceId) ((void)0) diff --git a/source/nsconfig.h b/source/nsconfig.h index bd7df30a632..59e3dc1a6fc 100644 --- a/source/nsconfig.h +++ b/source/nsconfig.h @@ -57,6 +57,12 @@ #endif #endif /* HAVE_THREAD */ +#if defined(HAVE_WS) +#ifndef HAVE_DHCPV6 +#define HAVE_DHCPV6 +#endif +#endif /* HAVE_WS */ + #endif // ifndef _NANOSTACK_SOURCE_CONFIG_H diff --git a/sources.mk b/sources.mk index 0217a539d46..e6461345da5 100644 --- a/sources.mk +++ b/sources.mk @@ -124,9 +124,9 @@ SRCS += \ source/6LoWPAN/Thread/thread_management_client.c \ source/6LoWPAN/Thread/thread_network_synch.c \ source/6LoWPAN/Thread/thread_bootstrap.c \ + source/6LoWPAN/Thread/thread_dhcpv6_server.c \ source/6LoWPAN/Thread/thread_host_bootstrap.c \ source/6LoWPAN/Thread/thread_router_bootstrap.c \ - source/6LoWPAN/Thread/thread_dhcpv6_client.c \ source/6LoWPAN/Thread/thread_discovery.c \ source/6LoWPAN/Thread/thread_commissioning_if.c \ source/6LoWPAN/Thread/thread_net_config_api.c \ @@ -143,6 +143,7 @@ SRCS += \ source/6LoWPAN/Thread/thread_lowpower_private_api.c \ source/6LoWPAN/Thread/thread_nvm_store.c \ source/DHCPv6_Server/DHCPv6_Server_service.c \ + source/DHCPv6_client/dhcpv6_client_service.c \ source/libDHCPv6/dhcp_service_api.c \ source/libDHCPv6/libDHCPv6.c \ source/libDHCPv6/libDHCPv6_server.c \