Skip to content

Commit

Permalink
net: conn_mgr: Bulk convenience functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
glarsennordic authored and carlescufi committed Jun 30, 2023
1 parent b65613e commit ad6fdaf
Show file tree
Hide file tree
Showing 4 changed files with 638 additions and 1 deletion.
51 changes: 51 additions & 0 deletions include/zephyr/net/conn_mgr_connectivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/**
* @}
*/
Expand Down
145 changes: 144 additions & 1 deletion subsys/net/conn_mgr/conn_mgr_connectivity.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions tests/net/conn_mgr_conn/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit ad6fdaf

Please sign in to comment.