Skip to content

Commit 16c8a16

Browse files
Cristib05kartben
authored andcommitted
modules: openthread: Add new Border Router functionalities.
This commit brings new platform files: -`border_agent` -`udp` -`mdns_socket` -'trel' This commit also makes use of existing Openthread task to process border router messages. Signed-off-by: Cristian Bulacu <[email protected]>
1 parent 2928670 commit 16c8a16

File tree

11 files changed

+1445
-19
lines changed

11 files changed

+1445
-19
lines changed

modules/openthread/Kconfig

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,13 +356,56 @@ config OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS
356356
help
357357
Enable support for functions such as modulated carrier and continuous carrier.
358358

359+
menu "OpenThread Border Router"
360+
359361
config OPENTHREAD_ZEPHYR_BORDER_ROUTER
360362
bool "Adds support for Border Router functionality [EXPERIMENTAL]"
361363
select EXPERIMENTAL
362364
imply NET_ROUTING
363365
help
364366
Enable support for Border Router using Openthread's implementation.
365367

368+
if OPENTHREAD_ZEPHYR_BORDER_ROUTER
369+
370+
config OPENTHREAD_ZEPHYR_BORDER_ROUTER_VENDOR_NAME
371+
string "Base name from which mDNS host name will be derived."
372+
default "Zephyr-OTBR"
373+
help
374+
This value represents part of the mDNS host that will be register within OpenThread
375+
Border Router.
376+
377+
config OPENTHREAD_ZEPHYR_BORDER_ROUTER_BASE_SERVICE_NAME
378+
string "Base name from which a service instance name will be derived."
379+
default "Zephyr-BorderRouter"
380+
help
381+
This value represents part of a service instance name which will be registered
382+
within OpenThread Border Router.
383+
384+
config OPENTHREAD_ZEPHYR_BORDER_ROUTER_MODEL_NAME
385+
string "Name of the Border Agent product model"
386+
default "BorderRouter"
387+
help
388+
This value represents Border Agent's product model.
389+
390+
config OPENTHREAD_ZEPHYR_BORDER_ROUTER_MAX_UDP_SERVICES
391+
int "The maximum number of pollable UDP sockets to be registered in platform UDP."
392+
depends on OPENTHREAD_ZEPHYR_BORDER_ROUTER
393+
default 5
394+
help
395+
This configuration defines the maximum number of pollable UDP sockets
396+
to be used within platform UDP module.
397+
398+
config OPENTHREAD_ZEPHYR_BORDER_ROUTER_MSG_POOL_NUM
399+
int "Maximum entries of backbone message pool."
400+
default 10
401+
help
402+
This value represents the maximum number of messages from backbone interface
403+
that could be stored without being processed.
404+
405+
endif # OPENTHREAD_ZEPHYR_BORDER_ROUTER
406+
407+
endmenu # "OpenThread Border Router"
408+
366409
menu "OpenThread stack features"
367410
rsource "Kconfig.features"
368411
endmenu

modules/openthread/include/openthread.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ int openthread_mutex_try_lock(void);
156156
*/
157157
void openthread_mutex_unlock(void);
158158

159+
#if defined(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER)
160+
/**
161+
* @brief Notify OpenThread task about Border Router pending work.
162+
*/
163+
void openthread_notify_border_router_work(void);
164+
#endif /* CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER */
165+
159166
#ifdef __cplusplus
160167
}
161168
#endif

modules/openthread/openthread.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ LOG_MODULE_REGISTER(net_openthread_platform, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVE
4343
#include <openthread/nat64.h>
4444
#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
4545

46+
#if defined(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER)
47+
#include "openthread_border_router.h"
48+
#endif /* CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER */
49+
4650
#define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE)
4751

4852
#if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE)
@@ -513,6 +517,17 @@ void openthread_mutex_unlock(void)
513517
(void)k_mutex_unlock(&openthread_lock);
514518
}
515519

520+
#if defined(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER)
521+
void openthread_notify_border_router_work(void)
522+
{
523+
int error = k_work_submit_to_queue(&openthread_work_q, &openthread_border_router_work);
524+
525+
if (error < 0) {
526+
LOG_ERR("Failed to submit work to queue, error: %d", error);
527+
}
528+
}
529+
#endif /* CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER */
530+
516531
#ifdef CONFIG_OPENTHREAD_SYS_INIT
517532
static int openthread_sys_init(void)
518533
{

modules/openthread/platform/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ zephyr_library_sources_ifdef(CONFIG_SETTINGS settings.c)
2929
zephyr_library_sources_ifndef(CONFIG_LOG_BACKEND_SPINEL logging.c)
3030

3131
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER infra_if.c)
32+
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER udp.c)
33+
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER mdns_socket.c)
34+
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER border_agent.c)
35+
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER trel.c)
3236

3337
zephyr_include_directories(.)
3438

