Skip to content

Commit

Permalink
Thread discovery response update (ARMmbed#2024)
Browse files Browse the repository at this point in the history
 Thread discovery response update

Do not reply to discovery request if CCM is disabled or domain
certificate is missing.
  • Loading branch information
Arto Kinnunen committed Mar 21, 2019
1 parent 4ac7842 commit a91a2b4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 46 deletions.
115 changes: 71 additions & 44 deletions source/6LoWPAN/Thread/thread_extension.c
Expand Up @@ -27,7 +27,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/


#include "nsconfig.h"
#include <ns_types.h>
#include <string.h>
Expand Down Expand Up @@ -68,7 +67,10 @@

#define TRACE_GROUP "comm"

#define SECURITY_POLICY_CCM_DISABLED 0x04 /* Thread Commercial Commissioning Mode is enabled when this bit is set. This is Thread 1.2 feature. */
/* See thread_management_if.h for reserved Thread 1.1 bits */
#define SECURITY_POLICY_CCM_DISABLED 0x04 /* M-bit, Commercial Commissioning Mode is disabled when this bit is set. This is Thread 1.2 feature. */
#define SECURITY_POLICY_AUTONOMOUS_ENROLLMENT_DISABLED 0x02 /* A-bit, Autonomous enrollement disabled when this bit is set */
#define SECURITY_POLICY_NMKP_DISABLED 0x01 /* P-bit, NMKP is disabled when bit is set */

typedef struct thread_extension_info {
int8_t coap_service_id;
Expand Down Expand Up @@ -976,75 +978,100 @@ static void thread_extension_relay_socket_cb(void *cb_res)
ns_dyn_mem_free(data_ptr);
}

static void thread_extension_joiner_router_deinit(protocol_interface_info_entry_t *cur)
static void thread_extension_joiner_router_ae_deinit(protocol_interface_info_entry_t *cur)
{
if (cur->thread_info->extension_info->relay_port_ae > 0) {
tr_debug("deinit AE");
coap_service_unregister_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_TRI_TX_NTF);
socket_close(cur->thread_info->extension_info->listen_socket_ae);
cur->thread_info->extension_info->listen_socket_ae = -1;
cur->thread_info->extension_info->relay_port_ae = 0;
}
}

tr_debug("deinit joiner router");
coap_service_unregister_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_TRI_TX_NTF);
coap_service_unregister_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_NMK_TX_NTF);

socket_close(cur->thread_info->extension_info->listen_socket_ae);
socket_close(cur->thread_info->extension_info->listen_socket_nmkp);
cur->thread_info->extension_info->listen_socket_ae = -1;
cur->thread_info->extension_info->listen_socket_nmkp = -1;
cur->thread_info->extension_info->relay_port_ae = 0;
cur->thread_info->extension_info->relay_port_nmkp = 0;
return;
static void thread_extension_joiner_router_nmkp_deinit(protocol_interface_info_entry_t *cur)
{
if (cur->thread_info->extension_info->relay_port_nmkp > 0) {
tr_debug("deinit NMKP");
coap_service_unregister_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_NMK_TX_NTF);
socket_close(cur->thread_info->extension_info->listen_socket_nmkp);
cur->thread_info->extension_info->listen_socket_nmkp = -1;
cur->thread_info->extension_info->relay_port_nmkp = 0;
}
}

