Esempio n. 1
0
static bool rpl_data_handle_fwd_error(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *opt, const sockaddr_t *ll_src)
{
    if (!ll_src) {
        tr_warn("Forwarding-Error - dst=%s, neighbour unknown", trace_ipv6(buf->dst_sa.address));
        return false;
    } else {
        tr_warn("Forwarding-Error - dst=%s, neighbour=%s", trace_ipv6(buf->dst_sa.address), trace_sockaddr(ll_src, true));
    }

    rpl_instance_t *instance = rpl_lookup_instance(cur->rpl_domain, opt[1], rpl_data_get_dodagid(buf));
    if (!instance) {
        return false;
    }

#if 1
    return false;
#else
    /* Work needed */
    if (rpl_instance_am_root(instance)) {
        /* We are looking for a target that has us as its transit */
    }
    bool deleted = ipv6_route_delete_by_info_and_ll(buf->dst_sa.address, ROUTE_RPL_DAO, ll_src);
    deleted |= ipv6_route_delete_by_info_and_ll(buf->dst_sa.address, ROUTE_RPL_DAO_SR, ll_src);
    opt[0] &=~ RPL_OPT_FWD_ERROR;

    return true;
#endif
}
int8_t thread_management_get_request_full_nwk_data(int8_t interface_id, bool *full_nwk_data)
{
#ifdef HAVE_THREAD
    const protocol_interface_info_entry_t *cur;

    if (!full_nwk_data) {
        tr_warn("Invalid input ptr");
        return -3;
    }
    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }
    if (!cur->thread_info) {
        tr_warn("Thread not active");
        return -2;
    }
    *full_nwk_data = cur->thread_info->requestFullNetworkData;
    return 0;
#else
    (void) interface_id;
    (void) full_nwk_data;
    return -1;
#endif
}
int thread_management_max_child_count(
    int8_t interface_id,
    uint8_t maxChildCount)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur;

    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }

    if (!cur->thread_info) {
        tr_warn("Not Thread specific interface");
        return -1;
    }

    mac_description_storage_size_t buffer;
    if (!cur->mac_api || !cur->mac_api->mac_storage_sizes_get || cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) {
        return -1;
    }

    if (maxChildCount > buffer.device_decription_table_size) {
        tr_error("Accept values are between 0-%d for max Child count", buffer.device_decription_table_size);
        return -1;
    }
    cur->thread_info->maxChildCount = maxChildCount;
    return 0;
#else
    (void) interface_id;
    (void) maxChildCount;
    return -1;
#endif
}
int8_t thread_management_get_link_timeout(int8_t interface_id, uint32_t *link_timeout)
{
#ifdef HAVE_THREAD
    const protocol_interface_info_entry_t *cur;

    if (!link_timeout) {
        tr_warn("Invalid input ptr");
        return -3;
    }
    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }
    const thread_info_t *thread = cur->thread_info;
    if (!thread) {
        tr_warn("Thread not active");
        return -2;
    }
    *link_timeout = thread->host_link_timeout;
    return 0;
#else
    (void) interface_id;
    (void) link_timeout;
    return -1;
#endif
}
int8_t thread_management_set_link_timeout(int8_t interface_id, uint32_t link_timeout)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur;

    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }
    thread_info_t *thread = cur->thread_info;
    if (!thread) {
        tr_warn("Thread not active");
        return -2;
    }
    tr_info("set new link timeout %"PRIu32" , old value %"PRIu32"", link_timeout, thread->host_link_timeout);
    thread->host_link_timeout = link_timeout;
    thread_bootstrap_child_update_trig(cur);
    return 0;
#else
    (void) interface_id;
    (void) link_timeout;
    return -1;
#endif
}
int thread_management_device_type_set(int8_t interface_id, thread_device_type_e device_type)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);

    if (!cur || !cur->thread_info) {
        tr_warn("Not Thread specific interface");
        return -1;
    }
    if (device_type == THREAD_DEVICE_REED) {
        // Change mode to router
        cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER;
    } else if (device_type == THREAD_DEVICE_FED) {
        //FED devices makes links and makes address resolutions
        cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST;
        cur->thread_info->end_device_link_synch = true;
    } else if (device_type == THREAD_DEVICE_MED) {
        cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST;
        cur->thread_info->end_device_link_synch = false;
    } else if (device_type == THREAD_DEVICE_SED) {
        cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST;
        cur->thread_info->end_device_link_synch = false;
    }
    if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
        // bootstrap active need to restart
        thread_bootstrap_reset_restart(interface_id);
    }

    return 0;
#else
    (void) interface_id;
    (void) device_type;
    return -1;
