Skip to content

Commit b92a43d

Browse files
JordanYatesjhedberg
authored andcommitted
net: conn_mgr_connectivity: idle timeouts
Implement idle timeouts, primarily in the common connectivity library, with individual interfaces notifying the library when the interface has been used. Signed-off-by: Jordan Yates <[email protected]>
1 parent 3a107e5 commit b92a43d

File tree

4 files changed

+88
-4
lines changed

4 files changed

+88
-4
lines changed

include/zephyr/net/conn_mgr_connectivity.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,19 @@ int conn_mgr_if_get_idle_timeout(struct net_if *iface);
298298
*/
299299
int conn_mgr_if_set_idle_timeout(struct net_if *iface, int timeout);
300300

301+
#if defined(CONFIG_NET_CONNECTION_MANAGER) || defined(__DOXYGEN__)
302+
/**
303+
* @brief Notify connection manager that interface was just used
304+
*
305+
* @note Typically called from network drivers, not application software.
306+
*
307+
* @param iface iface that was just used
308+
*/
309+
void conn_mgr_if_used(struct net_if *iface);
310+
#else
311+
#define conn_mgr_if_used(iface) (void)(iface)
312+
#endif /* defined(CONFIG_NET_CONNECTION_MANAGER) || defined(__DOXYGEN__) */
313+
301314
/**
302315
* @}
303316
*/

include/zephyr/net/conn_mgr_connectivity_impl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ struct conn_mgr_conn_binding {
206206
/** @} */
207207

208208
/** @cond INTERNAL_HIDDEN */
209+
/* Internal-use work item for tracking interface idle timeouts */
210+
struct k_work_delayable idle_worker;
211+
209212
/* Internal-use mutex for protecting access to the binding and API functions. */
210213
struct k_mutex *mutex;
211214
/** @endcond */

subsys/net/conn_mgr/conn_mgr_connectivity.c

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ int conn_mgr_if_connect(struct net_if *iface)
5151
return status;
5252
}
5353

54-
int conn_mgr_if_disconnect(struct net_if *iface)
54+
static int conn_mgr_if_disconnect_internal(struct net_if *iface, bool idle_timeout)
5555
{
5656
struct conn_mgr_conn_binding *binding;
5757
struct conn_mgr_conn_api *api;
@@ -75,7 +75,9 @@ int conn_mgr_if_disconnect(struct net_if *iface)
7575
goto out;
7676
}
7777

78-
conn_mgr_if_set_flag(iface, CONN_MGR_IF_DISCONNECTING, true);
78+
if (!idle_timeout) {
79+
conn_mgr_if_set_flag(iface, CONN_MGR_IF_DISCONNECTING, true);
80+
}
7981

8082
status = api->disconnect(binding);
8183

@@ -85,6 +87,11 @@ int conn_mgr_if_disconnect(struct net_if *iface)
8587
return status;
8688
}
8789

90+
int conn_mgr_if_disconnect(struct net_if *iface)
91+
{
92+
return conn_mgr_if_disconnect_internal(iface, false);
93+
}
94+
8895
bool conn_mgr_if_is_bound(struct net_if *iface)
8996
{
9097
struct conn_mgr_conn_binding *binding = conn_mgr_if_get_binding(iface);
@@ -261,6 +268,19 @@ int conn_mgr_if_set_idle_timeout(struct net_if *iface, int timeout)
261268
return 0;
262269
}
263270

271+
void conn_mgr_if_used(struct net_if *iface)
272+
{
273+
struct conn_mgr_conn_binding *binding = conn_mgr_if_get_binding(iface);
274+
275+
if (binding == NULL) {
276+
return;
277+
}
278+
if (binding->idle_timeout == CONN_MGR_IF_NO_TIMEOUT) {
279+
return;
280+
}
281+
k_work_reschedule(&binding->idle_worker, K_SECONDS(binding->idle_timeout));
282+
}
283+
264284
/* Automated behavior handling */
265285

266286
/**
@@ -299,6 +319,8 @@ static void conn_mgr_conn_handle_iface_admin_up(struct net_if *iface)
299319
*/
300320
static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface)
301321
{
322+
struct conn_mgr_conn_binding *binding = conn_mgr_if_get_binding(iface);
323+
302324
/* NOTE: This will be double-fired for ifaces that are both non-persistent
303325
* and are being directly requested to disconnect, since both of these conditions
304326
* separately trigger conn_mgr_conn_if_auto_admin_down.
@@ -308,17 +330,40 @@ static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface)
308330
*/
309331

310332
/* Ignore ifaces that don't have connectivity implementations */
311-
if (!conn_mgr_if_is_bound(iface)) {
333+
if (binding == NULL) {
312334
return;
313335
}
314336

337+
/* Cancel any pending idle timeouts */
338+
k_work_cancel_delayable(&binding->idle_worker);
339+
315340
/* Take the iface admin-down if AUTO_DOWN is enabled */
316341
if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN) &&
317342
!conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN)) {
318343
net_if_down(iface);
319344
}
320345
}
321346

347+
static void conn_mgr_conn_handle_iface_up(struct net_if *iface)
348+
{
349+
struct conn_mgr_conn_binding *binding = conn_mgr_if_get_binding(iface);
350+
int idle_timeout;
351+
352+
/* Ignore ifaces that don't have connectivity implementations */
353+
if (binding == NULL) {
354+
return;
355+
}
356+
357+
idle_timeout = conn_mgr_if_get_idle_timeout(iface);
358+
if (idle_timeout == CONN_MGR_IF_NO_TIMEOUT) {
359+
/* No idle timeout configured for the interface */
360+
return;
361+
}
362+
363+
/* Start the idle timeout */
364+
k_work_reschedule(&binding->idle_worker, K_SECONDS(idle_timeout));
365+
}
366+
322367
/**
323368
* @brief Perform automated behaviors in response to any iface that loses oper-up state.
324369
*
@@ -358,6 +403,9 @@ static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint
358403
}
359404

360405
switch (mgmt_event) {
406+
case NET_EVENT_IF_UP:
407+
conn_mgr_conn_handle_iface_up(iface);
408+
break;
361409
case NET_EVENT_IF_DOWN:
362410
conn_mgr_conn_handle_iface_down(iface);
363411
break;
@@ -393,8 +441,22 @@ static void conn_mgr_conn_self_handler(struct net_mgmt_event_callback *cb, uint6
393441
*/
394442
conn_mgr_conn_if_auto_admin_down(iface);
395443
break;
444+
case NET_EVENT_CONN_CMD_IF_IDLE_TIMEOUT:
445+
/* Interface is idle, disconnect */
446+
LOG_DBG("iface %d (%p) idle", net_if_get_by_iface(iface), iface);
447+
conn_mgr_if_disconnect_internal(iface, true);
448+
break;
396449
}
450+
}
451+
452+
static void conn_mgr_iface_idle_fn(struct k_work *work)
453+
{
454+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
455+
struct conn_mgr_conn_binding *binding =
456+
CONTAINER_OF(dwork, struct conn_mgr_conn_binding, idle_worker);
397457

458+
LOG_DBG("iface %d (%p) idle", net_if_get_by_iface(binding->iface), binding->iface);
459+
net_mgmt_event_notify(NET_EVENT_CONN_IF_IDLE_TIMEOUT, binding->iface);
398460
}
399461

400462
void conn_mgr_conn_init(void)
@@ -407,6 +469,10 @@ void conn_mgr_conn_init(void)
407469
} else if (binding->impl->api->init) {
408470
conn_mgr_binding_lock(binding);
409471

472+
/* Initialise idle worker */
473+
474+
k_work_init_delayable(&binding->idle_worker, conn_mgr_iface_idle_fn);
475+
410476
/* Set initial default values for binding state */
411477

412478
binding->timeout = CONN_MGR_IF_NO_TIMEOUT;

subsys/net/conn_mgr/conn_mgr_private.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@
4040
NET_EVENT_IF_UP)
4141

4242
#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP |\
43+
NET_EVENT_IF_UP |\
4344
NET_EVENT_IF_DOWN)
4445

4546
#define CONN_MGR_CONN_SELF_EVENTS_MASK (NET_EVENT_CONN_IF_TIMEOUT | \
46-
NET_EVENT_CONN_IF_FATAL_ERROR)
47+
NET_EVENT_CONN_IF_FATAL_ERROR | \
48+
NET_EVENT_CONN_IF_IDLE_TIMEOUT)
4749

4850
#define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \
4951
NET_EVENT_IPV6_ADDR_DEL | \

0 commit comments

Comments
 (0)