3539
if(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER)
3640
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip)
37-
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2/openthread)
41+
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets)
42+
zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/l2/openthread)
3843
endif()
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <platform-zephyr.h>
8+
#include <openthread/border_agent.h>
9+
#include <openthread/cli.h>
10+
#include <openthread/dns.h>
11+
#include <openthread/thread.h>
12+
#include <openthread/verhoeff_checksum.h>
13+
#include <openthread/platform/entropy.h>
14+
#include "common/code_utils.hpp"
15+
#include "openthread_border_router.h"
16+
#include <zephyr/sys/byteorder.h>
17+
#include <string.h>
18+
#include <stdlib.h>
19+
#include <inttypes.h>
20+
#include <zephyr/kernel.h>
21+
#include <zephyr/shell/shell.h>
22+
23+
static struct otInstance *ot_instance_ptr;
24+
static bool border_agent_is_init;
25+
26+
#if defined(CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)
27+
/* Byte values, 9 bytes for the key, one for null terminator. */
28+
static uint8_t ephemeral_key_string[10];
29+
30+
static uint32_t ephemeral_key_timeout;
31+
static bool epskc_active;
32+
33+
static otError generate_ephemeral_key(void);
34+
static void handle_border_agent_ephemeral_key_callback(void *context);
35+
static otError border_agent_enable_epskc_service(uint32_t timeout);
36+
37+
/* shell related functions */
38+
static int border_agent_eph_key_shell_cmd(const struct shell *sh, size_t argc, char **argv);
39+
static int border_agent_eph_key_run(size_t argc, char **argv);
40+
41+
#endif /* CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE */
42+
43+
static void append_vendor_txt_data(uint8_t *txt_data, uint16_t *txt_data_len);
44+
45+
otError border_agent_init(otInstance *instance)
46+
{
47+
otError error = OT_ERROR_NONE;
48+
49+
ot_instance_ptr = instance;
50+
51+
if (!border_agent_is_init) {
52+
uint8_t txt_buffer[128] = {0};
53+
uint16_t txt_buffer_len = 0;
54+
55+
VerifyOrExit(otBorderAgentSetMeshCoPServiceBaseName(instance,
56+
otbr_base_service_instance_name)
57+
== OT_ERROR_NONE, error = OT_ERROR_FAILED);
58+
append_vendor_txt_data(txt_buffer, &txt_buffer_len);
59+
otBorderAgentSetVendorTxtData(instance, txt_buffer, txt_buffer_len);
60+
#if defined(CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)
61+
otBorderAgentEphemeralKeySetEnabled(instance, true);
62+
otBorderAgentEphemeralKeySetCallback(instance,
63+
handle_border_agent_ephemeral_key_callback,
64+
instance);
65+
#endif /* CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE */
66+
67+
border_agent_is_init = true;
68+
}
69+
exit:
70+
return error;
71+
}
72+
73+
void border_agent_deinit(void)
74+
{
75+
#if defined(CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)
76+
otBorderAgentEphemeralKeySetEnabled(ot_instance_ptr, false);
77+
epskc_active = false;
78+
#endif /* CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE */
79+
border_agent_is_init = false;
80+
}
81+
82+
static void append_vendor_txt_data(uint8_t *txt_data, uint16_t *txt_data_len)
83+
{
84+
*txt_data_len = 0;
85+
size_t i = 0;
86+
otDnsTxtEntry txt_entries[] = {
87+
{.mKey = "vn", .mValue = (uint8_t *)otbr_vendor_name,
88+
.mValueLength = strlen(otbr_vendor_name)},
89+
{.mKey = "mn", .mValue = (uint8_t *)otbr_model_name,
90+
.mValueLength = strlen(otbr_model_name)}};
91+
92+
for (i = 0; i < ARRAY_SIZE(txt_entries); ++i) {
93+
const otDnsTxtEntry *entry = &txt_entries[i];
94+
uint8_t key_len = (uint8_t)strlen(entry->mKey);
95+
uint8_t total_len = key_len + 1 + entry->mValueLength; /* +1 for '=' */
96+
97+
txt_data[(*txt_data_len)++] = total_len;
98+
memcpy(txt_data + *txt_data_len, entry->mKey, key_len);
99+
*txt_data_len += key_len;
100+
101+
txt_data[(*txt_data_len)++] = '=';
102+
memcpy(txt_data + *txt_data_len, entry->mValue, entry->mValueLength);
103+
*txt_data_len += entry->mValueLength;
104+
}
105+
106+
}
107+
108+
#if defined(CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)
109+
110+
/** Defining functions below as weak allows applications to implement their specific behaviour,
111+
* i.e., custom messages/used print function.
112+
*/
113+
__weak void print_ephemeral_key(const char *ephemeral_key, uint32_t timeout)
114+
{
115+
otCliOutputFormat("\r\n Use this passcode to enable an additional device to administer "
116+
"and manage your Thread network, including adding new devices to it. "
117+
"\r\nThis passcode is not required for an app to communicate with "
118+
"existing devices on your Thread network.");
119+
otCliOutputFormat("\r\n\nePSKc : %s", ephemeral_key);
120+
otCliOutputFormat("\r\n\nValid for %" PRIu32 " seconds.\r\n", timeout);
121+
}
122+
123+
__weak void print_ephemeral_key_expired_message(void)
124+
{
125+
otCliOutputFormat("\r\nEphemeral Key disabled.\r\n");
126+
}
127+
128+
static otError generate_ephemeral_key(void)
129+
{
130+
otError error = OT_ERROR_NONE;
131+
uint8_t i = 0;
132+
uint32_t random;
133+
char verhoeff_checksum;
134+
135+
memset(ephemeral_key_string, 0, sizeof(ephemeral_key_string));
136+
137+
VerifyOrExit(otPlatEntropyGet((uint8_t *)&random, sizeof(random)) == OT_ERROR_NONE,
138+
error = OT_ERROR_FAILED);
139+
random %= 100000000;
140+
i += snprintf((char *)ephemeral_key_string, sizeof(ephemeral_key_string),
141+
"%08u", random);
142+
VerifyOrExit(otVerhoeffChecksumCalculate((const char *)ephemeral_key_string,
143+
&verhoeff_checksum) == OT_ERROR_NONE,
144+
error = OT_ERROR_FAILED);
145+
snprintf((char *)&ephemeral_key_string[i], sizeof(ephemeral_key_string) - i,
146+
"%c", verhoeff_checksum);
147+
exit:
148+
return error;
149+
}
150+
151+
static void handle_border_agent_ephemeral_key_callback(void *context)
152+
{
153+
char formatted_epskc[12] = {0};
154+
otBorderAgentEphemeralKeyState eph_key_state;
155+
156+
eph_key_state = otBorderAgentEphemeralKeyGetState((otInstance *)context);
157+
158+
switch (eph_key_state) {
159+
case OT_BORDER_AGENT_STATE_STOPPED:
160+
if (epskc_active) {
161+
epskc_active = false;
162+
print_ephemeral_key_expired_message();
163+
}
164+
break;
165+
166+
case OT_BORDER_AGENT_STATE_STARTED:
167+
snprintf(formatted_epskc, sizeof(formatted_epskc), "%.3s %.3s %.3s",
168+
ephemeral_key_string, ephemeral_key_string + 3,
169+
ephemeral_key_string + 6);
170+
print_ephemeral_key(formatted_epskc, (uint32_t)(ephemeral_key_timeout / 1000UL));
171+
epskc_active = true;
172+
break;
173+
174+
case OT_BORDER_AGENT_STATE_CONNECTED:
175+
/* connected to */
176+
case OT_BORDER_AGENT_STATE_ACCEPTED:
177+
default:
178+
break;
179+
}
180+
}
181+
static otError border_agent_enable_epskc_service(uint32_t timeout)
182+
{
183+
otError error = OT_ERROR_NONE;
184+
185+
VerifyOrExit(border_agent_is_init, error = OT_ERROR_INVALID_STATE);
186+
187+
ephemeral_key_timeout = (timeout &&
188+
timeout >= OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT &&
189+
timeout <= OT_BORDER_AGENT_MAX_EPHEMERAL_KEY_TIMEOUT) ?
190+
timeout : OT_BORDER_AGENT_DEFAULT_EPHEMERAL_KEY_TIMEOUT;
191+
192+
VerifyOrExit((generate_ephemeral_key() == OT_ERROR_NONE), error = OT_ERROR_FAILED);
193+
error = otBorderAgentEphemeralKeyStart(ot_instance_ptr,
194+
(const char *)ephemeral_key_string,
195+
ephemeral_key_timeout, 0);
196+
197+
exit:
198+
return error;
199+
}
200+
201+
static int border_agent_eph_key_run(size_t argc, char **argv)
202+
{
203+
if (strcmp(argv[1], "enable") == 0) {
204+
uint32_t timeout = (argc >= 1) ? strtoul(argv[2], NULL, 10) : 0;
205+
206+
if (border_agent_enable_epskc_service(timeout) != OT_ERROR_NONE) {
207+
otCliOutputFormat("Invalid state\r\n");
208+
}
209+
return 0;
210+
}
211+
212+
if (strcmp(argv[1], "help") == 0) {
213+
otCliOutputFormat("ephkey enable [timeout-in-msec]\r\n");
214+
}
215+
216+
return 0;
217+
}
218+
219+
static int border_agent_eph_key_shell_cmd(const struct shell *sh, size_t argc, char **argv)
220+
{
221+
if (argc < 2) {
222+
shell_help(sh);
223+
return -ENOEXEC;
224+
}
225+
226+
border_agent_eph_key_run(argc, argv);
227+
228+
return 0;
229+
}
230+
#endif /* CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE */
231+
232+
#if defined(CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)
233+
SHELL_CMD_ARG_REGISTER(ephkey, NULL, "Ephemeral key support", border_agent_eph_key_shell_cmd, 2,
234+
CONFIG_SHELL_ARGC_MAX);
235+
#endif /* CONFIG_OPENTHREAD_BORDER_AGENT_EPHEMERAL_KEY_ENABLE */

0 commit comments

Comments
 (0)