#endif
}
Esempio n. 7
0
bool rpl_data_remember_outer(buffer_t *buf)
{
    /* We're stripping the IP header - need the HBH header for future reference */
     uint8_t *hbh;
     rpl_data_locate_info(buf, &hbh, NULL);
     if (hbh) {
         uint8_t instance_id = hbh[3];
         /* For local instances, also need to extract the DODAG ID from src/dst */
         bool local = rpl_instance_id_is_local(instance_id);
         /* Copy the length byte and the option data (and optionally DODAG ID) */
         buf->rpl_option = ns_dyn_mem_temporary_alloc(hbh[1] + 1 + (local ? 16 : 0));
         if (buf->rpl_option) {
             memcpy(buf->rpl_option, hbh + 1, hbh[1] + 1);
             if (local) {
                 uint8_t *dodagid = instance_id & RPL_INSTANCE_DEST ? buf->dst_sa.address : buf->src_sa.address;
                 memcpy(buf->rpl_option + hbh[1] + 1, dodagid, 16);
             }
         }
     }

     if ((buf->options.ip_extflags & IPEXT_HBH_RPL) && !buf->rpl_option) {
         tr_warn("RPL tunnel exit HbH fail");
         return false;
     }

     return true;
}
Esempio n. 8
0
void pana_event_handler(arm_event_s *event)
{
    switch (event->event_type) {
        case ARM_PANA_INIT:
            tr_debug("Pana Tasklet Init");
            break;

        case ARM_PANA_TLS_CB:
            if (event->data_ptr) {
                buffer_t *buf = event->data_ptr;
                sec_suite_t *tls_suite = buf->session_ptr;
                buf->session_ptr = NULL;

                tls_suite = sec_suite_verify(tls_suite);

                if (tls_suite && pana_tls_handler_cb) {
                    buf = pana_tls_handler_cb(buf, tls_suite);
                } else {
                    tr_warn("Pana/TLS er");
                }

                if (buf) {
                    buffer_free(buf);
                }
            }
            break;
        default:
            break;
    }
}
Esempio n. 9
0
static void thread_nd_coap_notification_callback(int8_t interface_id, const uint8_t ip_addr[16], uint16_t loc_addr, const uint8_t ml_eid[8])
{
    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        return;
    }

    /* First check to see if we have an existing entry with different RLOC - we need to unicast error
     * notification to that old entry if so. */
    ipv6_neighbour_t *entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr);
    if (entry && entry->ll_type == ADDR_802_15_4_SHORT) {
        uint16_t old_entry_rloc = common_read_16_bit(entry->ll_address + 2);
        if (old_entry_rloc != loc_addr) {
            uint8_t old_entry_ip[16];
            thread_addr_write_mesh_local_16(old_entry_ip, common_read_16_bit(entry->ll_address + 2), cur->thread_info);
            tr_warn("Proactive address change %s %04x->%04x", trace_ipv6(ip_addr), old_entry_rloc, loc_addr);
            thread_resolution_client_address_error(interface_id, old_entry_ip, ip_addr, ml_eid);
        }
    }

    /* Now treat as an unsolicited update (by address, because entry may be NULL) */
    uint8_t ll_addr[4];
    common_write_16_bit(cur->mac_parameters->pan_id, ll_addr + 0);
    common_write_16_bit(loc_addr, ll_addr + 2);
    ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, ip_addr, ADDR_802_15_4_SHORT, ll_addr);

    if (nd_proxy_enabled_for_upstream(cur->id)) {
        ipv6_route_add(ip_addr, 128, cur->id, NULL, ROUTE_THREAD_PROXIED_HOST, 3600, 0);
    }
}
Esempio n. 10
0
/**
 * \brief Network state event handler.
 * \param event show network start response or current network state.
 *
 * - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
 * - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
 * - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state
 * - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
 * - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
 * - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
 */
