net: conn_mgr: Bulk convenience functions

To further reduce the need for networking boilerplate in applications,
provide bulk versions of net_if_up, net_if_down, conn_mgr_if_connect,
and conn_mgr_if_disconnect that affect all available / eligible ifaces
at once.

Since it is not intuitive whether these functions should affect ifaces
which conn_mgr is ignoring, these functions take an argument that allows
this to be specified by the application.

Signed-off-by: Georges Oates_Larsen <georges.larsen@nordicsemi.no>
This commit is contained in:
Georges Oates_Larsen 2023-05-02 16:46:30 -07:00 committed by Carles Cufí
parent b65613e79c
commit ad6fdaf2c2
4 changed files with 638 additions and 1 deletions

View file

@ -423,6 +423,57 @@ int conn_mgr_if_set_timeout(struct net_if *iface, int timeout);
*/
void conn_mgr_conn_init(void);
/**
* @brief Convenience function that takes all available ifaces into the admin-up state.
*
* Essentially a wrapper for net_if_up.
*
* @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr.
* Otherwise, affect all ifaces.
* @return 0 if all net_if_up calls returned 0, otherwise the first nonzero value
* returned by a net_if_up call.
*/
int conn_mgr_all_if_up(bool skip_ignored);
/**
* @brief Convenience function that takes all available ifaces into the admin-down state.
*
* Essentially a wrapper for net_if_down.
*
* @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr.
* Otherwise, affect all ifaces.
* @return 0 if all net_if_down calls returned 0, otherwise the first nonzero value
* returned by a net_if_down call.
*/
int conn_mgr_all_if_down(bool skip_ignored);
/**
* @brief Convenience function that takes all available ifaces into the admin-up state, and
* connects those that support connectivity.
*
* Essentially a wrapper for net_if_up and conn_mgr_if_connect.
*
* @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr.
* Otherwise, affect all ifaces.
* @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero
* value returned by either net_if_up or conn_mgr_if_connect.
*/
int conn_mgr_all_if_connect(bool skip_ignored);
/**
* @brief Convenience function that disconnects all available ifaces that support connectivity
* without putting them into admin-down state (unless auto-down is enabled for the iface).
*
* Essentially a wrapper for net_if_down.
*
* @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr.
* Otherwise, affect all ifaces.
* @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero
* value returned by either net_if_up or conn_mgr_if_connect.
*/
int conn_mgr_all_if_disconnect(bool skip_ignored);
/**
* @}
*/

View file

@ -8,8 +8,10 @@
LOG_MODULE_REGISTER(conn_mgr_conn, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL);
#include <zephyr/net/net_if.h>
#include <zephyr/net/conn_mgr_connectivity.h>
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/net/conn_mgr.h>
#include <zephyr/net/conn_mgr_connectivity.h>
#include "conn_mgr_private.h"
@ -422,3 +424,144 @@ void conn_mgr_conn_init(void)
}
}
}
enum conn_mgr_conn_all_if_oper {
ALL_IF_UP,
ALL_IF_DOWN,
ALL_IF_CONNECT,
ALL_IF_DISCONNECT
};
struct conn_mgr_conn_all_if_ctx {
bool skip_ignored;
enum conn_mgr_conn_all_if_oper operation;
int status;
};
/* Per-iface callback for conn_mgr_conn_all_if_up */
static void conn_mgr_conn_all_if_cb(struct net_if *iface, void *user_data)
{
int status = 0;
struct conn_mgr_conn_all_if_ctx *context = (struct conn_mgr_conn_all_if_ctx *)user_data;
/* Skip ignored ifaces if so desired */
if (context->skip_ignored && conn_mgr_is_iface_ignored(iface)) {
return;
}
/* Perform the requested operation */
switch (context->operation) {
case ALL_IF_UP:
/* Do not take iface admin up if it already is. */
if (net_if_is_admin_up(iface)) {
return;
}
status = net_if_up(iface);
break;
case ALL_IF_DOWN:
/* Do not take iface admin down if it already is. */
if (!net_if_is_admin_up(iface)) {
return;
}
status = net_if_down(iface);
break;
case ALL_IF_CONNECT:
/* Connect operation only supported if iface is bound */
if (!conn_mgr_if_is_bound(iface)) {
return;
}
status = conn_mgr_if_connect(iface);
break;
case ALL_IF_DISCONNECT:
/* Disconnect operation only supported if iface is bound */
if (!conn_mgr_if_is_bound(iface)) {
return;
}
status = conn_mgr_if_disconnect(iface);
break;
}
if (status == 0) {
return;
}
if (context->status == 0) {
context->status = status;
}
NET_ERR("%s failed for iface %d (%p). Error: %d",
context->operation == ALL_IF_UP ? "net_if_up" :
context->operation == ALL_IF_DOWN ? "net_if_down" :
context->operation == ALL_IF_CONNECT ? "conn_mgr_if_connect" :
context->operation == ALL_IF_DISCONNECT ? "conn_mgr_if_disconnect" :
"invalid",
net_if_get_by_iface(iface), iface, status
);
}
int conn_mgr_all_if_up(bool skip_ignored)
{
struct conn_mgr_conn_all_if_ctx context = {
.operation = ALL_IF_UP,
.skip_ignored = skip_ignored,
.status = 0
};
net_if_foreach(conn_mgr_conn_all_if_cb, &context);
return context.status;
}
int conn_mgr_all_if_down(bool skip_ignored)
{
struct conn_mgr_conn_all_if_ctx context = {
.operation = ALL_IF_DOWN,
.skip_ignored = skip_ignored,
.status = 0
};
net_if_foreach(conn_mgr_conn_all_if_cb, &context);
return context.status;
}
int conn_mgr_all_if_connect(bool skip_ignored)
{
/* First, take all ifaces up.
* All bound ifaces will do this automatically when connect is called, but non-bound ifaces
* won't, so we must request it explicitly.
*/
struct conn_mgr_conn_all_if_ctx context = {
.operation = ALL_IF_UP,
.skip_ignored = skip_ignored,
.status = 0
};
net_if_foreach(conn_mgr_conn_all_if_cb, &context);
/* Now connect all ifaces.
* We are delibarately not resetting context.status between these two calls so that
* the first nonzero status code encountered between the two of them is what is returned.
*/
context.operation = ALL_IF_CONNECT;
net_if_foreach(conn_mgr_conn_all_if_cb, &context);
return context.status;
}
int conn_mgr_all_if_disconnect(bool skip_ignored)
{
struct conn_mgr_conn_all_if_ctx context = {
.operation = ALL_IF_DISCONNECT,
.skip_ignored = skip_ignored,
.status = 0
};
net_if_foreach(conn_mgr_conn_all_if_cb, &context);
return context.status;
}

