@@ -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+
8895bool 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 */
300320static 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
400462void 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 ;
0 commit comments