void nd_tasklet_parse_network_event(arm_event_s *event)
{
    arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
    tr_debug("app_parse_network_event() %d", status);
    switch (status) {
        case ARM_NWK_BOOTSTRAP_READY:
            /* Network is ready and node is connected to Access Point */
            if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
                tr_info("6LoWPAN ND bootstrap ready");
                tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
                nd_tasklet_trace_bootstrap_info();
                nd_tasklet_network_state_changed(MESH_CONNECTED);
            }
            break;
        case ARM_NWK_NWK_SCAN_FAIL:
            /* Link Layer Active Scan Fail, Stack is Already at Idle state */
            tr_debug("Link Layer Scan Fail: No Beacons");
            tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
            nd_tasklet_network_state_changed(MESH_DISCONNECTED);
            break;
        case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
            /* No ND Router at current Channel Stack is Already at Idle state */
            tr_debug("ND Scan/ GP REG fail");
            tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
            nd_tasklet_network_state_changed(MESH_DISCONNECTED);
            break;
        case ARM_NWK_NWK_CONNECTION_DOWN:
            /* Connection to Access point is lost wait for Scan Result */
            tr_debug("ND/RPL scan new network");
            tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
            nd_tasklet_network_state_changed(MESH_DISCONNECTED);
            break;
        case ARM_NWK_NWK_PARENT_POLL_FAIL:
            tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
            nd_tasklet_network_state_changed(MESH_DISCONNECTED);
            break;
        case ARM_NWK_AUHTENTICATION_FAIL:
            tr_debug("Network authentication fail");
            tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
            nd_tasklet_network_state_changed(MESH_DISCONNECTED);
            break;
        default:
            tr_warn("Unknown event %d", status);
            break;
    }

    if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY &&
        tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
        // Set 5s timer for new network scan
        eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
                                    ARM_LIB_SYSTEM_TIMER_EVENT,
                                    tasklet_data_ptr->tasklet,
                                    5000);

    }
}
/**
 * Set DHCPV6 server for Thread GP data purpose
 *
 * \param interface_id Network Interface
 * \param prefix_ptr pointer DHCPv6 Server Given Prefix
 *
 * return 0, Set OK
 * return <0 Set Not OK
 */
int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t max_client_cnt, bool stableData)
{
#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;
    uint8_t temp[16];
    uint8_t *ptr = temp;

    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        return -1;
    }

    if (!cur->thread_info) {
        return -1;
    }

    if (thread_dhcp6_server_init(interface_id, prefix_ptr, cur->mac, THREAD_MIN_PREFIX_LIFETIME) != 0) {
        tr_warn("SerVER alloc fail");
        return -1;
    }

    prefixTlv.domainId = 0;
    prefixTlv.Prefix = prefix_ptr;
    prefixTlv.PrefixLen = 64;

    memset(&service, 0, sizeof(thread_border_router_tlv_entry_t));
    service.Prf = 1;
    service.P_dhcp = true;
    service.P_on_mesh = true;
    service.stableData = stableData;

    // SET maximum number of accepted clients
    DHCPv6_server_service_set_max_clients_accepts_count(interface_id, prefix_ptr, max_client_cnt);

    tr_debug("GUA server Generate OK");
    memcpy(ptr, prefix_ptr, 8);
    memset(ptr + 8, 0, 8);
    //Network Data
    if (thread_local_server_list_add_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv, &service) != 0) {
        return -1;
    }

    return 0;
#else
    (void) interface_id;
    (void) prefix_ptr;
    (void) max_client_cnt;
    (void) stableData;
    return -1;
#endif
}
Esempio n. 12
0
buffer_t *pana_auth_message_handler(buffer_t *buf, pana_header_t *header, sec_suite_t *suite)
{
    if (!buf) {
        return NULL;
    }
    protocol_interface_info_entry_t *cur = buf->interface;
    if (!cur) {
        return buffer_free(buf);
    }

    uint16_t length = buffer_data_length(buf);
    uint8_t *ptr = buffer_data_pointer(buf);
    pana_avp_t avp_temp;

    if (suite->pana_session.session_ready) {
        return buffer_free(buf);
    }

    if (sec_check_suite_ptrs(suite) == 0) {
        tr_warn("SEC Lib Fail");
        return buffer_free(buf);
    }

    avp_temp.code = AVP_NONCE_CODE;
    if (pana_avp_discover(ptr, length, &avp_temp)) {
        if (avp_temp.len == 16) {
            if ((header->flags & PANA_FLAGS_REQUEST)  == PANA_FLAGS_RESPONSE) {
                memcpy(suite->pana_session.pana_heap->client_nonce, avp_temp.avp_ptr, 16);
            } else {
                memcpy(suite->pana_session.pana_heap->agent_nonce, avp_temp.avp_ptr, 16);
            }
            //tr_debug("Pana:A_NONCE OK");

        } else {
            tr_debug("A_NONCE length fail, Len: %x", avp_temp.len);
        }
    }

    avp_temp.code = AVP_EAP_PAYLOAD_CODE;
    if (pana_avp_discover(ptr, length, &avp_temp)) {
        ptr = avp_temp.avp_ptr;
        if (avp_temp.len > 4) {
            buf->buf_ptr = 0;
            buf->buf_end = avp_temp.len;
            memmove(buf->buf, ptr, avp_temp.len);
            return buf;
        }
    }

    return buffer_free(buf);
}
int8_t thread_management_set_request_full_nwk_data(int8_t interface_id, bool full_nwk_data)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur;
    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }
    if (!cur->thread_info) {
        tr_warn("Thread not active");
        return -2;
    }
    if (cur->thread_info->requestFullNetworkData != full_nwk_data) {
        cur->thread_info->requestFullNetworkData = full_nwk_data;
        thread_bootstrap_child_update_trig(cur);
    }
    return 0;