static int thread_extension_joiner_router_init(protocol_interface_info_entry_t *cur)
{

int8_t securityLinkLayer = 0;

if (!cur->thread_info->extension_info) {
if (!cur->thread_info->extension_info || thread_info(cur)->version < THREAD_VERSION_1_2) {
return -1;
}

if (0 != thread_extension_primary_bbr_get(cur, NULL, NULL, NULL, NULL)) {
if (cur->thread_info->extension_info->relay_port_ae ||
cur->thread_info->extension_info->relay_port_nmkp) {
// Need to disable Joiner router either because port changed or moving to disabled
tr_info("Commercial Joiner router Disable joining");
thread_extension_joiner_router_deinit(cur);
}
// Need to disable Joiner router either because port changed or moving to disabled
thread_extension_joiner_router_ae_deinit(cur);
thread_extension_joiner_router_nmkp_deinit(cur);
// Joiner router should be disabled
return 0;
}
// Primary border router is present Enable relays to AE and NMKP
if (cur->thread_info->extension_info->relay_port_ae ||
cur->thread_info->extension_info->relay_port_nmkp) {
// Setup is OK

// Is this a CCM network?
uint16_t securityPolicy = thread_joiner_application_security_policy_get(cur->id);
if (securityPolicy & SECURITY_POLICY_CCM_DISABLED) {
// Not a CCM network, de-initialize
thread_extension_joiner_router_ae_deinit(cur);
thread_extension_joiner_router_nmkp_deinit(cur);
return 0;
}

if (thread_extension_bootstrap_network_certificate_available(cur) == false) {
// No domain certificate available
return 0;
}

if (cur->thread_info->extension_info->listen_socket_ae < 0) {
// Start AE relay
cur->thread_info->extension_info->relay_port_ae = THREAD_DEFAULT_AE_PORT;
cur->thread_info->extension_info->listen_socket_ae = socket_open(SOCKET_UDP, cur->thread_info->extension_info->relay_port_ae, thread_extension_relay_socket_cb);
socket_setsockopt(cur->thread_info->extension_info->listen_socket_ae, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
if (!(securityPolicy & SECURITY_POLICY_AUTONOMOUS_ENROLLMENT_DISABLED)) {
if (cur->thread_info->extension_info->listen_socket_ae < 0) {
tr_warn("Commercial Joiner router ae failed");
cur->thread_info->extension_info->relay_port_ae = 0;
// Start AE relay
cur->thread_info->extension_info->listen_socket_ae = socket_open(SOCKET_UDP, THREAD_DEFAULT_AE_PORT, thread_extension_relay_socket_cb);
if (cur->thread_info->extension_info->listen_socket_ae >= 0) {
cur->thread_info->extension_info->relay_port_ae = THREAD_DEFAULT_AE_PORT;
socket_setsockopt(cur->thread_info->extension_info->listen_socket_ae, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
// The regular TX is usable from joiner router, because it is stateless, but it neds to be forced on
coap_service_register_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_TRI_TX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_relay_tx_cb);
} else {
tr_warn("Joiner AE failed");
cur->thread_info->extension_info->relay_port_ae = 0;
}
}
} else {
thread_extension_joiner_router_ae_deinit(cur);
}
if (cur->thread_info->extension_info->listen_socket_nmkp < 0) {
// Start nmkp relay
cur->thread_info->extension_info->relay_port_nmkp = THREAD_DEFAULT_NMKP_PORT;
cur->thread_info->extension_info->listen_socket_nmkp = socket_open(SOCKET_UDP, cur->thread_info->extension_info->relay_port_nmkp, thread_extension_relay_socket_cb);
socket_setsockopt(cur->thread_info->extension_info->listen_socket_nmkp, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));

if (!(securityPolicy & SECURITY_POLICY_NMKP_DISABLED)) {
if (cur->thread_info->extension_info->listen_socket_nmkp < 0) {
tr_warn("Commercial Joiner router nmkp failed");
cur->thread_info->extension_info->relay_port_nmkp = 0;
// Start nmkp relay
cur->thread_info->extension_info->listen_socket_nmkp = socket_open(SOCKET_UDP, THREAD_DEFAULT_NMKP_PORT, thread_extension_relay_socket_cb);
if (cur->thread_info->extension_info->listen_socket_nmkp >= 0) {
cur->thread_info->extension_info->relay_port_nmkp = THREAD_DEFAULT_NMKP_PORT;
socket_setsockopt(cur->thread_info->extension_info->listen_socket_nmkp, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t));
// The regular TX is usable from joiner router, because it is stateless, but it neds to be forced on
coap_service_register_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_NMK_TX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_relay_tx_cb);
} else {
tr_warn("Joiner NMKP failed");
cur->thread_info->extension_info->relay_port_nmkp = 0;
}
}
} else {
thread_extension_joiner_router_nmkp_deinit(cur);
}

tr_info("init commercial joiner router ae:%d nmkp:%d", cur->thread_info->extension_info->relay_port_ae, cur->thread_info->extension_info->relay_port_nmkp);

// The regular TX is usable from joiner router, because it is stateless, but it neds to be forced on
coap_service_register_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_TRI_TX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_relay_tx_cb);
coap_service_register_uri(cur->thread_info->extension_info->coap_service_id, THREAD_URI_BBR_NMK_TX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_relay_tx_cb);
return 0;
}

bool thread_extension_joining_enabled(int8_t interface_id)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
Expand Down Expand Up @@ -1120,7 +1147,7 @@ uint8_t thread_extension_discover_response_len(protocol_interface_info_entry_t *
length += 4;
}
/* Thread 1.2 CCM add-ons */
if (cur->thread_info->version == THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
if (cur->thread_info->version >= THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
// Calculate also following optional TLV's:
// Thread domain name TLV
domain_name_len = thread_extension_bootstrap_thread_name_length_get(cur);
Expand All @@ -1146,7 +1173,7 @@ uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_
ptr = thread_meshcop_tlv_data_write_uint16(ptr, MESHCOP_TLV_NMKP_PORT, cur->thread_info->extension_info->relay_port_nmkp);
}
/* Thread 1.2 CCM add-ons */
if (cur->thread_info->version == THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
if (cur->thread_info->version >= THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
// Thread domain name TLV
if (thread_extension_bootstrap_thread_name_length_get(cur)) {
ptr = thread_meshcop_tlv_data_write(ptr, MESHCOP_TLV_DOMAIN_NAME, thread_extension_bootstrap_thread_name_length_get(cur), thread_extension_bootstrap_thread_name_ptr_get(cur));
Expand Down
12 changes: 10 additions & 2 deletions source/6LoWPAN/Thread/thread_extension_bootstrap.c
Expand Up @@ -564,6 +564,14 @@ int thread_extension_bootstrap_device_certificate_set(protocol_interface_info_en
return 0;
}

bool thread_extension_bootstrap_network_certificate_available(protocol_interface_info_entry_t *cur)
{
if (!thread_info(cur)->extension_credentials_ptr || !thread_info(cur)->extension_credentials_ptr->domain_certificate_ptr) {
return false;
}

return true;
}

int thread_extension_bootstrap_network_certificate_set(protocol_interface_info_entry_t *cur, const unsigned char *domain_certificate_ptr, uint16_t domain_certificate_len)
{
Expand Down Expand Up @@ -640,7 +648,7 @@ int thread_extension_bootstrap_commission_start(protocol_interface_info_entry_t
{
discovery_additional_info_t *discovery_add_info = (discovery_additional_info_t *)nwk_info->reserved_opaque;

if (thread_info(cur)->version == THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
if (thread_info(cur)->version >= THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
if (thread_info(cur)->extension_credentials_ptr->domain_certificate_ptr && discovery_add_info->nmk_port) {
return thread_joiner_application_nmkp_commission_start(cur->id, parent_address, discovery_add_info->nmk_port, done_cb);
} else if (thread_info(cur)->extension_credentials_ptr->device_certificate_ptr && discovery_add_info->ae_port) {
Expand All @@ -658,7 +666,7 @@ discovery_response_list_t *thread_extension_bootstrap_network_select(protocol_in
{
discovery_response_list_t *discovered_network_ptr = NULL;

if (thread_info(cur)->version == THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
if (thread_info(cur)->version >= THREAD_VERSION_1_2 && thread_info(cur)->extension_credentials_ptr) {
/* If we have domain certificate, search for domain to join */
if (thread_info(cur)->extension_credentials_ptr->domain_certificate_ptr) {
ns_list_foreach_safe(discovery_response_list_t, cur_class, discover_response) {
Expand Down
3 changes: 3 additions & 0 deletions source/6LoWPAN/Thread/thread_extension_bootstrap.h
Expand Up @@ -44,6 +44,8 @@ int thread_extension_bootstrap_network_certificate_set(protocol_interface_info_e

int thread_extension_bootstrap_network_private_key_set(protocol_interface_info_entry_t *cur, const unsigned char *priv_key_ptr, uint16_t priv_key_len);

bool thread_extension_bootstrap_network_certificate_available(protocol_interface_info_entry_t *cur);

int thread_extension_bootstrap_thread_name_set(protocol_interface_info_entry_t *cur, char thread_name[16]);

int thread_extension_bootstrap_commission_start(protocol_interface_info_entry_t *cur, uint8_t parent_address[16], discovery_response_list_t *nwk_info, thread_joiner_application_commission_done_cb *done_cb);
Expand All @@ -62,6 +64,7 @@ int thread_extension_bootstrap_reenrollment_start(protocol_interface_info_entry_
#define thread_extension_bootstrap_free(cur);
#define thread_extension_bootstrap_device_certificate_set(cur, device_certificate_ptr, device_certificate_len, priv_key_ptr, priv_key_len) (-1)
#define thread_extension_bootstrap_network_certificate_set(cur, domain_certificate_ptr, domain_certificate_len) (-1)
#define thread_extension_bootstrap_network_certificate_available(cur) (false)
#define thread_extension_bootstrap_network_private_key_set(cur, priv_key_ptr, priv_key_len) (-1)
#define thread_extension_bootstrap_thread_name_set(cur, thread_name) (-1)
#define thread_extension_bootstrap_commission_start(cur, parent_address, port, done_cb) (-1)
Expand Down
Expand Up @@ -63,6 +63,11 @@ int thread_extension_bootstrap_network_private_key_set(protocol_interface_info_e
return 0;
}

bool thread_extension_bootstrap_network_certificate_available(protocol_interface_info_entry_t *cur)
{
return false;
}

int thread_extension_bootstrap_thread_name_set(protocol_interface_info_entry_t *cur, char thread_name[16])
{
return 0;
Expand Down

0 comments on commit a91a2b4

Please sign in to comment.