Merge branch 'feature/otbr-1.3' into 'master'

openthread: support 1.3 border routing features

See merge request espressif/esp-idf!14407
This commit is contained in:
Shu Chen 2021-07-21 08:01:26 +00:00
commit 80f03f4820
12 changed files with 179 additions and 26 deletions

@ -1 +1 @@
Subproject commit 46396c46bd3c4d459b194e0e9273ff004158b993 Subproject commit efbc05d641040253567e825dae53731da595c7b5

View File

@ -40,7 +40,7 @@ int __weak lwip_hook_netconn_external_resolve(const char *name, ip_addr_t *addr,
#endif #endif
#ifdef CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT #ifdef CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT
const ip6_addr_t *lwip_hook_nd6_get_gw(struct netif *netif, const ip6_addr_t *dest) const ip6_addr_t *__weak lwip_hook_nd6_get_gw(struct netif *netif, const ip6_addr_t *dest)
{ {
LWIP_UNUSED_ARG(netif); LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(dest); LWIP_UNUSED_ARG(dest);

View File

@ -11,23 +11,20 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License // limitations under the License
#include <string.h> #include <string.h>
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_netif_net_stack.h" #include "esp_netif_net_stack.h"
#include "lwip/netif.h" #include "lwip/netif.h"
#include "lwip/pbuf.h"
#include "netif/openthreadif.h" #include "netif/openthreadif.h"
#include "openthread/error.h"
#include "openthread/ip6.h" #include "openthread/ip6.h"
#include "openthread/link.h" #include "openthread/link.h"
#include "openthread/message.h"
#define OPENTHREAD_IP6_MTU 1280 #define OPENTHREAD_IP6_MTU 1280
static void openthread_free_rx_buf_l2(struct netif *netif, void *buf)
{
free(buf);
}
static err_t openthread_output_ip6(struct netif *netif, struct pbuf *p, const struct ip6_addr *peer_addr) static err_t openthread_output_ip6(struct netif *netif, struct pbuf *p, const struct ip6_addr *peer_addr)
{ {
struct pbuf *q = p; struct pbuf *q = p;
@ -69,24 +66,26 @@ void openthread_netif_input(void *h, void *buffer, size_t len, void *eb)
{ {
struct netif *netif = h; struct netif *netif = h;
struct pbuf *p; struct pbuf *p;
otMessage *message = (otMessage *)buffer;
if (unlikely(buffer == NULL || !netif_is_up(netif))) { if (unlikely(buffer == NULL || !netif_is_up(netif))) {
if (buffer) {
openthread_free_rx_buf_l2(netif, buffer);
}
return; return;
} }
/* acquire new pbuf, type: PBUF_REF */ /* Allocate LINK buffer in case it's forwarded to WiFi/ETH */
p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
if (p == NULL) { if (p == NULL) {
openthread_free_rx_buf_l2(netif, buffer); LWIP_DEBUGF(NETIF_DEBUG, ("Failed to allocate input pbuf for OpenThread netif\n"));
return; return;
} }
p->payload = buffer;
if (unlikely(otMessageRead(message, 0, p->payload, len) != OT_ERROR_NONE)) {
LWIP_DEBUGF(NETIF_DEBUG, ("Failed to read OpenThread message\n"));
}
#if ESP_LWIP #if ESP_LWIP
p->l2_owner = netif; p->l2_owner = NULL;
p->l2_buf = buffer; p->l2_buf = NULL;
#endif #endif
/* full packet send to tcpip_thread to process */ /* full packet send to tcpip_thread to process */
if (unlikely(netif->input(p, netif) != ERR_OK)) { if (unlikely(netif->input(p, netif) != ERR_OK)) {
@ -106,7 +105,7 @@ err_t openthread_netif_init(struct netif *netif)
netif->flags = NETIF_FLAG_BROADCAST; netif->flags = NETIF_FLAG_BROADCAST;
netif->output = NULL; netif->output = NULL;
netif->output_ip6 = openthread_output_ip6; netif->output_ip6 = openthread_output_ip6;
netif->l2_buffer_free_notify = openthread_free_rx_buf_l2; netif->l2_buffer_free_notify = NULL;
netif_set_link_up(netif); netif_set_link_up(netif);
return ERR_OK; return ERR_OK;

View File

@ -4,7 +4,6 @@ if(CONFIG_OPENTHREAD_ENABLED)
"openthread/include") "openthread/include")
set(private_include_dirs set(private_include_dirs
"openthread/include/openthread"
"openthread/src" "openthread/src"
"openthread/src/core" "openthread/src/core"
"openthread/src/lib/hdlc" "openthread/src/lib/hdlc"
@ -38,11 +37,15 @@ if(CONFIG_OPENTHREAD_ENABLED)
endif() endif()
set(exclude_srcs set(exclude_srcs
"openthread/examples/apps/cli/main.cpp" "openthread/examples/apps/cli/main.c"
"openthread/examples/platforms/utils/logging_rtt.c" "openthread/examples/platforms/utils/logging_rtt.c"
"openthread/examples/platforms/utils/soft_source_match_table.c" "openthread/examples/platforms/utils/soft_source_match_table.c"
"openthread/src/core/common/extension_example.cpp") "openthread/src/core/common/extension_example.cpp")
set_source_files_properties("openthread/src/core/net/srp_server.cpp"
PROPERTIES COMPILE_FLAGS
-Wno-maybe-uninitialized)
if(CONFIG_OPENTHREAD_FTD) if(CONFIG_OPENTHREAD_FTD)
set(device_type "OPENTHREAD_FTD=1") set(device_type "OPENTHREAD_FTD=1")
elseif(CONFIG_OPENTHREAD_MTD) elseif(CONFIG_OPENTHREAD_MTD)

View File

@ -34,6 +34,10 @@ COMPONENT_SRCDIRS := \
openthread/src/lib/spinel \ openthread/src/lib/spinel \
port port
ifdef CONFIG_OPENTHREAD_BORDER_ROUTER
COMPONENT_SRCDIRS += openthread/src/core/border_router
endif
COMPONENT_OBJEXCLUDE := \ COMPONENT_OBJEXCLUDE := \
openthread/examples/apps/cli/main.o \ openthread/examples/apps/cli/main.o \
openthread/src/core/common/extension_example.o \ openthread/src/core/common/extension_example.o \
@ -54,7 +58,8 @@ OPENTHREAD_PACKAGE_VERSION := $(IDF_VERSION_FOR_OPENTHREAD_PACKAGE)-$(OPENTHREAD
COMMON_FLAGS := \ COMMON_FLAGS := \
-DOPENTHREAD_CONFIG_FILE=\<openthread-core-esp32x-config.h\> \ -DOPENTHREAD_CONFIG_FILE=\<openthread-core-esp32x-config.h\> \
-DPACKAGE_VERSION=\"OPENTHREAD_PACKAGE_VERSION\" -DPACKAGE_VERSION=\"OPENTHREAD_PACKAGE_VERSION\" \
-Wno-maybe-uninitialized
ifdef CONFIG_OPENTHREAD_FTD ifdef CONFIG_OPENTHREAD_FTD
COMMON_FLAGS += -DOPENTHREAD_FTD=1 COMMON_FLAGS += -DOPENTHREAD_FTD=1

View File

@ -17,6 +17,7 @@
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_netif_types.h" #include "esp_netif_types.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "openthread/instance.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -33,10 +34,23 @@ extern "C" {
* @return * @return
* - ESP_OK on success * - ESP_OK on success
* - ESP_ERR_NOT_SUPPORTED if feature not supported * - ESP_ERR_NOT_SUPPORTED if feature not supported
* - ESP_ERR_INVALID_STATE if already initialized
* - ESP_FIAL on other failures
* *
*/ */
esp_err_t esp_openthread_border_router_init(esp_netif_t *backbone_netif); esp_err_t esp_openthread_border_router_init(esp_netif_t *backbone_netif);
/**
* @brief Deinitializes the border router features of OpenThread.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if not initialized
* - ESP_FIAL on other failures
*
*/
esp_err_t esp_openthread_border_router_deinit(void);
/** /**
* @brief Gets the backbone interface of OpenThread border router. * @brief Gets the backbone interface of OpenThread border router.
* *

View File

@ -105,6 +105,7 @@
*/ */
#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 #define OPENTHREAD_CONFIG_COAP_API_ENABLE 1
/** /**
* @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE * @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
* *
@ -115,6 +116,16 @@
#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1 #define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1
#endif #endif
/**
* @def OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
*
* Enable the external heap.
*
*/
#ifndef OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
#define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 1
#endif
#if CONFIG_OPENTHREAD_BORDER_ROUTER #if CONFIG_OPENTHREAD_BORDER_ROUTER
/** /**
@ -137,6 +148,16 @@
#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1
#endif #endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
*
* Define to 1 to enable Border Routing support.
*
*/
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#define OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 1
#endif
/** /**
* @def OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE * @def OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
* *
@ -147,6 +168,26 @@
#define OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE 1 #define OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE 1
#endif #endif
/**
* @def OPENTHREAD_CONFIG_ECDSA_ENABLE
*
* Define to 1 to enable ECDSA support.
*
*/
#ifndef OPENTHREAD_CONFIG_ECDSA_ENABLE
#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
*
* Define to 1 to enable SRP Server support.
*
*/
#ifndef OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 1
#endif
#endif // CONFIG_OPENTHREAD_BORDER_ROUTER #endif // CONFIG_OPENTHREAD_BORDER_ROUTER
/** /**

@ -1 +1 @@
Subproject commit d84f8967f8ce14490e19433b85c8c363d424f4c1 Subproject commit 105f3610d2258d7a7dd1c72f5f1adea89077c6cc

@ -1 +1 @@
Subproject commit d16edaa5ef73e9139ac9c9d3b71981bf21a5de17 Subproject commit a662c32eb074cc624bf344f810f65f8637a89552

View File

@ -146,3 +146,80 @@ I(552749) OPENTHREAD:[INFO]-UTIL----: Starting Child Supervision
``` ```
The device has now joined the same Thread network based on the key set by the commissioner. The device has now joined the same Thread network based on the key set by the commissioner.
## Bidirectional IPv6 connectivity
The border router will automatically publish the prefix and the route table rule to the WiFi network via ICMPv6 router advertisment packages.
### Host configuration
The automatically configure your host's route table rules you need to set these sysctl options:
Please relace `wlan0` with the real name of your WiFi network interface.
```
sudo sysctl -w net/ipv6/conf/wlan0/accept_ra=2
sudo sysctl -w net/ipv6/conf/wlan0/accept_ra_rt_info_max_plen=128
```
For mobile devices, the route table rules will be automatically configured after iOS 14 and Android 8.1.
### Testing IPv6 connecitivity
Now in the joining device, check the IP addresses:
```
> ipaddr
fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5
fdde:ad00:beef:0:0:ff:fe00:c402
fdde:ad00:beef:0:ad4a:9a9a:3cd6:e423
fe80:0:0:0:f011:2951:569e:9c4a
```
You'll notice an IPv6 global prefix with only on address assigned under it. This is the routable address of this Thread node.
You can ping this address on your host:
``` bash
$ ping fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5
PING fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5(fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5) 56 data bytes
64 bytes from fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5: icmp_seq=1 ttl=63 time=459 ms
64 bytes from fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5: icmp_seq=2 ttl=63 time=109 ms
64 bytes from fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5: icmp_seq=3 ttl=63 time=119 ms
64 bytes from fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5: icmp_seq=4 ttl=63 time=117 ms
```
## Service discovery
The newly introduced service registration protocol([SRP](https://datatracker.ietf.org/doc/html/draft-ietf-dnssd-srp-10)) allows devices in the Thread network to register a service. The border router will forward the service to the WiFi network via mDNS.
Now we'll publish the service `my-service._test._udp` with hostname `test0` and port 12345
```
> srp client host name test0
Done
> srp client host address fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5
Done
> srp client service add my-service _test._udp 12345
Done
> srp client autostart enable
Done
```
This service will also become visible on the WiFi network:
```bash
$ avahi-browse -r _test._udp -t
+ enp1s0 IPv6 my-service _test._udp local
= enp1s0 IPv6 my-service _test._udp local
hostname = [test0.local]
address = [fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5]
port = [12345]
txt = []
+ enp1s0 IPv4 my-service _test._udp local
= enp1s0 IPv4 my-service _test._udp local
hostname = [test0.local]
address = [fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5]
port = [12345]
txt = []
```

View File

@ -30,6 +30,7 @@
#include "esp_ot_config.h" #include "esp_ot_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "mdns.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "protocol_examples_common.h" #include "protocol_examples_common.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@ -109,18 +110,19 @@ static void create_config_network(otInstance *instance)
abort(); abort();
} }
dataset.mComponents.mIsExtendedPanIdPresent = true; dataset.mComponents.mIsExtendedPanIdPresent = true;
if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_MASTERKEY, dataset.mMasterKey.m8, if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_MASTERKEY, dataset.mNetworkKey.m8,
sizeof(dataset.mMasterKey.m8)) != sizeof(dataset.mMasterKey.m8)) { sizeof(dataset.mNetworkKey.m8)) != sizeof(dataset.mNetworkKey.m8)) {
ESP_LOGE(TAG, "Cannot convert OpenThread master key. Please double-check your config."); ESP_LOGE(TAG, "Cannot convert OpenThread master key. Please double-check your config.");
abort(); abort();
} }
dataset.mComponents.mIsMasterKeyPresent = true; dataset.mComponents.mIsNetworkKeyPresent = true;
if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_PSKC, dataset.mPskc.m8, sizeof(dataset.mPskc.m8)) != if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_PSKC, dataset.mPskc.m8, sizeof(dataset.mPskc.m8)) !=
sizeof(dataset.mPskc.m8)) { sizeof(dataset.mPskc.m8)) {
ESP_LOGE(TAG, "Cannot convert OpenThread pre-shared commissioner key. Please double-check your config."); ESP_LOGE(TAG, "Cannot convert OpenThread pre-shared commissioner key. Please double-check your config.");
abort(); abort();
} }
dataset.mComponents.mIsPskcPresent = true; dataset.mComponents.mIsPskcPresent = true;
dataset.mComponents.mIsMeshLocalPrefixPresent = false;
if (otDatasetSetActive(instance, &dataset) != OT_ERROR_NONE) { if (otDatasetSetActive(instance, &dataset) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread active dataset."); ESP_LOGE(TAG, "Failed to set OpenThread active dataset.");
abort(); abort();
@ -188,5 +190,7 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect()); ESP_ERROR_CHECK(example_connect());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
xTaskCreate(ot_task_worker, "ot_br_main", 20480, xTaskGetCurrentTaskHandle(), 5, NULL); xTaskCreate(ot_task_worker, "ot_br_main", 20480, xTaskGetCurrentTaskHandle(), 5, NULL);
} }

View File

@ -36,6 +36,16 @@ CONFIG_OPENTHREAD_BORDER_ROUTER=y
# #
# lwIP # lwIP
# #
CONFIG_LWIP_IPV6_FORWARD=y
CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
CONFIG_LWIP_MULTICAST_PING=y CONFIG_LWIP_MULTICAST_PING=y
CONFIG_LWIP_NETIF_STATUS_CALLBACK=y
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# end of lwIP # end of lwIP
#
# mDNS
#
CONFIG_MDNS_STRICT_MODE=y
# end of mDNS