#else
    (void) interface_id;
    (void) full_nwk_data;
    return -1;
#endif
}
int thread_management_device_certificate_set(int8_t interface_id, const unsigned char *device_certificate_ptr, uint16_t device_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur;

    cur = protocol_stack_interface_info_get_by_id(interface_id);
    if (!cur) {
        tr_warn("invalid interface id");
        return -1;
    }

    return thread_extension_bootstrap_device_certificate_set(cur, device_certificate_ptr, device_certificate_len, priv_key_ptr, priv_key_len);

#else
    (void) interface_id;
    (void) device_certificate_ptr;
    (void) device_certificate_len;
    (void) priv_key_ptr;
    (void) priv_key_len;
    return -1;
#endif
}
static bool thread_router_leader_data_process(protocol_interface_info_entry_t *cur, uint8_t *src_address, thread_leader_data_t *leaderData, mle_tlv_info_t *routeTlv, mle_neigh_table_entry_t *neighbor)
{
    int leaderDataUpdate = thread_leader_data_validation(cur, leaderData, routeTlv);

    if (leaderDataUpdate == 1) {
        if (neighbor && neighbor->handshakeReady == 1) {
            // Request network data if we have a 2-way link
            tr_debug("Request New Network Data from %s", trace_ipv6(src_address));
            thread_network_data_request_send(cur, src_address, true);
        } else {

        }
    } else if (leaderDataUpdate == 2) {
        tr_debug("Start Merge");
        thread_bootstrap_connection_error(cur->id, CON_ERROR_PARTITION_MERGE, NULL);
        return false;

    } else if (leaderDataUpdate < 0) {
        tr_warn("Leader data failure");
        return false;
    }
    return true;
}
Esempio n. 16
0
buffer_t *nwk_udp_rx_security_check(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;
    uint8_t drop_unsecured = 0;

    // Hack for PANA and MLE. PANA socket is not unsecured, need to allow unsecured link local traffic.
    // MLE need to allow joiner request, that is not secured.
    // TODO: Check if there is better fix for these.
    if (buf->src_sa.port == UDP_PORT_PANA || buf->dst_sa.port == UDP_PORT_PANA) {
        if ((buf->dst_sa.address[0] != 0xfe)  && (buf->options.ll_security_bypass_rx)) {
            drop_unsecured = 1;
        }
    } else if (buf->dst_sa.port == UDP_PORT_MLE) {
        // OK
    } else if (buf->options.ll_security_bypass_rx) {
        if (addr_ipv6_scope(buf->src_sa.address, cur) > IPV6_SCOPE_LINK_LOCAL) {
            drop_unsecured = 1;
        } else {
            if (!buf->socket) {
                buffer_socket_set(buf, socket_lookup_ipv6(IPV6_NH_UDP, &buf->dst_sa, &buf->src_sa, true));
            }
            if (buf->socket && buf->socket->inet_pcb->link_layer_security == 0) {
                // non-secure okay if it's for a socket whose security flag is clear.
            } else {
                drop_unsecured = 1;
            }
        }
    }

    if (drop_unsecured) {
        tr_warn("Drop UDP Unsecured");
        buf = buffer_free(buf);
    }

    return buf;
}
int thread_management_node_init(
    int8_t interface_id,
    channel_list_s *channel_list,
    device_configuration_s *device_configuration,
    link_configuration_s *static_configuration)
{
#ifdef HAVE_THREAD
    protocol_interface_info_entry_t *cur;
    nwk_scan_params_t *scan_params;

    if (!device_configuration) {
        return -1;
    }

    cur = protocol_stack_interface_info_get_by_id(interface_id);

    if (!cur) {
        tr_warn("Invalid interface id");
        return -1;
    }

    if (!cur->thread_info) {
        tr_warn("Not Thread specific interface");
        return -1;
    }

    if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) !=  0) {
        return -1;
    }

    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->border_router_setup) {
        return -1;
    }

    if (thread_init(cur) < 0) {
        thread_nd_service_delete(cur->id);
        tr_warn("Thread Boostarp Init Fail");
        return -1;
    }
    if (thread_management_server_init(cur->id) != 0) {
        tr_warn("Thread management server init fail");
        return -1;
    }

    if (thread_diagnostic_init(cur->id) != 0) {
        tr_warn("Thread diagnostic init fail");
        return -1;
    }
    //Store setup to application Joiner Application
    if (thread_joiner_application_init(cur->id, device_configuration, static_configuration) != 0) {
        tr_error("mandatory device configuration missing");
        return -2;
    }

    // Joiner application copies and massages the device configuration - switch to massaged version
    device_configuration = thread_joiner_application_get_device_config(cur->id);
    if (!device_configuration) {
        return -1;
    }
    cur->if_lowpan_security_params->nwk_security_mode = NET_SEC_MODE_NO_LINK_SECURITY;
    cur->mac_parameters->mac_configured_sec_level = 0;

    // If no-one has already set a secret key, use the EUI-64 - Thread
    // wants RFC 7217 IIDs. Also ensure they're on for the Thread interface.
    // (Note that this will likely enable opaque IIDs on Ethernet too).
    if (!addr_opaque_iid_key_is_set()) {
        // Could we include some private key here?
        arm_nwk_ipv6_opaque_iid_key(device_configuration->eui64, 8);
        arm_nwk_ipv6_opaque_iid_enable(cur->id, true);
    }
    // Copy the channel list
    memset(&cur->mac_parameters->mac_channel_list, 0, sizeof(channel_list_s));
    if (channel_list) {
        // Application has given limited set of channels
        cur->mac_parameters->mac_channel_list = *channel_list;
    } else {
        cur->mac_parameters->mac_channel_list.channel_page = CHANNEL_PAGE_0;
        cur->mac_parameters->mac_channel_list.channel_mask[0] = 0x07FFF800;
    }

    scan_params = &cur->mac_parameters->nwk_scan_params;
    memset(&scan_params->stack_chan_list, 0, sizeof(channel_list_s));
    if (channel_list) {
        // Application has given limited set of channels
        scan_params->stack_chan_list = *channel_list;
    } else {
        scan_params->stack_chan_list.channel_page = CHANNEL_PAGE_0;
        scan_params->stack_chan_list.channel_mask[0] = 0x07FFF800;
    }
    scan_params->scan_duration = 5;

    cur->thread_info->masterSecretMaterial.valid_Info = false;
    thread_key_guard_timer_calculate(cur, static_configuration, true);

    cur->thread_info->maxChildCount = THREAD_MAX_CHILD_COUNT;
    cur->thread_info->rfc6775 = false;
    cur->thread_info->host_link_timeout = THREAD_END_DEVICE_DEFAULT_TIMEOUT;
    /* Thread will manage the address query timing, and report negatives. Set this high so as not to interfere. */
    cur->ipv6_neighbour_cache.retrans_timer = 10000;

    // Set default partition weighting
    cur->thread_info->partition_weighting = THREAD_DEFAULT_WEIGHTING;

    /* IP forwarding is off by default */
    cur->ip_forwarding = false;

    lowpan_adaptation_indirect_queue_params_set(cur,
                                                THREAD_INDIRECT_BIG_PACKET_THRESHOLD,
                                                THREAD_INDIRECT_BIG_PACKETS_TOTAL,
                                                THREAD_INDIRECT_SMALL_PACKETS_PER_CHILD);

    if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST) {
        cur->thread_info->requestFullNetworkData = false;
    } else {
        cur->thread_info->requestFullNetworkData = true;
    }

    cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION;
    cur->configure_flags |= INTERFACE_SECURITY_DEFINED;
    cur->comm_status_ind_cb = thread_comm_status_indication_cb;
    return 0;
#else
    (void) interface_id;
    (void) channel_list;
    (void) device_configuration;
    (void) static_configuration;
    return -1;
#endif
}
/* Public functions */
void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, mle_security_header_t *security_headers)
{
    /* TODO's:
     * - Any incoming link configuration or advertisement message, or an incoming update sent to a
     *   link-local address, whose IP Hop Limit is not 255, may have been forwarded by a Router
     *   and MUST be discarded.
     */

    protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);

    if (!cur) {
        return;
    }

    /* Check that message is from link-local scope */
    if(!addr_is_ipv6_link_local(mle_msg->packet_src_address)) {
        return;
    }

    uint8_t linkMargin = thread_compute_link_margin(mle_msg->dbm);

    // Always save lowpower queries
    thread_lowpower_process_request(mle_msg);

    switch (mle_msg->message_type) {
    case MLE_COMMAND_ACCEPT: {
        thread_parse_accept(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_METRIC_MANAGEMENT_REQUEST: {
        thread_lowpower_metrics_management_query_request_process(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_REJECT: {
        mle_neigh_table_entry_t *entry_temp;
        tr_warn("Reject Link");
        entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false);
        if (entry_temp) {
            mle_class_remove_entry(cur->id, entry_temp);
        }
        break;
    }

    case MLE_COMMAND_DATASET_ANNOUNCE: {
        thread_parse_annoucement(cur, mle_msg);
        break;
    }

    case MLE_COMMAND_ADVERTISEMENT: {
        thread_parse_advertisement(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_DATA_RESPONSE: {
        thread_parse_data_response(cur, mle_msg, linkMargin);
        break;
    }

    case MLE_COMMAND_CHILD_UPDATE_RESPONSE:
    {
        thread_parse_child_update_response(cur, mle_msg, security_headers, linkMargin);
        break;
    }

    case MLE_COMMAND_PARENT_RESPONSE: {
        tr_debug("MLE parent response received");
        thread_mle_parent_discover_receive_cb(interface_id, mle_msg, security_headers);
        break;
    }
    default:
        if ((thread_am_host(cur) || thread_am_reed(cur)) && mle_msg->message_type == MLE_COMMAND_CHILD_UPDATE_REQUEST){
            // Thread host and router in REED mode answer the message same way. Routers only process messages from child
            thread_host_child_update_request_process(cur, mle_msg, linkMargin);
        } else if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) {
            thread_router_bootstrap_mle_receive_cb(interface_id, mle_msg, security_headers);
        } else {
            tr_warn("Not supported MLE message for host %d", mle_msg->message_type);
        }
    }

}
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;
    mle_tlv_info_t networkDataTlv;
    mle_tlv_info_t ConfigurationTlv;
    mle_tlv_info_t challengeTlv;
    mle_tlv_info_t tlv_req;
    uint64_t active_timestamp = 0;
    uint64_t pending_timestamp = 0;// means no pending timestamp
    mle_neigh_table_entry_t *entry_temp;
    bool data_request_needed = false;

    tr_debug("Child update request");
    entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false);

    if (!thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData) ||
        !entry_temp ||
        !thread_check_is_this_my_parent(cur, entry_temp)) {
        // Dropped if no leader data or not from parent
        tr_warn("invalid message");
        return;
    }
    mle_tlv_read_tlv(MLE_TYPE_CHALLENGE, mle_msg->data_ptr, mle_msg->data_length, &challengeTlv);
    mle_tlv_read_tlv(MLE_TYPE_TLV_REQUEST, mle_msg->data_ptr, mle_msg->data_length, &tlv_req);

    // Check if partition changed
    if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) {
        thread_info(cur)->thread_leader_data->leaderRouterId = leaderData.leaderRouterId;
        thread_info(cur)->thread_leader_data->partitionId = leaderData.partitionId;
        thread_old_partition_data_purge(cur);
    }
    //Check Network Data TLV
    if (mle_tlv_read_tlv(MLE_TYPE_NETWORK_DATA, mle_msg->data_ptr, mle_msg->data_length, &networkDataTlv)) {
       thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen);
       thread_bootstrap_network_data_update(cur);
    }

    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
        data_request_needed = true;
    }

    // update operational datasets
    mle_tlv_read_tlv(MLE_TYPE_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv);
    if (mle_tlv_read_64_bit_tlv(MLE_TYPE_ACTIVE_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &active_timestamp)) {
        thread_active_operational_dataset_process(cur,ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen, active_timestamp);
    }
    mle_tlv_read_tlv(MLE_TYPE_PENDING_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv);
    if (mle_tlv_read_64_bit_tlv(MLE_TYPE_PENDING_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &pending_timestamp)) {
        thread_pending_operational_dataset_process(cur, pending_timestamp, ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen);
    }
    // Check if operational datasets are in sync
    if (thread_joiner_application_active_timestamp_get(cur->id) < active_timestamp ||
        thread_joiner_application_pending_config_timestamp_get(cur->id) < pending_timestamp) {
        tr_debug("Request new network data with configurations active %"PRIX64", %"PRIX64" Pending %"PRIX64", %"PRIX64,
                active_timestamp, thread_joiner_application_active_timestamp_get(cur->id),
                pending_timestamp, thread_joiner_application_pending_config_timestamp_get(cur->id));
        data_request_needed = true;
    }
    thread_host_child_update_response_send(cur, mle_msg->packet_src_address, &challengeTlv, &tlv_req);

    if (data_request_needed) {
        thread_network_data_request_send(cur, mle_msg->packet_src_address, true);
    }
}
static void thread_parse_data_response(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, uint8_t linkMargin)
{
    thread_leader_data_t leaderData;
    mle_tlv_info_t networkDataTlv;
    mle_tlv_info_t ConfigurationTlv;
    uint64_t active_timestamp = 0;
    uint64_t pending_timestamp = 0;// means no pending timestamp
    mle_neigh_table_entry_t *entry_temp;
    bool accept_new_data = false;
    bool leaderDataReceived;

    tr_debug("Data Response");

    if (thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData)) {
        leaderDataReceived = true;
    } else {
        leaderDataReceived = false;
    }
    if (!leaderDataReceived) {
        tr_warn("no leader TLV");
        return;
    }

    entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false);

    if(cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER ||
            cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_FULL_END_DEVICE) {
        if (thread_info(cur)->thread_attached_state == THREAD_STATE_CONNECTED) {
            // We are attached as child and just learn new data
            if (!thread_check_is_this_my_parent(cur, entry_temp)) {
                return;
            }
        } else {
            if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) {
                // if receiving data response from different partition it is dropped
                return;
            }
        }
    } else if (thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE ||
            thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) {
        if (!entry_temp) {
            tr_debug("Unknown neighbor");
            return;
        }
    }

    if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) {
        thread_info(cur)->thread_leader_data->leaderRouterId = leaderData.leaderRouterId;
        thread_info(cur)->thread_leader_data->partitionId = leaderData.partitionId;
        thread_old_partition_data_purge(cur);
        accept_new_data = true;
    }

    //check response is for link metrics query
    thread_lowpower_process_response(mle_msg->packet_src_address, cur->id, mle_msg->data_ptr, mle_msg->data_length);

    if (cur->thread_info->networkDataRequested) {
        tr_debug("Requested network data received");
        cur->thread_info->networkDataRequested = false;
        accept_new_data = true;
    }
    if (1 == thread_leader_data_validation(cur, &leaderData, NULL)) {
        tr_debug("Network data updated");
        accept_new_data = true;
    }
    // update operational datasets

    mle_tlv_read_tlv(MLE_TYPE_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv);
    if (mle_tlv_read_64_bit_tlv(MLE_TYPE_ACTIVE_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &active_timestamp)) {
        thread_active_operational_dataset_process(cur,ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen, active_timestamp);
    }
    // TODO check if result is true then need to update all configurations
    mle_tlv_read_tlv(MLE_TYPE_PENDING_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv);
    if (mle_tlv_read_64_bit_tlv(MLE_TYPE_PENDING_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &pending_timestamp)) {
        thread_pending_operational_dataset_process(cur, pending_timestamp, ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen);
    }
    // Check if we are now in sync
    // if not matching must send data request again
    if (thread_joiner_application_active_timestamp_get(cur->id) < active_timestamp
            || thread_joiner_application_pending_config_timestamp_get(cur->id) < pending_timestamp) {
        tr_debug("Request new network data with configurations active %"PRIX64", %"PRIX64" Pending %"PRIX64", %"PRIX64,
                active_timestamp, thread_joiner_application_active_timestamp_get(cur->id),
                pending_timestamp, thread_joiner_application_pending_config_timestamp_get(cur->id));
        thread_network_data_request_send(cur, mle_msg->packet_src_address, true);
        return;
    }
    //Check Network Data TLV
    if (accept_new_data) {
        if (mle_tlv_read_tlv(MLE_TYPE_NETWORK_DATA, mle_msg->data_ptr, mle_msg->data_length, &networkDataTlv)) {
           thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen);
           thread_bootstrap_network_data_update(cur);
        } else {
            tr_debug("SET NWK data Request state");
        }
    }

    // leader has finished synching network data after reset/restart
    if (cur->thread_info->leader_synced) {
        cur->thread_info->leader_synced = false;
        thread_leader_service_network_data_changed(cur, true, true);
    }
}
Esempio n. 21
0
/* Input: Final IP packet for transmission on link.
 *        Buffer destination = final destination
 *        Buffer source undefined.
 *        Route next hop address set.
 * Output: Buffer destination+source = link-layer addresses
 *         Sent to mesh, LowPAN fragmentation or MAC layers
 */
