Nanostack Border Router is a generic mbed border router implementation that provides the 6LoWPAN ND or Thread border router initialization logic.

Revision:
0:85f4174a8e29
Child:
4:0a9d1eeaa905
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/thread_br_conn_handler.c	Thu Mar 09 17:47:03 2017 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016 ARM Limited. All rights reserved.
+ */
+
+#include <string.h>
+#include "net_interface.h"
+#include "mbed-trace/mbed_trace.h"
+#include "thread_border_router_api.h"
+#include "thread_br_conn_handler.h"
+#include "thread_dhcpv6_server.h"
+#include "borderrouter_helpers.h"
+#include "common_functions.h"
+#include "eventOS_event_timer.h"
+#include "thread_bbr_ext.h"
+
+#define TRACE_GROUP "TBRH"
+#define DHCP_SERVER_SHUTDOWN_TIMEOUT (100)
+
+typedef struct {
+    
+    uint8_t dhcp_prefix[16];
+    timeout_t *thread_dhcp_shutdown_timer;
+    uint8_t dhcp_prefix_len;
+    int8_t  thread_interface_id;
+    int8_t  eth_interface_id;
+    bool    eth_connection_ready;
+    bool    thread_connection_ready;
+    bool    dhcp_server_running;
+} thread_br_handler_t;
+
+static thread_br_handler_t thread_br_handler;
+static void thread_br_conn_handler_border_router_startup_attempt(void);
+static bool thread_br_conn_handler_default_route_enable(void);
+static void thread_br_conn_handler_dhcp_server_stop_cb(void *arg);
+static void thread_br_conn_handler_border_router_shutdown_request(void);
+
+
+void thread_br_conn_handler_init(void)
+{
+    thread_br_handler.eth_connection_ready = false;
+    thread_br_handler.thread_connection_ready = false;    
+    thread_br_handler.dhcp_server_running = false;
+    thread_br_handler.dhcp_prefix_len = 0;
+    thread_br_handler.thread_interface_id = -1;
+    thread_br_handler.eth_interface_id = -1;    
+    thread_br_handler.thread_dhcp_shutdown_timer = NULL;
+    memset(thread_br_handler.dhcp_prefix, 0, 16);
+}
+
+static void thread_br_conn_handler_border_router_startup_attempt(void)
+{
+    if (thread_br_handler.thread_dhcp_shutdown_timer != NULL) {
+        tr_debug("DHCP server already running, enable default_route");
+        eventOS_timeout_cancel(thread_br_handler.thread_dhcp_shutdown_timer);
+        thread_br_handler.thread_dhcp_shutdown_timer = NULL;
+    }
+
+    if (!thread_br_handler.eth_connection_ready) {
+        tr_debug("eth0 is down");
+        return;
+    } else if (!thread_br_handler.thread_connection_ready) {
+        tr_debug("mesh0 is down");
+        return;
+    }
+
+    if (thread_br_handler.dhcp_prefix_len == 0) {
+        //No prefix/prefix_len to start DHCP server
+        tr_error("DHCP server prefix length = 0");
+        return;
+    }
+
+    if (thread_br_handler.thread_interface_id == -1) {
+        tr_error("Thread interface ID not set");
+        return;
+    }
+
+    if (thread_br_handler.dhcp_server_running == true) {
+        // DHCP server is already running, enable default route
+        tr_debug("DHCP server already running, enable default_route");
+        thread_br_conn_handler_default_route_enable();
+        return;
+    }
+
+    int retcode = thread_dhcpv6_server_add(thread_br_handler.thread_interface_id, thread_br_handler.dhcp_prefix, 200, true);
+    if (retcode == 0) {
+        tr_debug("DHCP server started ");
+        if (thread_br_conn_handler_default_route_enable()) {
+            thread_br_handler.dhcp_server_running = true;
+            thread_bbr_extension_start(thread_br_handler.thread_interface_id, thread_br_handler.eth_interface_id);
+        } else {
+            tr_error("Failed to update DHCP default route");
+        }
+    } else {
+        tr_error("DHCP server start failed");
+    }
+}
+
+void thread_br_conn_handler_thread_connection_update(bool status)
+{
+    thread_br_handler.thread_connection_ready = status;
+    if (status) {
+        tr_debug("mesh0 connected");
+        thread_br_conn_handler_border_router_startup_attempt();
+    } else {
+        // Thread network down. Reset DHCP server back to original state
+        thread_br_handler.dhcp_server_running = false;
+        if (thread_br_handler.thread_dhcp_shutdown_timer != NULL) {
+            // cancel active shutdown timer
+            eventOS_timeout_cancel(thread_br_handler.thread_dhcp_shutdown_timer);
+            thread_br_handler.thread_dhcp_shutdown_timer = NULL;
+        }
+    }
+}
+
+
+void thread_br_conn_handler_ethernet_connection_update(bool status)
+{
+    thread_br_handler.eth_connection_ready = status;
+    if (status) {
+        tr_debug("Eth0 connected");
+        thread_br_conn_handler_border_router_startup_attempt();
+    } else {
+        // Ethernet connection down, request DHCP server shutdown
+        thread_br_conn_handler_border_router_shutdown_request();
+        tr_debug("Eth0 disconnected");
+    }
+}
+
+void thread_br_conn_handler_eth_ready()
+{    
+    uint8_t prefix_len = 64;
+    uint8_t global_address[16];
+    
+    if (0 == arm_net_address_get(thread_br_conn_handler_eth_interface_id_get(), ADDR_IPV6_GP, global_address)) {
+        tr_info("Ethernet (eth0) bootstrap ready. IP: %s", print_ipv6(global_address));
+    } else {
+        tr_warn("arm_net_address_get fail");
+    }
+    thread_br_handler.dhcp_prefix_len = prefix_len;
+    memset(thread_br_handler.dhcp_prefix, 0, 16);
+    memcpy(thread_br_handler.dhcp_prefix, global_address, prefix_len / 8);
+}
+
+static bool thread_br_conn_handler_default_route_enable(void)
+{
+    thread_border_router_info_t thread_border_router_info;
+    thread_border_router_info.Prf = 1;
+    thread_border_router_info.P_preferred = false;
+    thread_border_router_info.P_slaac = false;
+    thread_border_router_info.P_dhcp = true;
+    thread_border_router_info.P_configure = false;
+    thread_border_router_info.P_default_route = true;
+    thread_border_router_info.P_on_mesh = false;
+    thread_border_router_info.P_nd_dns = false;
+    thread_border_router_info.stableData = true;
+
+    if (thread_border_router_prefix_add(thread_br_handler.thread_interface_id, thread_br_handler.dhcp_prefix, thread_br_handler.dhcp_prefix_len, &thread_border_router_info) == 0) {
+        thread_border_router_publish(thread_br_handler.thread_interface_id);
+        tr_debug("Updated %s prefix", print_ipv6_prefix(thread_br_handler.dhcp_prefix, thread_br_handler.dhcp_prefix_len));
+        return true;
+    } else {
+        tr_error("Failed to enable default_route flag to prefix");
+        return false;
+    }
+}
+
+static void thread_br_conn_handler_dhcp_server_stop_cb(void *arg)
+{
+    (void)arg;
+    thread_br_handler.thread_dhcp_shutdown_timer = NULL;
+    thread_br_handler.dhcp_server_running = false;
+    thread_dhcpv6_server_delete(thread_br_handler.thread_interface_id, thread_br_handler.dhcp_prefix);
+    thread_border_router_publish(thread_br_handler.thread_interface_id);
+
+    tr_debug("DHCP server stop cb");
+    thread_br_handler.dhcp_prefix_len = 0;
+    memset(thread_br_handler.dhcp_prefix, 0, 16);
+}
+
+static void thread_br_conn_handler_border_router_shutdown_request(void)
+{
+    if (thread_br_handler.dhcp_server_running && thread_br_handler.thread_dhcp_shutdown_timer == NULL) {
+        tr_debug("DHCP server shutdown timer started");
+        thread_br_handler.thread_dhcp_shutdown_timer = eventOS_timeout_ms(thread_br_conn_handler_dhcp_server_stop_cb, DHCP_SERVER_SHUTDOWN_TIMEOUT, NULL);
+    }
+}
+
+void thread_br_conn_handler_thread_interface_id_set(int8_t interfaceId)
+{
+    thread_br_handler.thread_interface_id = interfaceId;
+    thread_bbr_extension_mesh_interface_updated_ntf(thread_br_handler.thread_interface_id);
+}
+
+int8_t thread_br_conn_handler_thread_interface_id_get(void)
+{
+    return thread_br_handler.thread_interface_id;
+}
+
+bool thread_br_conn_handler_eth_connection_status_get(void)
+{
+    return thread_br_handler.eth_connection_ready;
+}
+
+bool thread_br_conn_handler_thread_connection_status_get(void)
+{
+    return thread_br_handler.thread_connection_ready;
+}
+
+void thread_br_conn_handler_eth_interface_id_set(int8_t interfaceId)
+{
+    thread_br_handler.eth_interface_id = interfaceId;
+    thread_bbr_extension_bb_interface_updated_ntf(thread_br_handler.eth_interface_id);
+}
+
+int8_t thread_br_conn_handler_eth_interface_id_get(void)
+{
+    return thread_br_handler.eth_interface_id;
+}