diff --git a/source/WanManager/wanmgr_dhcp_event_handler.c b/source/WanManager/wanmgr_dhcp_event_handler.c index 556e4fee..dbc7e562 100644 --- a/source/WanManager/wanmgr_dhcp_event_handler.c +++ b/source/WanManager/wanmgr_dhcp_event_handler.c @@ -24,6 +24,8 @@ #include "wanmgr_dhcp_client_events.h" #include "wanmgr_net_utils.h" #include "wanmgr_dhcpv6_apis.h" + +extern WANMGR_DATA_ST gWanMgrDataBase; #ifdef FEATURE_MAPE #include "wanmgr_map_apis.h" #endif @@ -144,8 +146,22 @@ void WanMgr_ProcessDhcpClientEvent(DhcpEventThreadArgs *eventData) break; case DHCP_CLIENT_STOPPED: - CcspTraceInfo(("%s-%d : DHCPv4 client stopped for %s\n", __FUNCTION__, __LINE__, pVirtIf->Name)); - pVirtIf->IP.Dhcp4cStatus = DHCPC_STOPPED; + CcspTraceInfo(("%s-%d : DHCPv4 client stopped for %s (Dhcp4cStatus=%d)\n", __FUNCTION__, __LINE__, pVirtIf->Name, pVirtIf->IP.Dhcp4cStatus)); + if (pVirtIf->IP.Dhcp4cStatus == DHCPC_STARTED) + { + /* Client was stopped externally (not by WanManager). + * WanManager_StopDhcpv4Client sets Dhcp4cStatus=STOPPED + * synchronously before any event arrives, so DHCPC_STARTED + * here means the stop was NOT initiated by WanManager. + * Restart the client to maintain IPv4 connectivity. */ + pVirtIf->IP.Dhcp4cStatus = DHCPC_STOPPED; + CcspTraceInfo(("%s-%d : SELFHEAL - Restarting DHCPv4 client for %s\n", __FUNCTION__, __LINE__, pVirtIf->Name)); + WanManager_StartDhcpv4Client(pVirtIf, gWanMgrDataBase.IfaceCtrl.pIface[pVirtIf->baseIfIdx].data.Name, gWanMgrDataBase.IfaceCtrl.pIface[pVirtIf->baseIfIdx].data.IfaceType); + } + else + { + pVirtIf->IP.Dhcp4cStatus = DHCPC_STOPPED; + } break; case DHCP_CLIENT_FAILED: @@ -207,8 +223,22 @@ void WanMgr_ProcessDhcpClientEvent(DhcpEventThreadArgs *eventData) break; case DHCP_CLIENT_STOPPED: - CcspTraceInfo(("%s-%d : DHCPv6 client stopped for %s\n", __FUNCTION__, __LINE__, pVirtIf->Name)); - pVirtIf->IP.Dhcp6cStatus = DHCPC_STOPPED; + CcspTraceInfo(("%s-%d : DHCPv6 client stopped for %s (Dhcp6cStatus=%d)\n", __FUNCTION__, __LINE__, pVirtIf->Name, pVirtIf->IP.Dhcp6cStatus)); + if (pVirtIf->IP.Dhcp6cStatus == DHCPC_STARTED) + { + /* Client was stopped externally (not by WanManager). + * WanManager_StopDhcpv6Client sets Dhcp6cStatus=STOPPED + * synchronously before any event arrives, so DHCPC_STARTED + * here means the stop was NOT initiated by WanManager. + * Restart the client to maintain IPv6 connectivity. */ + pVirtIf->IP.Dhcp6cStatus = DHCPC_STOPPED; + CcspTraceInfo(("%s-%d : SELFHEAL - Restarting DHCPv6 client for %s\n", __FUNCTION__, __LINE__, pVirtIf->Name)); + WanManager_StartDhcpv6Client(pVirtIf, gWanMgrDataBase.IfaceCtrl.pIface[pVirtIf->baseIfIdx].data.IfaceType); + } + else + { + pVirtIf->IP.Dhcp6cStatus = DHCPC_STOPPED; + } break; case DHCP_CLIENT_FAILED: diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index c858e368..03eeb95d 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -2927,7 +2927,6 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa } else { - if(p_VirtIf->IP.Dhcp6cStatus != DHCPC_STARTED) { /* Start DHCPv6 Client */ diff --git a/source/WanManager/wanmgr_net_utils.c b/source/WanManager/wanmgr_net_utils.c index 44341ca8..82ca93c6 100644 --- a/source/WanManager/wanmgr_net_utils.c +++ b/source/WanManager/wanmgr_net_utils.c @@ -546,17 +546,22 @@ ANSC_STATUS WanManager_StopDhcpv6Client(DML_VIRTUAL_IFACE* pVirtIf, DHCP_RELEASE snprintf( dmlName, sizeof(dmlName), "%s.Enable", pVirtIf->IP.DHCPv6Iface ); snprintf( dmlValue, sizeof(dmlValue), "%s", "false"); } + /* Set status to STOPPED before issuing the stop request to eliminate the + * race where the STOPPED event arrives (and the worker thread processes it) + * before WanMgr_RdkBus_SetParamValues returns. Without this, the event + * handler would see Dhcp6cStatus==STARTED and trigger a spurious self-heal + * restart for an intentional stop. */ + pVirtIf->IP.Dhcp6cStatus = DHCPC_STOPPED; + pVirtIf->IP.Dhcp6cPid = 0; + WanMgr_UnSubscribeDhcpClientEvents(pVirtIf->IP.DHCPv6Iface); if (ANSC_STATUS_SUCCESS == WanMgr_RdkBus_SetParamValues(DHCPMGR_COMPONENT_NAME, DHCPMGR_DBUS_PATH, dmlName, dmlValue, ccsp_boolean, TRUE)) { CcspTraceInfo(("%s %d - Successfully set [%s] to DHCP Manager \n", __FUNCTION__, __LINE__, pVirtIf->Name)); - pVirtIf->IP.Dhcp6cStatus = DHCPC_STOPPED; - pVirtIf->IP.Dhcp6cPid = 0; } else { CcspTraceInfo(("%s %d - Failed setting [%s] to DHCP Manager \n", __FUNCTION__, __LINE__, pVirtIf->Name)); } - WanMgr_UnSubscribeDhcpClientEvents(pVirtIf->IP.DHCPv6Iface); return ANSC_STATUS_SUCCESS; #else if (is_release_required == STOP_DHCP_WITH_RELEASE) @@ -662,17 +667,22 @@ ANSC_STATUS WanManager_StopDhcpv4Client(DML_VIRTUAL_IFACE* pVirtIf, DHCP_RELEASE snprintf( dmlName, sizeof(dmlName), "%s.Enable", pVirtIf->IP.DHCPv4Iface ); snprintf( dmlValue, sizeof(dmlValue), "%s", "false"); } + /* Set status to STOPPED before issuing the stop request to eliminate the + * race where the STOPPED event arrives (and the worker thread processes it) + * before WanMgr_RdkBus_SetParamValues returns. Without this, the event + * handler would see Dhcp4cStatus==STARTED and trigger a spurious self-heal + * restart for an intentional stop. */ + pVirtIf->IP.Dhcp4cStatus = DHCPC_STOPPED; + pVirtIf->IP.Dhcp4cPid = 0; + WanMgr_UnSubscribeDhcpClientEvents(pVirtIf->IP.DHCPv4Iface); if (ANSC_STATUS_SUCCESS == WanMgr_RdkBus_SetParamValues(DHCPMGR_COMPONENT_NAME, DHCPMGR_DBUS_PATH, dmlName, dmlValue, ccsp_boolean, TRUE)) { CcspTraceInfo(("%s %d - Successfully set [%s] to DHCP Manager \n", __FUNCTION__, __LINE__, pVirtIf->Name)); - pVirtIf->IP.Dhcp4cStatus = DHCPC_STOPPED; - pVirtIf->IP.Dhcp4cPid = 0; } else { CcspTraceInfo(("%s %d - Failed setting [%s] to DHCP Manager \n", __FUNCTION__, __LINE__, pVirtIf->Name)); } - WanMgr_UnSubscribeDhcpClientEvents(pVirtIf->IP.DHCPv4Iface); if (IsReleaseNeeded == STOP_DHCP_WITH_RELEASE) { //TODO: sleep added to allow dhcpv4 client to send release before interface deconfig. This should be handled by dhcpmanager itself.