buffer_t *lowpan_down(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;

    buf->options.type = 0;

    if (!buf->route) {
        tr_debug("lowpan_down route");
        return buffer_free(buf);
    }

    const uint8_t *ip_src = buffer_data_pointer(buf) + 8;
    const uint8_t *next_hop = buf->route->route_info.next_hop_addr;
    bool link_local = addr_is_ipv6_link_local(next_hop);
    bool stable_only = false;

    /* We have IP next hop - figure out the MAC address */
    if (addr_is_ipv6_multicast(next_hop)) {
        buf->dst_sa.addr_type = ADDR_BROADCAST;
        common_write_16_bit(cur->mac_parameters->pan_id, buf->dst_sa.address);
        buf->dst_sa.address[2] = 0x80 | (next_hop[14] & 0x1f);
        buf->dst_sa.address[3] = next_hop[15];
        stable_only = true;
    } else { /* unicast */
        ipv6_neighbour_t *n = ipv6_interface_resolve_new(cur, buf);
        if (!n) {
            return NULL;
        }
        if (thread_info(cur)) {
            stable_only = thread_stable_context_check(cur, buf);
        }
    }

    if (!buf->link_specific.ieee802_15_4.useDefaultPanId) {
        /* Override dest PAN ID (from multicast map above, or neighbour cache) */
        common_write_16_bit(buf->link_specific.ieee802_15_4.dstPanId, buf->dst_sa.address);
    }

    /* Figure out which source MAC address to use. Usually try to match the
     * source, for best compression, and to ensure if the layer above uses LL64
     * (like MLE), it forces us to use our MAC64.
     */
    if (thread_info(cur) && !(link_local && thread_insist_that_mesh_isnt_a_link(cur)) && buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) {
        /* For Thread, we want to always use short source address for unicast
         * to non-link-local 16-bit addresses, which is the case where we want
         * to use mesh headers.
         */
        buf->src_sa.addr_type = ADDR_802_15_4_SHORT;
    } else if (addr_iid_matches_eui64(ip_src + 8, cur->mac)) {
        buf->src_sa.addr_type = ADDR_802_15_4_LONG;
    } else if (cur->mac_parameters->mac_short_address < 0xfffe && addr_iid_matches_lowpan_short(ip_src + 8, cur->mac_parameters->mac_short_address)) {
        buf->src_sa.addr_type = ADDR_802_15_4_SHORT;
    } else {
        /* This lets mac_mlme_write_our_addr choose based on address mode */
        buf->src_sa.addr_type = ADDR_NONE;
    }

    if (!mac_helper_write_our_addr(cur, &buf->src_sa)) {
        return buffer_free(buf);
    }

    /* Clear Link Layer Re Transmission Counter */
    //buf->fhss_channel_retries_left = 1+ cur->mac_parameters->number_of_fhss_channel_retries;


    if (buf->dst_sa.addr_type != ADDR_802_15_4_LONG && buf->dst_sa.addr_type != ADDR_802_15_4_SHORT && buf->dst_sa.addr_type != ADDR_BROADCAST) {
        tr_debug("IP:Dest Pro. addr_type: %02x", buf->dst_sa.addr_type);
        return buffer_free(buf);
    }

    uint_fast8_t mesh_size;
    if (link_local && thread_insist_that_mesh_isnt_a_link(cur)) {
        mesh_size = 0;
    } else {
        /* Allow the link-layer destination addresses passed from upper layers
         * to be remapped - used to implement Thread anycast.
         *
         * Mapping function can change address and type - if it returns false,
         * packet is dropped.
         *
         * Note that this mapping has to be done before IPHC compression, which
         * is why it moved from mesh.c.
         */
        if (!mesh_address_map(cur, &buf->dst_sa.addr_type, buf->dst_sa.address)) {
            tr_debug("mesh_address_map fail");
            return buffer_free(buf);
        }

        /* After mapping, compute final mesh header size (which depends on
         * the final address).
         */
        mesh_size = mesh_header_size(buf);
    }

    if (mesh_size == 0) {
        if (buf->dst_sa.addr_type == ADDR_BROADCAST) {
            /* Thread says multicasts other than MLE are sent to our parent, if we're an end device */
            if (cur->ip_multicast_as_mac_unicast_to_parent && !buf->options.ll_broadcast_tx) {
                if (protocol_6lowpan_interface_get_mac_coordinator_address(cur, &buf->dst_sa) < 0) {
                    tr_warn("IP: No parent for multicast as unicast");
                    return buffer_free(buf);
                }
            } else {
                /*
                 * Not using a mesh header, so have to "purify" RFC 4944 multicast - we
                 * set a 100xxxxxxxxxxxxx RFC 4944 multicast address above, but
                 * IEEE 802.15.4 only supports broadcast in the real MAC header.
                 */
                common_write_16_bit(0xFFFF, buf->dst_sa.address + 2);
            }
        }
    }

    /* RFC 6282+4944 require that we limit compression to the first fragment.
     * This check is slightly conservative - always allow 4 for first-fragment header
     */
    uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf);
    uint_fast16_t max_iphc_size = mac_helper_max_payload_size(cur, overhead) - mesh_size - 4;

    buf = iphc_compress(&cur->lowpan_contexts, buf, max_iphc_size, stable_only);
    if (!buf) {
        return NULL;
    }

    if (mesh_size != 0) {
        buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING | B_DIR_DOWN);
        return buf;
    }

    buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MAC | B_DIR_DOWN);

    return buf;
}