blob: a80074d29a0a78011de19209e6d77779896f1a60 [file] [log] [blame]
/* echo-server.c - Networking echo server */
/*
* Copyright (c) 2016 Intel Corporation.
* Copyright (c) 2018 Nordic Semiconductor ASA.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_echo_server_sample, LOG_LEVEL_DBG);
#include <zephyr/kernel.h>
#include <zephyr/linker/sections.h>
#include <errno.h>
#include <zephyr/shell/shell.h>
#include <zephyr/net/net_core.h>
#include <zephyr/net/tls_credentials.h>
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/net_event.h>
#include <zephyr/net/net_conn_mgr.h>
#include "common.h"
#include "certificate.h"
#define APP_BANNER "Run echo server"
static struct k_sem quit_lock;
static struct net_mgmt_event_callback mgmt_cb;
static bool connected;
K_SEM_DEFINE(run_app, 0, 1);
static bool want_to_quit;
#if defined(CONFIG_USERSPACE)
K_APPMEM_PARTITION_DEFINE(app_partition);
struct k_mem_domain app_domain;
#endif
#define EVENT_MASK (NET_EVENT_L4_CONNECTED | \
NET_EVENT_L4_DISCONNECTED)
APP_DMEM struct configs conf = {
.ipv4 = {
.proto = "IPv4",
},
.ipv6 = {
.proto = "IPv6",
},
};
void quit(void)
{
k_sem_give(&quit_lock);
}
static void start_udp_and_tcp(void)
{
LOG_INF("Starting...");
if (IS_ENABLED(CONFIG_NET_TCP)) {
start_tcp();
}
if (IS_ENABLED(CONFIG_NET_UDP)) {
start_udp();
}
}
static void stop_udp_and_tcp(void)
{
LOG_INF("Stopping...");
if (IS_ENABLED(CONFIG_NET_UDP)) {
stop_udp();
}
if (IS_ENABLED(CONFIG_NET_TCP)) {
stop_tcp();
}
}
static void event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface)
{
if ((mgmt_event & EVENT_MASK) != mgmt_event) {
return;
}
if (want_to_quit) {
k_sem_give(&run_app);
want_to_quit = false;
}
if (is_tunnel(iface)) {
/* Tunneling is handled separately, so ignore it here */
return;
}
if (mgmt_event == NET_EVENT_L4_CONNECTED) {
LOG_INF("Network connected");
connected = true;
k_sem_give(&run_app);
return;
}
if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
if (connected == false) {
LOG_INF("Waiting network to be connected");
} else {
LOG_INF("Network disconnected");
connected = false;
}
k_sem_reset(&run_app);
return;
}
}
static void init_app(void)
{
#if defined(CONFIG_USERSPACE)
struct k_mem_partition *parts[] = {
#if Z_LIBC_PARTITION_EXISTS
&z_libc_partition,
#endif
&app_partition
};
int ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
ARG_UNUSED(ret);
#endif
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || \
defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
int err;
#endif
k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT);
LOG_INF(APP_BANNER);
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
#if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC)
err = tls_credential_add(SERVER_CERTIFICATE_TAG,
TLS_CREDENTIAL_CA_CERTIFICATE,
ca_certificate,
sizeof(ca_certificate));
if (err < 0) {
LOG_ERR("Failed to register CA certificate: %d", err);
}
#endif
err = tls_credential_add(SERVER_CERTIFICATE_TAG,
TLS_CREDENTIAL_SERVER_CERTIFICATE,
server_certificate,
sizeof(server_certificate));
if (err < 0) {
LOG_ERR("Failed to register public certificate: %d", err);
}
err = tls_credential_add(SERVER_CERTIFICATE_TAG,
TLS_CREDENTIAL_PRIVATE_KEY,
private_key, sizeof(private_key));
if (err < 0) {
LOG_ERR("Failed to register private key: %d", err);
}
#endif
#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
err = tls_credential_add(PSK_TAG,
TLS_CREDENTIAL_PSK,
psk,
sizeof(psk));
if (err < 0) {
LOG_ERR("Failed to register PSK: %d", err);
}
err = tls_credential_add(PSK_TAG,
TLS_CREDENTIAL_PSK_ID,
psk_id,
sizeof(psk_id) - 1);
if (err < 0) {
LOG_ERR("Failed to register PSK ID: %d", err);
}
#endif
if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
net_mgmt_init_event_callback(&mgmt_cb,
event_handler, EVENT_MASK);
net_mgmt_add_event_callback(&mgmt_cb);
net_conn_mgr_resend_status();
}
init_vlan();
init_tunnel();
init_usb();
}
static int cmd_sample_quit(const struct shell *shell,
size_t argc, char *argv[])
{
want_to_quit = true;
net_conn_mgr_resend_status();
quit();
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(sample_commands,
SHELL_CMD(quit, NULL,
"Quit the sample application\n",
cmd_sample_quit),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(sample, &sample_commands,
"Sample application commands", NULL);
void main(void)
{
init_app();
if (!IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
/* If the config library has not been configured to start the
* app only after we have a connection, then we can start
* it right away.
*/
k_sem_give(&run_app);
}
/* Wait for the connection. */
k_sem_take(&run_app, K_FOREVER);
start_udp_and_tcp();
k_sem_take(&quit_lock, K_FOREVER);
if (connected) {
stop_udp_and_tcp();
}
}