From f1da58106bf1f2771117d1dedc1d07e7cafbb04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simen=20S=2E=20R=C3=B8stad?= Date: Mon, 6 Oct 2025 18:23:36 +0200 Subject: [PATCH] lib: nrf_modem_lib: Add connection manager backend for NTN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add connection manager backend for NTN - Currently just an empty shell, content of the backend needs to be implemented. - Add sample that showcases how to switch between cellular and NTN iface Signed-off-by: Simen S. Røstad --- lib/nrf_modem_lib/Kconfig.modemlib | 1 + lib/nrf_modem_lib/lte_net_if/CMakeLists.txt | 3 + lib/nrf_modem_lib/lte_net_if/Kconfig.ntn | 77 ++++++ lib/nrf_modem_lib/lte_net_if/lte_net_if_ntn.c | 84 ++++++ lib/nrf_modem_lib/nrf9x_sockets.c | 49 ++++ samples/net/ntn/CMakeLists.txt | 16 ++ samples/net/ntn/Kconfig | 33 +++ .../net/ntn/boards/nrf9151dk_nrf9151_ns.conf | 40 +++ .../ntn/boards/nrf9151dk_nrf9151_ns.overlay | 18 ++ samples/net/ntn/prj.conf | 21 ++ samples/net/ntn/src/main.c | 246 ++++++++++++++++++ 11 files changed, 588 insertions(+) create mode 100644 lib/nrf_modem_lib/lte_net_if/Kconfig.ntn create mode 100644 lib/nrf_modem_lib/lte_net_if/lte_net_if_ntn.c create mode 100644 samples/net/ntn/CMakeLists.txt create mode 100644 samples/net/ntn/Kconfig create mode 100644 samples/net/ntn/boards/nrf9151dk_nrf9151_ns.conf create mode 100644 samples/net/ntn/boards/nrf9151dk_nrf9151_ns.overlay create mode 100644 samples/net/ntn/prj.conf create mode 100644 samples/net/ntn/src/main.c diff --git a/lib/nrf_modem_lib/Kconfig.modemlib b/lib/nrf_modem_lib/Kconfig.modemlib index 0aac16149d32..18a8f834ba83 100644 --- a/lib/nrf_modem_lib/Kconfig.modemlib +++ b/lib/nrf_modem_lib/Kconfig.modemlib @@ -272,6 +272,7 @@ config NRF_MODEM_LIB_FAULT_STRERROR The description can be retrieved with nrf_modem_lib_fault_strerror(). rsource "lte_net_if/Kconfig" +rsource "lte_net_if/Kconfig.ntn" rsource "shell/Kconfig" DT_IPC := $(dt_nodelabel_path,ipc) diff --git a/lib/nrf_modem_lib/lte_net_if/CMakeLists.txt b/lib/nrf_modem_lib/lte_net_if/CMakeLists.txt index ecb39a0a8800..054770db23a1 100644 --- a/lib/nrf_modem_lib/lte_net_if/CMakeLists.txt +++ b/lib/nrf_modem_lib/lte_net_if/CMakeLists.txt @@ -6,3 +6,6 @@ target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lte_net_if.c) target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lte_ip_addr_helper.c) + +# Add NTN source file when NTN is enabled +target_sources_ifdef(CONFIG_NRF_MODEM_LIB_NET_IF_NTN app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lte_net_if_ntn.c) diff --git a/lib/nrf_modem_lib/lte_net_if/Kconfig.ntn b/lib/nrf_modem_lib/lte_net_if/Kconfig.ntn new file mode 100644 index 000000000000..ff18c9e9a6f3 --- /dev/null +++ b/lib/nrf_modem_lib/lte_net_if/Kconfig.ntn @@ -0,0 +1,77 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menuconfig NRF_MODEM_LIB_NET_IF_NTN + bool "nRF91 LTE network interface for NTN (Non-Terrestrial Network)" + depends on NRF_MODEM_LIB + select CONN_MGR_CONNECTIVITY + help + Enable nRF91 LTE network interface for NTN (Non-Terrestrial Network). + This provides a separate network interface specifically for NTN connectivity, + allowing applications to choose between terrestrial and non-terrestrial networks. + + This works alongside the regular LTE network interface and provides similar + functionality but optimized for satellite communication. + +if NRF_MODEM_LIB_NET_IF_NTN + +config NRF_MODEM_LIB_NET_IF_NTN_AUTO_START + bool "Auto-start NTN interface" + help + Automatically start the NTN network interface when the system starts. + When enabled, the NTN interface will be brought up automatically during + system initialization. + +config NRF_MODEM_LIB_NET_IF_NTN_CONNECT_TIMEOUT_SECONDS + int "NTN LTE connection timeout in seconds" + range 0 86400 + default 120 + help + Time period (in seconds) that the connectivity layer will attempt to establish + an NTN LTE connection for, before timing out. If set to 0, no timeout is applied. + + NTN connections may take longer to establish than terrestrial connections + due to the nature of satellite communication, so a longer timeout is recommended. + +config NRF_MODEM_LIB_NET_IF_NTN_CONNECTION_PERSISTENCE + bool "NTN Connection persistence" + default y + help + When enabled, the NTN connectivity layer will attempt to keep the NTN LTE connection + active, even after a connection loss, by automatically re-establishing the connection. + + This is particularly useful for NTN connections where connectivity may be + intermittent due to satellite coverage patterns. + +config NRF_MODEM_LIB_NET_IF_NTN_AUTO_CONNECT + bool "Auto-connect for NTN interface" + default y + help + Automatically connect the NTN interface when it is brought up. + If disabled, the application will need to manually trigger NTN connections. + +config NRF_MODEM_LIB_NET_IF_NTN_AUTO_DOWN + bool "Auto-down for NTN interface" + default y + help + Automatically bring down the NTN interface when network connectivity is lost. + If disabled, the interface will remain up even without network connectivity. + +config NRF_MODEM_LIB_NET_IF_NTN_DOWN_DEFAULT_LTE_DISCONNECT + bool "Disconnect NTN LTE on interface down" + default y + help + When the NTN network interface is brought down, disconnect from NTN LTE instead + of shutting down the modem completely. This allows for faster re-connection + and preserves the ability to use other network interfaces. + +module = NRF_MODEM_LIB_NET_IF_NTN +module-dep = LOG +module-str = nRF91 NTN LTE network interface +module-help = Enables logging for nRF91 NTN LTE network interface. +source "subsys/logging/Kconfig.template.log_config" + +endif # NRF_MODEM_LIB_NET_IF_NTN diff --git a/lib/nrf_modem_lib/lte_net_if/lte_net_if_ntn.c b/lib/nrf_modem_lib/lte_net_if/lte_net_if_ntn.c new file mode 100644 index 000000000000..0f2f91994c76 --- /dev/null +++ b/lib/nrf_modem_lib/lte_net_if/lte_net_if_ntn.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lte_ip_addr_helper.h" + +LOG_MODULE_REGISTER(nrf_modem_lib_netif_ntn, CONFIG_NRF_MODEM_LIB_NET_IF_NTN_LOG_LEVEL); + +/* Forward declarations */ +static int lte_net_if_disconnect_ntn(struct conn_mgr_conn_binding *const if_conn); + +static void lte_net_if_init_ntn(struct conn_mgr_conn_binding *if_conn) +{ + LOG_DBG("Initializing NTN modem network interface"); + + /* Init stuff goes here */ +} + +int lte_net_if_enable_ntn(void) +{ + LOG_DBG("Enabling NTN"); + + if (!nrf_modem_is_initialized()) { + return nrf_modem_lib_init(); + } + + return 0; +} + +int lte_net_if_disable_ntn(void) +{ + LOG_DBG("Disabling NTN"); + + if (IS_ENABLED(CONFIG_NRF_MODEM_LIB_NET_IF_NTN_DOWN_DEFAULT_LTE_DISCONNECT)) { + return lte_net_if_disconnect_ntn(NULL); + } else { + return nrf_modem_lib_shutdown(); + } + + return 0; +} + +static int lte_net_if_connect_ntn(struct conn_mgr_conn_binding *const if_conn) +{ + ARG_UNUSED(if_conn); + + LOG_DBG("Connecting to NTN"); + + /* Connect stuff goes here */ + + return 0; +} + +static int lte_net_if_disconnect_ntn(struct conn_mgr_conn_binding *const if_conn) +{ + ARG_UNUSED(if_conn); + + LOG_DBG("Disconnecting from NTN"); + + /* Disconnect stuff goes here */ + + return 0; +} + +/* Bind connectivity APIs for NTN. + * extern in nrf9x_sockets.c + */ +struct conn_mgr_conn_api lte_net_if_conn_mgr_api_ntn = { + .init = lte_net_if_init_ntn, + .connect = lte_net_if_connect_ntn, + .disconnect = lte_net_if_disconnect_ntn, +}; diff --git a/lib/nrf_modem_lib/nrf9x_sockets.c b/lib/nrf_modem_lib/nrf9x_sockets.c index f4c059e2d066..6aa7fa95df8c 100644 --- a/lib/nrf_modem_lib/nrf9x_sockets.c +++ b/lib/nrf_modem_lib/nrf9x_sockets.c @@ -42,6 +42,7 @@ * Required but not implemented. */ #define NRF_MODEM_LIB_NET_IF_CTX_TYPE void * +#define NRF_MODEM_LIB_NET_IF_NTN_CTX_TYPE void * #define OBJ_TO_SD(obj) (((struct nrf_sock_ctx *)obj)->nrf_fd) #define OBJ_TO_CTX(obj) ((struct nrf_sock_ctx *)obj) @@ -1177,10 +1178,58 @@ NET_DEVICE_OFFLOAD_INIT(nrf9x_socket, "nrf9x_socket", &nrf9x_iface_data, NULL, 0, &nrf9x_iface_offload_api, 1280); +#if defined(CONFIG_NRF_MODEM_LIB_NET_IF_NTN) +static struct nrf9x_iface_data_ntn { + struct net_if *iface; +} nrf9x_iface_data_ntn; + +static void nrf9x_iface_api_init_ntn(struct net_if *iface) +{ + nrf9x_iface_data_ntn.iface = iface; + + iface->if_dev->socket_offload = nrf9x_socket_create; + + /* NTN shares the same DNS offload operations */ + socket_offload_dns_register(&nrf9x_socket_dns_offload_ops); + + if (!IS_ENABLED(CONFIG_NRF_MODEM_LIB_NET_IF_NTN_AUTO_START)) { + net_if_flag_set(iface, NET_IF_NO_AUTO_START); + } +} + +static int nrf9x_iface_enable_ntn(const struct net_if *iface, bool enabled) +{ + /* Enables or disable the NTN device (in response to admin state change) */ + extern int lte_net_if_enable_ntn(void); + extern int lte_net_if_disable_ntn(void); + + return enabled ? lte_net_if_enable_ntn() : + lte_net_if_disable_ntn(); +} + +static struct offloaded_if_api nrf9x_iface_offload_api_ntn = { + .iface_api.init = nrf9x_iface_api_init_ntn, + .enable = nrf9x_iface_enable_ntn, +}; + +/* NTN network device for Non-Terrestrial Network */ +NET_DEVICE_OFFLOAD_INIT(nrf9x_socket_ntn, "nrf9x_socket_ntn", + nrf9x_socket_offload_init, + NULL, + &nrf9x_iface_data_ntn, NULL, + 0, &nrf9x_iface_offload_api_ntn, 1280); +#endif /* CONFIG_NRF_MODEM_LIB_NET_IF_NTN */ + #if defined(CONFIG_NRF_MODEM_LIB_NET_IF) extern struct conn_mgr_conn_api lte_net_if_conn_mgr_api; CONN_MGR_CONN_DEFINE(NRF_MODEM_LIB_NET_IF, <e_net_if_conn_mgr_api); CONN_MGR_BIND_CONN(nrf9x_socket, NRF_MODEM_LIB_NET_IF); #endif /* CONFIG_NRF_MODEM_LIB_NET_IF */ +#if defined(CONFIG_NRF_MODEM_LIB_NET_IF_NTN) +extern struct conn_mgr_conn_api lte_net_if_conn_mgr_api_ntn; +CONN_MGR_CONN_DEFINE(NRF_MODEM_LIB_NET_IF_NTN, <e_net_if_conn_mgr_api_ntn); +CONN_MGR_BIND_CONN(nrf9x_socket_ntn, NRF_MODEM_LIB_NET_IF_NTN); +#endif /* CONFIG_NRF_MODEM_LIB_NET_IF_NTN */ + #endif /* CONFIG_NET_SOCKETS_OFFLOAD */ diff --git a/samples/net/ntn/CMakeLists.txt b/samples/net/ntn/CMakeLists.txt new file mode 100644 index 000000000000..088e87fa20d6 --- /dev/null +++ b/samples/net/ntn/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ntn) + +# NORDIC SDK APP START +target_sources(app PRIVATE src/main.c) +# NORDIC SDK APP END + +zephyr_include_directories(src) diff --git a/samples/net/ntn/Kconfig b/samples/net/ntn/Kconfig new file mode 100644 index 000000000000..cc18af0069c8 --- /dev/null +++ b/samples/net/ntn/Kconfig @@ -0,0 +1,33 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menu "NTN sample settings" + +config NTN_SAMPLE_DATA_UPLOAD_SIZE_BYTES + int "Number of bytes transmitted to the server" + default 10 + +config NTN_SAMPLE_DATA_UPLOAD_FREQUENCY_SECONDS + int "How often data is transmitted to the server" + default 900 + +config NTN_SAMPLE_SERVER_ADDRESS_STATIC + string "UDP server IP address" + default "8.8.8.8" + +config NTN_SAMPLE_SERVER_PORT + int "UDP server port number" + default "2469" + +endmenu + +module = NTN_SAMPLE +module-str = NTN sample +source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config" + +menu "Zephyr Kernel" +source "Kconfig.zephyr" +endmenu diff --git a/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.conf b/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.conf new file mode 100644 index 000000000000..dce9bcd671e4 --- /dev/null +++ b/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.conf @@ -0,0 +1,40 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Modem trace +CONFIG_NRF_MODEM_LIB_TRACE=y +CONFIG_NRF_MODEM_LIB_TRACE_BACKEND_UART=y +CONFIG_SERIAL=y +CONFIG_UART_ASYNC_API=y +CONFIG_UART_1_ASYNC=y +CONFIG_UART_1_INTERRUPT_DRIVEN=n + +# Disable Duplicate Address Detection (DAD) +# due to not being properly implemented for offloaded interfaces. +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +# Offload network operations to the modem. +CONFIG_NET_SOCKETS_OFFLOAD=y + +# Zephyr NET Connection Manager and Connectivity layer. +CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=1024 +CONFIG_NRF_MODEM_LIB_NET_IF=y +CONFIG_NRF_MODEM_LIB_NET_IF_LOG_LEVEL_DBG=y +CONFIG_NRF_MODEM_LIB_NET_IF_NTN=y +CONFIG_NRF_MODEM_LIB_NET_IF_NTN_LOG_LEVEL_DBG=y + +## PSM +CONFIG_LTE_PSM_REQ=y +CONFIG_LTE_PSM_REQ_RPTAU="00100001" +CONFIG_LTE_PSM_REQ_RAT="00000000" + +## eDRX +CONFIG_LTE_EDRX_REQ=n +CONFIG_LTE_EDRX_REQ_VALUE_LTE_M="1001" + +## RAI +CONFIG_LTE_RAI_REQ=n diff --git a/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.overlay b/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.overlay new file mode 100644 index 000000000000..5d85357b0a6f --- /dev/null +++ b/samples/net/ntn/boards/nrf9151dk_nrf9151_ns.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* Enable uart1 for tracing. */ +&uart1 { + status = "okay"; + current-speed = < 1000000 >; + hw-flow-control; +}; + +/ { + chosen { + nordic,modem-trace-uart = &uart1; + }; +}; diff --git a/samples/net/ntn/prj.conf b/samples/net/ntn/prj.conf new file mode 100644 index 000000000000..008e179c50e6 --- /dev/null +++ b/samples/net/ntn/prj.conf @@ -0,0 +1,21 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# General configurations +CONFIG_LOG=y + +# Network +CONFIG_NETWORKING=y +CONFIG_NET_NATIVE=y +CONFIG_NET_IPV4=y +CONFIG_NET_SOCKETS=y +CONFIG_POSIX_API=y +CONFIG_NET_CONNECTION_MANAGER=y + +# Heap and stacks +CONFIG_HEAP_MEM_POOL_SIZE=1280 +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/samples/net/ntn/src/main.c b/samples/net/ntn/src/main.c new file mode 100644 index 000000000000..9d0f9de5822f --- /dev/null +++ b/samples/net/ntn/src/main.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_POSIX_API) +#include +#include +#include +#endif + +LOG_MODULE_REGISTER(ntn_sample, CONFIG_NTN_SAMPLE_LOG_LEVEL); + +#define UDP_IP_HEADER_SIZE 28 + +/* Macros used to subscribe to specific Zephyr NET management events. */ +#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) +#define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) + +/* Macro called upon a fatal error, reboots the device. */ +#define FATAL_ERROR() \ + LOG_ERR("Fatal error! Rebooting the device."); \ + LOG_PANIC(); \ + IF_ENABLED(CONFIG_REBOOT, (sys_reboot(0))) + +/* Zephyr NET management event callback structures. */ +static struct net_mgmt_event_callback l4_cb; +static struct net_mgmt_event_callback conn_cb; + +/* Variables used to perform socket operations. */ +static int fd; +static struct sockaddr_storage host_addr; + +/* Forward declarations */ +static void server_transmission_work_fn(struct k_work *work); + +/* Work item used to schedule periodic UDP transmissions. */ +static K_WORK_DELAYABLE_DEFINE(server_transmission_work, server_transmission_work_fn); + +static void server_transmission_work_fn(struct k_work *work) +{ + int err; + char buffer[CONFIG_NTN_SAMPLE_DATA_UPLOAD_SIZE_BYTES] = {"\0"}; + + LOG_INF("Transmitting UDP/IP payload of %d bytes to the " + "IP address %s, port number %d", + CONFIG_NTN_SAMPLE_DATA_UPLOAD_SIZE_BYTES + UDP_IP_HEADER_SIZE, + CONFIG_NTN_SAMPLE_SERVER_ADDRESS_STATIC, + CONFIG_NTN_SAMPLE_SERVER_PORT); + + err = send(fd, buffer, sizeof(buffer), 0); + if (err < 0) { + LOG_ERR("Failed to transmit UDP packet, %d", -errno); + return; + } + + (void)k_work_reschedule(&server_transmission_work, + K_SECONDS(CONFIG_NTN_SAMPLE_DATA_UPLOAD_FREQUENCY_SECONDS)); +} + +static int server_addr_construct(void) +{ + int err; + + struct sockaddr_in *server4 = ((struct sockaddr_in *)&host_addr); + + server4->sin_family = AF_INET; + server4->sin_port = htons(CONFIG_NTN_SAMPLE_SERVER_PORT); + + err = inet_pton(AF_INET, CONFIG_NTN_SAMPLE_SERVER_ADDRESS_STATIC, &server4->sin_addr); + if (err < 0) { + LOG_ERR("inet_pton, error: %d", -errno); + return err; + } + + return 0; +} + +static void on_net_event_l4_connected(void) +{ + int err; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + LOG_ERR("Failed to create UDP socket: %d", -errno); + FATAL_ERROR(); + return; + } + + err = connect(fd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr_in)); + if (err < 0) { + LOG_ERR("connect, error: %d", -errno); + FATAL_ERROR(); + return; + } + + (void)k_work_reschedule(&server_transmission_work, K_NO_WAIT); +} + +static void on_net_event_l4_disconnected(void) +{ + (void)close(fd); + (void)k_work_cancel_delayable(&server_transmission_work); +} + +static void l4_event_handler(struct net_mgmt_event_callback *cb, + uint64_t event, + struct net_if *iface) +{ + switch (event) { + case NET_EVENT_L4_CONNECTED: + LOG_INF("Network connectivity established"); + on_net_event_l4_connected(); + break; + case NET_EVENT_L4_DISCONNECTED: + LOG_INF("Network connectivity lost"); + on_net_event_l4_disconnected(); + break; + default: + /* Don't care */ + return; + } +} + +static void connectivity_event_handler(struct net_mgmt_event_callback *cb, + uint64_t event, + struct net_if *iface) +{ + if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { + LOG_ERR("NET_EVENT_CONN_IF_FATAL_ERROR"); + FATAL_ERROR(); + return; + } +} + +int main(void) +{ + int err; + + LOG_INF("NTN sample has started"); + + /* Setup handler for Zephyr NET Connection Manager events. */ + net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); + net_mgmt_add_event_callback(&l4_cb); + + /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ + net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, CONN_LAYER_EVENT_MASK); + net_mgmt_add_event_callback(&conn_cb); + + err = server_addr_construct(); + if (err) { + LOG_INF("server_addr_construct, error: %d", err); + FATAL_ERROR(); + return err; + } + + /* Get references to both interfaces: TODO - Use better naming for ifaces, perhaps a suffix? */ + struct net_if *lte_if = net_if_get_by_index(net_if_get_by_name("net0")); + struct net_if *ntn_if = net_if_get_by_index(net_if_get_by_name("net1")); + + if (!lte_if || !ntn_if) { + LOG_ERR("Failed to get network interfaces"); + FATAL_ERROR(); + return -ENODEV; + } + + LOG_INF("Cellular interface found: %p, NTN interface found: %p", lte_if, ntn_if); + + /* Bring up cellular interface */ + err = net_if_up(lte_if); + if (err) { + LOG_ERR("conn_mgr_all_if_up, error: %d", err); + FATAL_ERROR(); + return err; + } + + /* Connect to the cellular interface */ + err = conn_mgr_if_connect(lte_if); + if (err) { + LOG_ERR("conn_mgr_if_connect cellular, error: %d", err); + FATAL_ERROR(); + return err; + } + + k_sleep(K_SECONDS(10)); + + /* Disconnect from the LTE cellular interface */ + err = conn_mgr_if_disconnect(lte_if); + if (err) { + LOG_ERR("conn_mgr_if_disconnect LTE, error: %d", err); + FATAL_ERROR(); + return err; + } + + k_sleep(K_SECONDS(10)); + + /* Bring down cellular interface */ + err = net_if_down(lte_if); + if (err) { + LOG_ERR("net_if_down cellular, error: %d", err); + FATAL_ERROR(); + return err; + } + + /* Bring up NTN interface */ + err = net_if_up(ntn_if); + if (err) { + LOG_ERR("conn_mgr_all_if_up NTN, error: %d", err); + FATAL_ERROR(); + return err; + } + + /* Connect to the NTN cellular interface */ + err = conn_mgr_if_connect(ntn_if); + if (err) { + LOG_ERR("conn_mgr_if_connect NTN, error: %d", err); + FATAL_ERROR(); + return err; + } + + k_sleep(K_SECONDS(10)); + + /* Disconnect from the NTN cellular interface */ + err = conn_mgr_if_disconnect(ntn_if); + if (err) { + LOG_ERR("conn_mgr_if_disconnect NTN, error: %d", err); + FATAL_ERROR(); + return err; + } + + k_sleep(K_SECONDS(10)); + + LOG_DBG("Finished"); + + return 0; +}