View file

@ -24,3 +24,7 @@ CONFIG_ZTEST_NEW_API=y
CONFIG_NET_IF_MAX_IPV4_COUNT=6
CONFIG_NET_IF_MAX_IPV6_COUNT=6
CONFIG_TEST_USERSPACE=y
# Increased net event queue size needed since this test performs simultaneous events on a
# large number of ifaces.
CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=16

View file

@ -15,6 +15,7 @@
#include <zephyr/ztest.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/conn_mgr_connectivity.h>
#include <zephyr/net/conn_mgr.h>
#include "conn_mgr_private.h"
#include "test_conn_impl.h"
#include "test_ifaces.h"
@ -54,6 +55,9 @@ static void reset_test_iface_state(struct net_if *iface)
struct conn_mgr_conn_binding *iface_binding = conn_mgr_if_get_binding(iface);
struct test_conn_data *iface_data = conn_mgr_if_get_data(iface);
/* Some tests mark ifaces as ignored, this must be reset between each test. */
conn_mgr_watch_iface(iface);
if (iface_binding) {
/* Reset all flags and settings for the binding */
iface_binding->flags = 0;
@ -1139,5 +1143,440 @@ ZTEST(conn_mgr_conn, test_auto_down_fatal)
"Auto-down should not trigger on fatal error if it is disabled.");
}
/* Verify that all_if_up brings all ifaces up, but only if they are not ignored or
* skip_ignored is false
*/
ZTEST(conn_mgr_conn, test_all_if_up)
{
/* Ignore an iface */
conn_mgr_ignore_iface(ifa1);
/* Take all ifaces up (do not skip ignored) */
zassert_equal(conn_mgr_all_if_up(false), 0, "conn_mgr_all_if_up should succeed.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Manually take all ifaces down */
zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Take all ifaces up (skip ignored) */
zassert_equal(conn_mgr_all_if_up(true), 0, "conn_mgr_all_if_up should succeed.");
k_sleep(K_MSEC(1));
/* Verify all except ignored are up */
zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-up.");
zassert_false(net_if_is_admin_up(ifa1), "Ignored iface should not be admin-up.");
}
/* Verify that all_if_connect brings all ifaces up, and connects all bound ifaces, but only those
* that are not ignored, or all of them if skip_ignored is false
*/
ZTEST(conn_mgr_conn, test_all_if_connect)
{
/* Ignore a bound and an unbound iface */
conn_mgr_ignore_iface(ifa1);
conn_mgr_ignore_iface(ifnone);
/* Connect all ifaces (do not skip ignored) */
zassert_equal(conn_mgr_all_if_connect(false), 0, "conn_mgr_all_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Verify bound ifaces are connected */
zassert_true(net_if_is_up(ifa1), "All bound ifaces should be connected.");
zassert_true(net_if_is_up(ifa2), "All bound ifaces should be connected.");
zassert_true(net_if_is_up(ifb), "All bound ifaces should be connected.");
zassert_true(net_if_is_up(ifni), "All bound ifaces should be connected.");
/* Manually take all ifaces down */
zassert_equal(conn_mgr_if_disconnect(ifa1), 0, "net_if_disconnect should succeed.");
zassert_equal(conn_mgr_if_disconnect(ifa2), 0, "net_if_disconnect should succeed.");
zassert_equal(conn_mgr_if_disconnect(ifb), 0, "net_if_disconnect should succeed.");
zassert_equal(conn_mgr_if_disconnect(ifni), 0, "net_if_disconnect should succeed.");
zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces.");
zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Connect all ifaces (skip ignored) */
zassert_equal(conn_mgr_all_if_connect(true), 0, "conn_mgr_all_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Verify all except ignored are up */
zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up.");
zassert_false(net_if_is_admin_up(ifa1), "All ignored ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnone), "All ignored ifaces should be admin-down.");
/* Verify bound ifaces are connected, except for ignored */
zassert_true(net_if_is_up(ifa2), "All non-ignored bound ifaces should be connected.");
zassert_true(net_if_is_up(ifb), "All non-ignored bound ifaces should be connected.");
zassert_true(net_if_is_up(ifni), "All non-ignored bound ifaces should be connected.");
zassert_false(net_if_is_up(ifa1), "Ignored iface should not be connected.");
}
/* Verify that all_if_down takes all ifaces down, but only if they are not ignored,
* or skip_ignored is false
*/
ZTEST(conn_mgr_conn, test_all_if_down)
{
/* Ignore an iface */
conn_mgr_ignore_iface(ifa1);
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Take all ifaces down (do not skip ignored) */
zassert_equal(conn_mgr_all_if_down(false), 0, "conn_mgr_all_if_down should succeed.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are down */
zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down.");
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Take all ifaces down (skip ignored) */
zassert_equal(conn_mgr_all_if_down(true), 0, "conn_mgr_all_if_down should succeed.");
k_sleep(K_MSEC(1));
/* Verify that all except the ignored iface is down */
zassert_false(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-down.");
zassert_true(net_if_is_admin_up(ifa1), "Ignored iface should be admin-up.");
}
/* Verify that all_if_disconnect disconnects all bound ifaces, but only if they are not ignored,
* or skip_ignored is false
*/
ZTEST(conn_mgr_conn, test_all_if_disconnect)
{
/* Ignore a bound iface */
conn_mgr_ignore_iface(ifa1);
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Manually connect all bound ifaces */
zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Disconnect all ifaces (do not skip ignored) */
zassert_equal(conn_mgr_all_if_disconnect(false), 0,
"conn_mgr_all_if_disconnect should succeed.");
k_sleep(K_MSEC(1));
/* Verify that all bound ifaces are disconnected */
zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected.");
/* Verify that all ifaces are still up, even if disconnected */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Manually reconnect bound ifaces */
zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Disconnect all ifaces (skip ignored) */
zassert_equal(conn_mgr_all_if_disconnect(true), 0,
"conn_mgr_all_if_disconnect should succeed.");
k_sleep(K_MSEC(1));
/* Verify that all bound ifaces are disconnected, except the ignored iface */
zassert_false(net_if_is_up(ifa2), "All non-ignored bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifb), "All non-ignored bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifni), "All non-ignored bound ifaces should be disconnected.");
zassert_true(net_if_is_up(ifa1), "Ignored iface should still be connected");
}
/* Verify that double calls to all_if_up do not raise errors */
ZTEST(conn_mgr_conn, test_all_if_up_double)
{
/* Take all ifaces up twice in a row */
zassert_equal(conn_mgr_all_if_up(false), 0,
"conn_mgr_all_if_up should succeed.");
zassert_equal(conn_mgr_all_if_up(false), 0,
"conn_mgr_all_if_up should succeed twice in a row.");
/* One more time, after a delay, to be sure */
k_sleep(K_MSEC(1));
zassert_equal(conn_mgr_all_if_up(false), 0,
"conn_mgr_all_if_up should succeed twice in a row.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
}
/* Verify that double calls to all_if_down do not raise errors */
ZTEST(conn_mgr_conn, test_all_if_down_double)
{
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Take all ifaces down twice in a row */
zassert_equal(conn_mgr_all_if_down(false), 0,
"conn_mgr_all_if_down should succeed.");
zassert_equal(conn_mgr_all_if_down(false), 0,
"conn_mgr_all_if_down should succeed twice in a row.");
/* One more time, after a delay, to be sure */
k_sleep(K_MSEC(1));
zassert_equal(conn_mgr_all_if_down(false), 0,
"conn_mgr_all_if_down should succeed twice in a row.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are down */
zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down.");
zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down.");
}
/* Verify that double calls to all_if_connect do not raise errors */
ZTEST(conn_mgr_conn, test_all_if_connect_double)
{
/* Connect all ifaces twice in a row */
zassert_equal(conn_mgr_all_if_connect(false), 0,
"conn_mgr_all_if_connect should succeed.");
zassert_equal(conn_mgr_all_if_connect(false), 0,
"conn_mgr_all_if_connect should succeed twice in a row.");
/* One more time, after a delay, to be sure */
k_sleep(K_MSEC(1));
zassert_equal(conn_mgr_all_if_connect(false), 0,
"conn_mgr_all_if_connect should succeed twice in a row.");
k_sleep(K_MSEC(1));
/* Verify all ifaces are up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Verify all bound ifaces are connected */
}
/* Verify that double calls to all_if_disconnect do not raise errors */
ZTEST(conn_mgr_conn, test_all_if_disconnect_double)
{
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Manually connect all bound ifaces */
zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Connect all ifaces twice in a row */
zassert_equal(conn_mgr_all_if_disconnect(false), 0,
"conn_mgr_all_if_disconnect should succeed.");
zassert_equal(conn_mgr_all_if_disconnect(false), 0,
"conn_mgr_all_if_disconnect should succeed twice in a row.");
/* One more time, after a delay, to be sure */
k_sleep(K_MSEC(1));
zassert_equal(conn_mgr_all_if_disconnect(false), 0,
"conn_mgr_all_if_disconnect should succeed twice in a row.");
k_sleep(K_MSEC(1));
/* Verify all bound ifaces are disconnected */
zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected.");
zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected.");
/* Verify all ifaces are up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
}
/* Testing error passing for all_if_up/all_if_down is not possible without using an L2 other than
* Dummy, since the dummy L2 is not capable of erroring in response to either of these.
*
* However, since all bulk convenience functions share a single implementation, testing
* connect and disconnect is sufficient to gain acceptable coverage of this behavior for all of
* them.
*/
/* Verify that all_if_connect successfully forwards errors encountered on individual ifaces */
ZTEST(conn_mgr_conn, test_all_if_connect_err)
{
struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1);
/* Schedule a connect error on one of the ifaces */
ifa1_data->api_err = -ECHILD;
/* Verify that this error is passed to all_if_connect */
zassert_equal(conn_mgr_all_if_connect(false), -ECHILD,
"conn_mgr_all_if_connect should fail with the requested error.");
k_sleep(K_MSEC(1));
/* Verify that all ifaces went admin-up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Verify that all the non-error ifaces are connected */
zassert_true(net_if_is_up(ifa2), "All non-failing ifaces should be connected.");
zassert_true(net_if_is_up(ifb), "All non-failing ifaces should be connected.");
zassert_true(net_if_is_up(ifni), "All non-failing ifaces should be connected.");
/* Verify that the error iface is not connected */
zassert_false(net_if_is_up(ifa1), "The failing iface should not be connected.");
}
/* Verify that all_if_disconnect successfully forwards errors encountered on individual ifaces */
ZTEST(conn_mgr_conn, test_all_if_disconnect_err)
{
struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1);
/* Manually take all ifaces up */
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces.");
zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces.");
k_sleep(K_MSEC(1));
/* Manually connect all bound ifaces */
zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed.");
zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed.");
k_sleep(K_MSEC(1));
/* Schedule a disconnect error on one of the ifaces */
ifa1_data->api_err = -ECHILD;
/* Verify that this error is passed to all_if_disconnect */
zassert_equal(conn_mgr_all_if_disconnect(false), -ECHILD,
"conn_mgr_all_if_disconnect should fail with the requested error.");
/* Verify that all ifaces are still admin-up */
zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up.");
zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up.");
/* Verify that all the non-error ifaces are disconnected */
zassert_false(net_if_is_up(ifa2), "All non-failing ifaces should be disconnected.");
zassert_false(net_if_is_up(ifb), "All non-failing ifaces should be disconnected.");
zassert_false(net_if_is_up(ifni), "All non-failing ifaces should be disconnected.");
/* Verify that the error iface is not connected */
zassert_true(net_if_is_up(ifa1), "The failing iface should not be disconnected.");
}
ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL);