mgmt: smp: add UDP transport for SMP
Adds a UDP driver dedicated to transporting mcumgr SMP requests and responses. Signed-off-by: Mikkel Jakobsen <mikkel.aunsbjerg@prevas.dk>
This commit is contained in:
parent
4dcca7f640
commit
7288f51519
6 changed files with 356 additions and 1 deletions
|
@ -435,6 +435,7 @@
|
||||||
/subsys/logging/ @nordic-krch
|
/subsys/logging/ @nordic-krch
|
||||||
/subsys/logging/log_backend_net.c @nordic-krch @jukkar
|
/subsys/logging/log_backend_net.c @nordic-krch @jukkar
|
||||||
/subsys/mgmt/ @carlescufi @nvlsianpu
|
/subsys/mgmt/ @carlescufi @nvlsianpu
|
||||||
|
/subsys/mgmt/smp_udp.c @aunsbjerg
|
||||||
/subsys/net/buf.c @jukkar @jhedberg @tbursztyka @pfalcon
|
/subsys/net/buf.c @jukkar @jhedberg @tbursztyka @pfalcon
|
||||||
/subsys/net/ip/ @jukkar @tbursztyka @pfalcon
|
/subsys/net/ip/ @jukkar @tbursztyka @pfalcon
|
||||||
/subsys/net/lib/ @jukkar @tbursztyka @pfalcon
|
/subsys/net/lib/ @jukkar @tbursztyka @pfalcon
|
||||||
|
|
37
include/mgmt/smp_udp.h
Normal file
37
include/mgmt/smp_udp.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Prevas A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief UDP transport for the mcumgr SMP protocol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_MGMT_SMP_UDP_H_
|
||||||
|
#define ZEPHYR_INCLUDE_MGMT_SMP_UDP_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Opens a UDP socket for the SMP UDP service.
|
||||||
|
*
|
||||||
|
* @return 0 on success; negative error code on failure.
|
||||||
|
*/
|
||||||
|
int smp_udp_open(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes the UDP socket for the SMP UDP service.
|
||||||
|
*
|
||||||
|
* @return 0 on success; negative error code on failure.
|
||||||
|
*/
|
||||||
|
int smp_udp_close(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@ zephyr_library_sources(smp.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_BT smp_bt.c)
|
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_BT smp_bt.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_SHELL smp_shell.c)
|
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_SHELL smp_shell.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_UART smp_uart.c)
|
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_UART smp_uart.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_MCUMGR_SMP_UDP smp_udp.c)
|
||||||
zephyr_library_link_libraries(MCUMGR)
|
zephyr_library_link_libraries(MCUMGR)
|
||||||
|
|
||||||
if (CONFIG_MCUMGR_SMP_SHELL OR CONFIG_MCUMGR_SMP_UART)
|
if (CONFIG_MCUMGR_SMP_SHELL OR CONFIG_MCUMGR_SMP_UART)
|
||||||
|
|
|
@ -64,9 +64,69 @@ config MCUMGR_SMP_UART_MTU
|
||||||
|
|
||||||
source "subsys/mgmt/Kconfig.mcumgr"
|
source "subsys/mgmt/Kconfig.mcumgr"
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP
|
||||||
|
bool "UDP mcumgr SMP transport"
|
||||||
|
select MCUMGR
|
||||||
|
select NETWORKING
|
||||||
|
select NET_UDP
|
||||||
|
select NET_SOCKETS
|
||||||
|
select NET_SOCKETS_POSIX_NAMES
|
||||||
|
help
|
||||||
|
Enables handling of SMP commands received over UDP.
|
||||||
|
Will start a thread for listening on the configured UDP port.
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_IPV4
|
||||||
|
bool "UDP SMP using IPv4"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
depends on NET_IPV4
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Enable SMP UDP using IPv4 addressing.
|
||||||
|
Can be enabled alongside IPv6 addressing.
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_IPV6
|
||||||
|
bool "UDP SMP using IPv6"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
depends on NET_IPV6
|
||||||
|
help
|
||||||
|
Enable SMP UDP using IPv6 addressing.
|
||||||
|
Can be enabled alongside IPv4 addressing.
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_PORT
|
||||||
|
int "UDP SMP port"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
default 1337
|
||||||
|
help
|
||||||
|
UDP port that SMP server will listen for SMP commands on.
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_STACK_SIZE
|
||||||
|
int "UDP SMP stack size"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
default 512
|
||||||
|
help
|
||||||
|
Stack size of the SMP UDP listening thread
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_THREAD_PRIO
|
||||||
|
int "UDP SMP thread priority"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
default 0
|
||||||
|
help
|
||||||
|
Scheduling priority of the SMP UDP listening thread.
|
||||||
|
|
||||||
|
config MCUMGR_SMP_UDP_MTU
|
||||||
|
int "UDP SMP MTU"
|
||||||
|
depends on MCUMGR_SMP_UDP
|
||||||
|
default 1500
|
||||||
|
help
|
||||||
|
Maximum size of SMP frames sent and received over UDP, in bytes.
|
||||||
|
This value must satisfy the following relation:
|
||||||
|
MCUMGR_SMP_UDP_MTU <= MCUMGR_BUF_SIZE + SMP msg overhead - address size
|
||||||
|
where address size is determined by IPv4/IPv6 selection.
|
||||||
|
|
||||||
if MCUMGR
|
if MCUMGR
|
||||||
config MCUMGR_BUF_COUNT
|
config MCUMGR_BUF_COUNT
|
||||||
int "Number of mcumgr buffers"
|
int "Number of mcumgr buffers"
|
||||||
|
default 2 if MCUMGR_SMP_UDP
|
||||||
default 4
|
default 4
|
||||||
help
|
help
|
||||||
The number of net_bufs to allocate for mcumgr. These buffers are
|
The number of net_bufs to allocate for mcumgr. These buffers are
|
||||||
|
@ -74,6 +134,7 @@ config MCUMGR_BUF_COUNT
|
||||||
|
|
||||||
config MCUMGR_BUF_SIZE
|
config MCUMGR_BUF_SIZE
|
||||||
int "Size of each mcumgr buffer"
|
int "Size of each mcumgr buffer"
|
||||||
|
default 2048 if MCUMGR_SMP_UDP
|
||||||
default 384
|
default 384
|
||||||
help
|
help
|
||||||
The size, in bytes, of each mcumgr buffer. This value must satisfy
|
The size, in bytes, of each mcumgr buffer. This value must satisfy
|
||||||
|
@ -82,11 +143,18 @@ config MCUMGR_BUF_SIZE
|
||||||
|
|
||||||
config MCUMGR_BUF_USER_DATA_SIZE
|
config MCUMGR_BUF_USER_DATA_SIZE
|
||||||
int "Size of mcumgr buffer user data"
|
int "Size of mcumgr buffer user data"
|
||||||
|
default 24 if MCUMGR_SMP_UDP && MCUMGR_SMP_UDP_IPV6
|
||||||
|
default 8 if MCUMGR_SMP_UDP && MCUMGR_SMP_UDP_IPV4
|
||||||
default 4
|
default 4
|
||||||
help
|
help
|
||||||
The size, in bytes, of user data to allocate for each mcumgr buffer.
|
The size, in bytes, of user data to allocate for each mcumgr buffer.
|
||||||
|
|
||||||
Different mcumgr transports impose different requirements for this
|
Different mcumgr transports impose different requirements for this
|
||||||
setting. A value of 4 is sufficient for UART, shell, and bluetooth.
|
setting. A value of 4 is sufficient for UART, shell, and bluetooth.
|
||||||
|
For UDP, the userdata must be large enough to hold a IPv4/IPv6 address.
|
||||||
|
|
||||||
|
Note that CONFIG_NET_BUF_USER_DATA_SIZE must be at least as big as
|
||||||
|
MCUMGR_BUF_USER_DATA_SIZE.
|
||||||
|
|
||||||
endif # MCUMGR
|
endif # MCUMGR
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -10,6 +10,10 @@ config MCUMGR
|
||||||
|
|
||||||
if MCUMGR
|
if MCUMGR
|
||||||
|
|
||||||
|
module = MCUMGR
|
||||||
|
module-str = mcumgr
|
||||||
|
source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
||||||
config MGMT_CBORATTR_MAX_SIZE
|
config MGMT_CBORATTR_MAX_SIZE
|
||||||
int "The maximum size of a CBOR attribute during decoding"
|
int "The maximum size of a CBOR attribute during decoding"
|
||||||
default 512
|
default 512
|
||||||
|
|
244
subsys/mgmt/smp_udp.c
Normal file
244
subsys/mgmt/smp_udp.c
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Prevas A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief UDP transport for the mcumgr SMP protocol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <net/socket.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <mgmt/mgmt.h>
|
||||||
|
#include <mgmt/smp_udp.h>
|
||||||
|
#include <mgmt/buf.h>
|
||||||
|
#include <mgmt/smp.h>
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_MCUMGR_LOG_LEVEL
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(smp_udp);
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
int sock;
|
||||||
|
const char *proto;
|
||||||
|
struct zephyr_smp_transport smp_transport;
|
||||||
|
char recv_buffer[CONFIG_MCUMGR_SMP_UDP_MTU];
|
||||||
|
struct k_thread thread;
|
||||||
|
K_THREAD_STACK_MEMBER(stack, CONFIG_MCUMGR_SMP_UDP_STACK_SIZE);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct configs {
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
struct config ipv4;
|
||||||
|
#endif
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
struct config ipv6;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct configs configs = {
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
.ipv4 = {
|
||||||
|
.proto = "IPv4",
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
.ipv6 = {
|
||||||
|
.proto = "IPv6",
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
static int smp_udp4_tx(struct zephyr_smp_transport *zst, struct net_buf *nb)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(zst);
|
||||||
|
|
||||||
|
struct sockaddr *addr = net_buf_user_data(nb);
|
||||||
|
int ret = sendto(configs.ipv4.sock, nb->data, nb->len,
|
||||||
|
0, addr, sizeof(*addr));
|
||||||
|
mcumgr_buf_free(nb);
|
||||||
|
|
||||||
|
return ret < 0 ? MGMT_ERR_EINVAL : MGMT_ERR_EOK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
static int smp_udp6_tx(struct zephyr_smp_transport *zst, struct net_buf *nb)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(zst);
|
||||||
|
|
||||||
|
struct sockaddr *addr = net_buf_user_data(nb);
|
||||||
|
int ret = sendto(configs.ipv6.sock, nb->data, nb->len,
|
||||||
|
0, addr, sizeof(*addr));
|
||||||
|
mcumgr_buf_free(nb);
|
||||||
|
|
||||||
|
return ret < 0 ? MGMT_ERR_EINVAL : MGMT_ERR_EOK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint16_t smp_udp_get_mtu(const struct net_buf *nb)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(nb);
|
||||||
|
|
||||||
|
return CONFIG_MCUMGR_SMP_UDP_MTU;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smp_udp_ud_copy(struct net_buf *dst, const struct net_buf *src)
|
||||||
|
{
|
||||||
|
struct sockaddr *src_ud = net_buf_user_data(src);
|
||||||
|
struct sockaddr *dst_ud = net_buf_user_data(dst);
|
||||||
|
|
||||||
|
net_ipaddr_copy(dst_ud, src_ud);
|
||||||
|
|
||||||
|
return MGMT_ERR_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smp_udp_receive_thread(void *p1, void *p2, void *p3)
|
||||||
|
{
|
||||||
|
struct config *conf = (struct config *)p1;
|
||||||
|
|
||||||
|
ARG_UNUSED(p2);
|
||||||
|
ARG_UNUSED(p3);
|
||||||
|
|
||||||
|
LOG_INF("Started (%s)", conf->proto);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct sockaddr addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
|
||||||
|
int len = recvfrom(conf->sock, conf->recv_buffer,
|
||||||
|
CONFIG_MCUMGR_SMP_UDP_MTU,
|
||||||
|
0, &addr, &addr_len);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
struct sockaddr *ud;
|
||||||
|
struct net_buf *nb;
|
||||||
|
|
||||||
|
/* store sender address in user data for reply */
|
||||||
|
nb = mcumgr_buf_alloc();
|
||||||
|
net_buf_add_mem(nb, conf->recv_buffer, len);
|
||||||
|
ud = net_buf_user_data(nb);
|
||||||
|
net_ipaddr_copy(ud, &addr);
|
||||||
|
|
||||||
|
zephyr_smp_rx_req(&conf->smp_transport, nb);
|
||||||
|
} else if (len < 0) {
|
||||||
|
LOG_ERR("recvfrom error (%s): %i", conf->proto, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smp_udp_init(struct device *dev)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
zephyr_smp_transport_init(&configs.ipv4.smp_transport,
|
||||||
|
smp_udp4_tx, smp_udp_get_mtu,
|
||||||
|
smp_udp_ud_copy, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
zephyr_smp_transport_init(&configs.ipv6.smp_transport,
|
||||||
|
smp_udp6_tx, smp_udp_get_mtu,
|
||||||
|
smp_udp_ud_copy, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MGMT_ERR_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create_socket(struct sockaddr *addr, const char *proto)
|
||||||
|
{
|
||||||
|
int sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
|
||||||
|
if (sock < 0) {
|
||||||
|
LOG_ERR("Could not open receive socket (%s), err: %i",
|
||||||
|
proto, errno);
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(sock, addr, sizeof(*addr)) < 0) {
|
||||||
|
LOG_ERR("Could not bind to receive socket (%s), err: %i",
|
||||||
|
proto, errno);
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_thread(struct config *conf, const char *name)
|
||||||
|
{
|
||||||
|
k_thread_create(&(conf->thread), conf->stack,
|
||||||
|
K_THREAD_STACK_SIZEOF(conf->stack),
|
||||||
|
smp_udp_receive_thread, conf, NULL, NULL,
|
||||||
|
CONFIG_MCUMGR_SMP_UDP_THREAD_PRIO, 0, K_FOREVER);
|
||||||
|
|
||||||
|
k_thread_name_set(&(conf->thread), name);
|
||||||
|
k_thread_start(&(conf->thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(smp_udp_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||||
|
|
||||||
|
int smp_udp_open(void)
|
||||||
|
{
|
||||||
|
struct config *conf;
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
struct sockaddr_in addr4;
|
||||||
|
|
||||||
|
memset(&addr4, 0, sizeof(addr4));
|
||||||
|
addr4.sin_family = AF_INET;
|
||||||
|
addr4.sin_port = htons(CONFIG_MCUMGR_SMP_UDP_PORT);
|
||||||
|
inet_pton(AF_INET, INADDR_ANY, &addr4.sin_addr);
|
||||||
|
|
||||||
|
conf = &configs.ipv4;
|
||||||
|
conf->sock = create_socket((struct sockaddr *)&addr4, conf->proto);
|
||||||
|
|
||||||
|
if (conf->sock < 0) {
|
||||||
|
return -MGMT_ERR_EUNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_thread(conf, "smp_udp4");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
struct sockaddr_in6 addr6;
|
||||||
|
|
||||||
|
memset(&addr6, 0, sizeof(addr6));
|
||||||
|
addr6.sin6_family = AF_INET6;
|
||||||
|
addr6.sin6_port = htons(CONFIG_MCUMGR_SMP_UDP_PORT);
|
||||||
|
addr6.sin6_addr = in6addr_any;
|
||||||
|
|
||||||
|
conf = &configs.ipv6;
|
||||||
|
conf->sock = create_socket((struct sockaddr *)&addr6, conf->proto);
|
||||||
|
|
||||||
|
if (conf->sock < 0) {
|
||||||
|
return -MGMT_ERR_EUNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_thread(conf, "smp_udp6");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MGMT_ERR_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int smp_udp_close(void)
|
||||||
|
{
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV4
|
||||||
|
k_thread_abort(&(configs.ipv4.thread));
|
||||||
|
close(configs.ipv4.sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MCUMGR_SMP_UDP_IPV6
|
||||||
|
k_thread_abort(&(configs.ipv6.thread));
|
||||||
|
close(configs.ipv6.sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MGMT_ERR_EOK;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue