net: conn_mgr: Support Auto-Down
To reduce the amount of boiler-plate needed in applications, this commit grants conn_mgr the ability to automatically take ifaces that have given up on connecting into the admin-down state. Tests adjusted as appropriate. This behavior can be disabled globally by disabling NET_CONNECTION_MANAGER_AUTO_IF_DOWN, or disabled per-iface using the CONN_MGR_IF_NO_AUTO_DOWN flag. Signed-off-by: Georges Oates_Larsen <georges.larsen@nordicsemi.no>
This commit is contained in:
parent
f3d75c4c65
commit
b65613e79c
|
@ -186,6 +186,12 @@ enum conn_mgr_if_flag {
|
|||
*/
|
||||
CONN_MGR_IF_NO_AUTO_CONNECT,
|
||||
|
||||
/* No auto-down
|
||||
* When set, conn_mgr will not automatically take the iface admin-down when it stops
|
||||
* trying to connect, even if NET_CONNECTION_MANAGER_AUTO_IF_DOWN is enabled.
|
||||
*/
|
||||
CONN_MGR_IF_NO_AUTO_DOWN,
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
CONN_MGR_NUM_IF_FLAGS,
|
||||
|
|
|
@ -36,4 +36,8 @@ config NET_CONNECTION_MANAGER_PRIORITY
|
|||
help
|
||||
This sets the starting priority of the connection manager thread.
|
||||
|
||||
config NET_CONNECTION_MANAGER_AUTO_IF_DOWN
|
||||
bool "Automatically call net_if_down on ifaces that have given up on connecting"
|
||||
default y
|
||||
|
||||
endif # NET_CONNECTION_MANAGER
|
||||
|
|
|
@ -48,6 +48,8 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface);
|
||||
|
||||
int conn_mgr_if_disconnect(struct net_if *iface)
|
||||
{
|
||||
struct conn_mgr_conn_binding *binding;
|
||||
|
@ -77,6 +79,16 @@ int conn_mgr_if_disconnect(struct net_if *iface)
|
|||
out:
|
||||
k_mutex_unlock(binding->mutex);
|
||||
|
||||
/* Since the connectivity implementation will not automatically attempt to reconnect after
|
||||
* a call to conn_mgr_if_disconnect, conn_mgr_conn_if_auto_admin_down should be called.
|
||||
*
|
||||
* conn_mgr_conn_handle_iface_down will only call conn_mgr_conn_if_auto_admin_down if
|
||||
* persistence is disabled. To ensure conn_mgr_conn_if_auto_admin_down is called in all
|
||||
* cases, we must call it directly from here. If persistence is disabled, this will result
|
||||
* in conn_mgr_conn_if_auto_admin_down being called twice, but that is not an issue.
|
||||
*/
|
||||
conn_mgr_conn_if_auto_admin_down(iface);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -263,6 +275,61 @@ static void conn_mgr_conn_handle_iface_admin_up(struct net_if *iface)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Take the provided iface admin-down.
|
||||
*
|
||||
* Called automatically by conn_mgr when an iface has lost connection and will not attempt to
|
||||
* regain it.
|
||||
*
|
||||
* @param iface - The iface to take admin-down
|
||||
*/
|
||||
static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface)
|
||||
{
|
||||
/* NOTE: This will be double-fired for ifaces that are both non-persistent
|
||||
* and are being directly requested to disconnect, since both of these conditions
|
||||
* separately trigger conn_mgr_conn_if_auto_admin_down.
|
||||
*
|
||||
* This is fine, because net_if_down is idempotent, but if you are adding other
|
||||
* behaviors to this function, bear it in mind.
|
||||
*/
|
||||
|
||||
/* Ignore ifaces that don't have connectivity implementations */
|
||||
if (!conn_mgr_if_is_bound(iface)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take the iface admin-down if AUTO_DOWN is enabled */
|
||||
if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN) &&
|
||||
!conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN)) {
|
||||
net_if_down(iface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform automated behaviors in response to any iface that loses oper-up state.
|
||||
*
|
||||
* This is how conn_mgr_conn automatically takes such ifaces admin-down if they are not persistent.
|
||||
*
|
||||
* @param iface - The iface which lost oper-up state.
|
||||
*/
|
||||
static void conn_mgr_conn_handle_iface_down(struct net_if *iface)
|
||||
{
|
||||
/* Ignore ifaces that don't have connectivity implementations */
|
||||
if (!conn_mgr_if_is_bound(iface)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the iface is persistent, we expect it to try to reconnect, so nothing else to do */
|
||||
if (conn_mgr_if_get_flag(iface, CONN_MGR_IF_PERSISTENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, we do not expect the iface to reconnect, and we should call
|
||||
* conn_mgr_conn_if_auto_admin_down
|
||||
*/
|
||||
conn_mgr_conn_if_auto_admin_down(iface);
|
||||
}
|
||||
|
||||
static struct net_mgmt_event_callback conn_mgr_conn_iface_cb;
|
||||
static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
|
||||
struct net_if *iface)
|
||||
|
@ -272,12 +339,45 @@ static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint
|
|||
}
|
||||
|
||||
switch (mgmt_event) {
|
||||
case NET_EVENT_IF_UP:
|
||||
case NET_EVENT_IF_DOWN:
|
||||
conn_mgr_conn_handle_iface_down(iface);
|
||||
break;
|
||||
case NET_EVENT_IF_ADMIN_UP:
|
||||
conn_mgr_conn_handle_iface_admin_up(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct net_mgmt_event_callback conn_mgr_conn_self_cb;
|
||||
static void conn_mgr_conn_self_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
|
||||
struct net_if *iface)
|
||||
{
|
||||
if ((mgmt_event & CONN_MGR_CONN_SELF_EVENTS_MASK) != mgmt_event) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (NET_MGMT_GET_COMMAND(mgmt_event)) {
|
||||
case NET_EVENT_CONN_CMD_IF_FATAL_ERROR:
|
||||
if (cb->info) {
|
||||
NET_ERR("Fatal connectivity error on iface %d (%p). Reason: %d.",
|
||||
net_if_get_by_iface(iface), iface, *((int *)cb->info)
|
||||
);
|
||||
} else {
|
||||
NET_ERR("Unknown fatal connectivity error on iface %d (%p).",
|
||||
net_if_get_by_iface(iface), iface
|
||||
);
|
||||
}
|
||||
__fallthrough;
|
||||
case NET_EVENT_CONN_CMD_IF_TIMEOUT:
|
||||
/* If a timeout or fatal error occurs, we do not expect the iface to try to
|
||||
* reconnect, so call conn_mgr_conn_if_auto_admin_down.
|
||||
*/
|
||||
conn_mgr_conn_if_auto_admin_down(iface);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void conn_mgr_conn_init(void)
|
||||
{
|
||||
/* Initialize connectivity bindings. */
|
||||
|
@ -305,6 +405,10 @@ void conn_mgr_conn_init(void)
|
|||
CONN_MGR_CONN_IFACE_EVENTS_MASK);
|
||||
net_mgmt_add_event_callback(&conn_mgr_conn_iface_cb);
|
||||
|
||||
net_mgmt_init_event_callback(&conn_mgr_conn_self_cb, conn_mgr_conn_self_handler,
|
||||
CONN_MGR_CONN_SELF_EVENTS_MASK);
|
||||
net_mgmt_add_event_callback(&conn_mgr_conn_self_cb);
|
||||
|
||||
/* Trigger any initial automated behaviors for ifaces */
|
||||
STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) {
|
||||
if (binding->impl->api) {
|
||||
|
|
|
@ -37,7 +37,11 @@
|
|||
#define CONN_MGR_IFACE_EVENTS_MASK (NET_EVENT_IF_DOWN | \
|
||||
NET_EVENT_IF_UP)
|
||||
|
||||
#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP)
|
||||
#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP |\
|
||||
NET_EVENT_IF_DOWN)
|
||||
|
||||
#define CONN_MGR_CONN_SELF_EVENTS_MASK (NET_EVENT_CONN_IF_TIMEOUT | \
|
||||
NET_EVENT_CONN_IF_FATAL_ERROR)
|
||||
|
||||
#define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \
|
||||
NET_EVENT_IPV6_ADDR_DEL | \
|
||||
|
|
|
@ -44,9 +44,6 @@ static void reset_test_iface(struct net_if *iface)
|
|||
struct in6_addr *ll_ipv6;
|
||||
|
||||
if (net_if_is_admin_up(iface)) {
|
||||
if (conn_mgr_if_is_bound(iface)) {
|
||||
(void)conn_mgr_if_disconnect(iface);
|
||||
}
|
||||
(void)net_if_down(iface);
|
||||
}
|
||||
|
||||
|
@ -206,10 +203,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb)
|
|||
"No events should be fired if connectivity availability did not change.");
|
||||
|
||||
/* Take A down */
|
||||
if (conn_mgr_if_is_bound(ifa)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifa), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifa.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa.");
|
||||
|
||||
/* Expect no events */
|
||||
|
@ -219,10 +212,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb)
|
|||
"No events should be fired if connectivity availability did not change.");
|
||||
|
||||
/* Take B down */
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifb), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifb.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb.");
|
||||
|
||||
/* Expect connectivity loss */
|
||||
|
@ -266,10 +255,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
"No events should be fired if connectivity availability did not change.");
|
||||
|
||||
/* Take B down */
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifb), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifb.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb.");
|
||||
|
||||
/* Expect no events */
|
||||
|
@ -300,10 +285,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
"No events should be fired if connectivity availability did not change.");
|
||||
|
||||
/* Take B down */
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifb), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifba.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb.");
|
||||
|
||||
/* Expect no events */
|
||||
|
@ -313,10 +294,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
"No events should be fired if connectivity availability did not change.");
|
||||
|
||||
/* Take A down */
|
||||
if (conn_mgr_if_is_bound(ifa)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifa), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifa.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa.");
|
||||
|
||||
/* Expect connectivity lost */
|
||||
|
@ -353,10 +330,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
zassert_equal(stats.conn_iface, ifa, "ifa should be blamed.");
|
||||
|
||||
/* Take B down */
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifb), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifb.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb.");
|
||||
|
||||
/* Expect no events */
|
||||
|
@ -368,10 +341,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
|
||||
/* Take B up */
|
||||
zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb.");
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_connect(ifb), 0,
|
||||
"conn_mgr_if_connect should succeed for ifb.");
|
||||
}
|
||||
|
||||
/* Expect no events */
|
||||
k_sleep(EVENT_WAIT_TIME);
|
||||
|
@ -392,10 +361,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb)
|
|||
zassert_equal(stats.dconn_iface, ifa, "ifa should be blamed.");
|
||||
|
||||
/* Take B down */
|
||||
if (conn_mgr_if_is_bound(ifb)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(ifb), 0,
|
||||
"conn_mgr_if_disconnect should succeed for ifb.");
|
||||
}
|
||||
zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb.");
|
||||
|
||||
/* Expect no events */
|
||||
|
@ -566,10 +531,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm)
|
|||
/* (10 -> 00): Lose oper-up from semi-ready state */
|
||||
|
||||
/* Take iface down */
|
||||
if (conn_mgr_if_is_bound(iface)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(iface), 0,
|
||||
"conn_mgr_if_disconnect should succeed.");
|
||||
}
|
||||
zassert_equal(net_if_down(iface), 0, "net_if_down should succeed.");
|
||||
|
||||
/* Verify there are no events fired */
|
||||
|
@ -619,10 +580,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm)
|
|||
/* (11 -> 01): Lose oper-up from ready state */
|
||||
|
||||
/* Take iface down */
|
||||
if (conn_mgr_if_is_bound(iface)) {
|
||||
zassert_equal(conn_mgr_if_disconnect(iface), 0,
|
||||
"conn_mgr_if_disconnect should succeed.");
|
||||
}
|
||||
zassert_equal(net_if_down(iface), 0, "net_if_down should succeed.");
|
||||
|
||||
/* Verify events are fired */
|
||||
|
|
|
@ -59,8 +59,9 @@ static void reset_test_iface_state(struct net_if *iface)
|
|||
iface_binding->flags = 0;
|
||||
iface_binding->timeout = CONN_MGR_IF_NO_TIMEOUT;
|
||||
|
||||
/* Disable auto-connect */
|
||||
/* Disable auto-connect and auto-down */
|
||||
conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT, true);
|
||||
conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN, true);
|
||||
}
|
||||
|
||||
if (iface_data) {
|
||||
|
@ -919,4 +920,224 @@ ZTEST(conn_mgr_conn, test_auto_connect)
|
|||
zassert_true(net_if_is_up(ifa1), "Auto-connect should succeed if enabled.");
|
||||
}
|
||||
|
||||
/* Verify that if auto-down is enabled, disconnecting an iface also takes it down,
|
||||
* regardless of whether persistence is enabled, but only if auto-down is disabled.
|
||||
*/
|
||||
ZTEST(conn_mgr_conn, test_auto_down_disconnect)
|
||||
{
|
||||
/* For convenience, use auto-connect for this test. */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false);
|
||||
|
||||
/* Enable auto-down, disable persistence */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false);
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Disconnect iface */
|
||||
zassert_equal(conn_mgr_if_disconnect(ifa1), 0,
|
||||
"conn_mgr_if_disconnect should succeed.");
|
||||
|
||||
/* Verify down */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_false(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should trigger on direct disconnect.");
|
||||
|
||||
|
||||
|
||||
/* Enable persistence */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Disconnect iface */
|
||||
zassert_equal(conn_mgr_if_disconnect(ifa1), 0,
|
||||
"conn_mgr_if_disconnect should succeed.");
|
||||
|
||||
/* Verify down */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_false(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should trigger on direct disconnect, even if persistence is enabled.");
|
||||
|
||||
|
||||
|
||||
/* Disable auto-down */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Disconnect iface */
|
||||
zassert_equal(conn_mgr_if_disconnect(ifa1), 0,
|
||||
"conn_mgr_if_disconnect should succeed.");
|
||||
|
||||
/* Verify up */
|
||||
zassert_true(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should not trigger if it is disabled.");
|
||||
}
|
||||
|
||||
/* Verify that auto-down takes an iface down if connection is lost, but only if persistence is not
|
||||
* enabled, and only if auto-down is enabled.
|
||||
*/
|
||||
ZTEST(conn_mgr_conn, test_auto_down_conn_loss)
|
||||
{
|
||||
/* For convenience, use auto-connect for this test. */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false);
|
||||
|
||||
/* Enable auto-down, disable persistence */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false);
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Simulate connection loss */
|
||||
simulate_connection_loss(ifa1);
|
||||
|
||||
/* Verify down */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_false(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should trigger on connection loss if persistence is disabled.");
|
||||
|
||||
/* Enable persistence */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Simulate connection loss */
|
||||
simulate_connection_loss(ifa1);
|
||||
|
||||
/* Verify up */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should not trigger on connection loss if persistence is enabled.");
|
||||
|
||||
/* Disable persistence and disable auto-down*/
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false);
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true);
|
||||
|
||||
/* Reconnect iface */
|
||||
zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Simulate connection loss */
|
||||
simulate_connection_loss(ifa1);
|
||||
|
||||
/* Verify up */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should not trigger on connection loss if it is disabled.");
|
||||
}
|
||||
|
||||
/* Verify that timeout takes the iface down, even if
|
||||
* persistence is enabled, but only if auto-down is enabled.
|
||||
*/
|
||||
ZTEST(conn_mgr_conn, test_auto_down_timeout)
|
||||
{
|
||||
struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1);
|
||||
|
||||
/* For convenience, use auto-connect for this test. */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false);
|
||||
|
||||
/* Enable auto-down and persistence*/
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true);
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false);
|
||||
|
||||
/* Schedule timeout */
|
||||
ifa1_data->timeout = true;
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify iface down after timeout */
|
||||
k_sleep(SIMULATED_EVENT_WAIT_TIME);
|
||||
zassert_false(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should trigger on connection timeout, even if persistence is enabled.");
|
||||
|
||||
/* Disable auto-down */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true);
|
||||
|
||||
/* Take iface up (timing out again) */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify iface up after timeout */
|
||||
k_sleep(SIMULATED_EVENT_WAIT_TIME);
|
||||
zassert_true(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should not trigger on connection timeout if it is disabled.");
|
||||
}
|
||||
|
||||
|
||||
/* Verify that fatal error takes the iface down, even if
|
||||
* persistence is enabled, but only if auto-down is enabled.
|
||||
*/
|
||||
ZTEST(conn_mgr_conn, test_auto_down_fatal)
|
||||
{
|
||||
/* For convenience, use auto-connect for this test. */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false);
|
||||
|
||||
/* Enable auto-down and persistence */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true);
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Raise fatal error */
|
||||
simulate_fatal_error(ifa1, -EAGAIN);
|
||||
|
||||
/* Verify iface down after fatal error */
|
||||
k_sleep(SIMULATED_EVENT_WAIT_TIME);
|
||||
zassert_false(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should trigger on fatal error, even if persistence is enabled.");
|
||||
|
||||
/* Disable auto-down */
|
||||
conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true);
|
||||
|
||||
/* Take iface up */
|
||||
zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed.");
|
||||
|
||||
/* Verify connected */
|
||||
k_sleep(K_MSEC(1));
|
||||
zassert_true(net_if_is_up(ifa1), "Connection should succeed.");
|
||||
|
||||
/* Raise fatal error */
|
||||
simulate_fatal_error(ifa1, -EAGAIN);
|
||||
|
||||
/* Verify iface still up after fatal error */
|
||||
k_sleep(SIMULATED_EVENT_WAIT_TIME);
|
||||
zassert_true(net_if_is_admin_up(ifa1),
|
||||
"Auto-down should not trigger on fatal error if it is disabled.");
|
||||
}
|
||||
|
||||
|
||||
ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL);
|
||||
|
|
|
@ -67,11 +67,16 @@ static void simulate_timeout(struct net_if *target)
|
|||
simulate_event(target, 0);
|
||||
}
|
||||
|
||||
static void simulate_fatal_error(struct net_if *target, int reason)
|
||||
void simulate_fatal_error(struct net_if *target, int reason)
|
||||
{
|
||||
simulate_event(target, reason);
|
||||
}
|
||||
|
||||
void simulate_connection_loss(struct net_if *target)
|
||||
{
|
||||
net_if_dormant_on(target);
|
||||
}
|
||||
|
||||
/* Connectivity implementations */
|
||||
|
||||
static void inc_call_count(struct test_conn_data *data, bool a)
|
||||
|
|
|
@ -80,6 +80,25 @@ CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_NI);
|
|||
#define SIMULATED_EVENT_DELAY_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS)
|
||||
#define SIMULATED_EVENT_WAIT_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS + 10)
|
||||
|
||||
/* Helper API for controlling implementations from tests */
|
||||
|
||||
/**
|
||||
* @brief Simulate a connection loss on the target iface.
|
||||
*
|
||||
* @param target - iface to simulate connection loss on.
|
||||
*/
|
||||
void simulate_connection_loss(struct net_if *target);
|
||||
|
||||
/**
|
||||
* @brief Simulate a fatal error on the target iface
|
||||
*
|
||||
* Please do not simulate events on more than one iface at a time.
|
||||
*
|
||||
* @param target - iface to simulate fatal error on.
|
||||
* @param reason - Reason to be given for the fatal error.
|
||||
*/
|
||||
void simulate_fatal_error(struct net_if *target, int reason);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue