From 7d54a8c21bb61b9f6b01a8c8a977ecec60515107 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Tue, 26 May 2026 10:43:04 +0100 Subject: [PATCH 01/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 256 +++++++++++++++++------- 1 file changed, 184 insertions(+), 72 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index c858e368..54324524 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -59,6 +59,56 @@ #define POSTD_START_FILE "/tmp/.postd_started" #define SELECTED_MODE_TIMEOUT_SECONDS 10 +/* ── WAN Failure Time tracking ───────────────────────────────────────────── + * Records how long WAN was down (wan-status: stopped → started) when HOTSPOT + * (non-primary interface) becomes the active failover. + * Prints telemetry marker: WAN_FAILURE_TIME:secs + * ──────────────────────────────────────────────────────────────────────── */ +static struct timespec gWanFailureStartTime = {0}; +static bool gWanFailureTimerActive = false; + +static void WanMgr_RecordWanFailureStart(void) +{ + if (!gWanFailureTimerActive) + { + clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); + gWanFailureTimerActive = true; + CcspTraceInfo(("%s %d - WAN_FAILURE_TIME: failure timer started at %ld\n", + __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec)); + } +} + +static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceName) +{ + if (!gWanFailureTimerActive) + { + return; /* no failure was recorded, nothing to print */ + } + struct timespec now = {0}; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + long duration = now.tv_sec - gWanFailureStartTime.tv_sec; + char durStr[64] = {0}; + snprintf(durStr, sizeof(durStr), "%ldsecs", duration); + +#ifdef ENABLE_FEATURE_TELEMETRY2_0 + t2_event_s("WAN_FAILURE_TIME_split", durStr); +#endif + CcspTraceInfo(("%s %d - WAN_FAILURE_TIME:%s (failover iface: %s)\n", + __FUNCTION__, __LINE__, durStr, ifaceName ? ifaceName : "unknown")); + + gWanFailureTimerActive = false; + memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); +} + +static void WanMgr_ResetWanFailureTimer(void) +{ + gWanFailureTimerActive = false; + memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); +} + +#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) +extern lanState_t lanState; +#endif #if defined(FEATURE_464XLAT) typedef enum @@ -195,7 +245,7 @@ static ANSC_STATUS WanManager_ClearDHCPData(DML_VIRTUAL_IFACE * pVirtIf); * lan ipv6 address ready to use. * @return RETURN_OK on success else RETURN_ERR *************************************************************************************/ -static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf); +static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf); #ifdef FEATURE_MAPE /************************************************************************************* @@ -1032,38 +1082,57 @@ int wan_updateDNS(WanMgr_IfaceSM_Controller_t* pWanIfaceCtrl, BOOL addIPv4, BOOL return ret; } - -/** - * @brief Checks if the IPv6 address is ready to use. - * - * This function checks the tentative address, detects Duplicate Address Detection (DAD) - * failure, and verifies that a default route is present. - * If the default route is missing, it triggers a Router Solicitation. - * - * @param p_VirtIf Pointer to the virtual interface structure. - * @return int 0 on success, negative value on failure. +/* Check Duplicate Address Detection (DAD) status. The way it works is that + after an address is added to an interface, the operating system uses the + Neighbor Discovery Protocol to check if any other host on the network + has the same address. The whole process will take around 3 to 4 seconds + to complete. Also we need to check and ensure that the gateway has + a valid default route entry. */ -static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) +static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) { char buffer[BUFLEN_256] = {0}; - FILE *fp_dad = NULL; - FILE *fp_route = NULL; + FILE *fp_dad = NULL; + FILE *fp_route = NULL; int dad_flag = 0; int route_flag = 0; + int i; + char IfaceName[BUFLEN_16] = {0}; + int BridgeMode = 0; - /* Check Duplicate Address Detection (DAD) status. The way it works is that after an address is added to an interface, the operating system uses the - Neighbor Discovery Protocol to check if any other host on the network has the same address. The whole process will take around 3 to 4 seconds - to complete. Also we need to check and ensure that the gateway has a valid default route entry. - */ - // Note: This check is not strictly necessary and this check could delay the WAN up by 15 seconds in worst case. If the IPv6 address (IANA) is obtained via DHCPv6, and the DHCP client already performs the DAD check. - // However, it is beneficial to verify that the WAN IPv6 address is auto-calculated from the delegated prefix or via SLAAC. + { //TODO : temporary debug code to identify the bridgemode sysevent failure issue. + char Output[BUFLEN_16] = {0}; + if (sysevent_get(sysevent_fd, sysevent_token, "bridge_mode", Output, sizeof(Output)) !=0) + { + CcspTraceError(("%s-%d: bridge_mode sysevent get failed. \n", __FUNCTION__, __LINE__)); + } + BridgeMode = atoi(Output); + CcspTraceInfo(("%s-%d: <> bridge_mode sysevent value set to =%d \n", __FUNCTION__, __LINE__, BridgeMode)); + } + /*TODO: + *Below Code should be removed once V6 Prefix/IP is assigned on erouter0 Instead of brlan0 for sky Devices. + */ + strncpy(IfaceName, ETH_BRIDGE_NAME, sizeof(IfaceName)-1); + if (WanMgr_isBridgeModeEnabled() == TRUE) + { + CcspTraceInfo(("%s-%d: Device is in bridge mode. Assigning IPv6 address on WAN interface.\n", __FUNCTION__, __LINE__)); + memset(IfaceName, 0, sizeof(IfaceName)); + strncpy(IfaceName, p_VirtIf->Name, sizeof(IfaceName)-1); + } + CcspTraceInfo(("%s-%d: IfaceName=%s, BridgeMode=%d \n", __FUNCTION__, __LINE__, IfaceName, BridgeMode)); + + /* TODO: the below code assumes if the LAN ipv6 address is tentaive for 15 seconds DAD has failed. Do we need additional check? + * IANA dad is handled in the DHCPv6 client for the Wan Interface. + * Should we remove the IP from LAN bridge and request a different Delegated prefix? + * Should we use EUI-64 based Interface identifiers for all platforms? + */ - for(int i=0; i<15; i++) + for(i=0; i<15; i++) { buffer[0] = '\0'; if(dad_flag == 0) { - if ((fp_dad = v_secure_popen("r","ip address show dev %s tentative", p_VirtIf->Name))) + if ((fp_dad = v_secure_popen("r","ip address show dev %s tentative", IfaceName))) { if(fp_dad != NULL) { @@ -1076,6 +1145,7 @@ static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) } } } + if(dad_flag == 0) { sleep(1); @@ -1099,10 +1169,10 @@ static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) } } - //if DAD failed on WAN interface, log an ERROR message and continue with the WAN process. + //if DAD failed on LAN bridge, log an ERROR message and continue with the WAN process. if(dad_flag == 0 || route_flag == 0) { - CcspTraceError(("%s %d dad_flag[%s] route_flag[%s] Failed \n", __FUNCTION__, __LINE__, dad_flag ? "SUCCESS" : "FAILED", route_flag ? "SUCCESS" : "FAILED")); + CcspTraceError(("%s %d dad_flag[%d] route_flag[%d] Failed \n", __FUNCTION__, __LINE__,dad_flag,route_flag)); } if(route_flag == 0) @@ -1208,15 +1278,13 @@ static void updateInterfaceToVoiceManager(WanMgr_IfaceSM_Controller_t* pWanIface * @brief Removes IPv6 default route and global addresses from interface * * @param ifaceName Interface name (e.g., "eth0", "erouter0") - * @param ipv6Address The IPv6 address to remove NDP proxy for (can be NULL or empty) * @return RETURN_OK on success, RETURN_ERR on failure * * @note This API performs the following operations: * 1. Deletes IPv6 default route for the interface * 2. Flushes all global scope IPv6 addresses from the interface - * 3. Removes the NDP proxy entry for the WAN address from the LAN bridge */ -static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName, const char* ipv6Address) +static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName) { if (ifaceName == NULL || strlen(ifaceName) == 0) { @@ -1248,16 +1316,6 @@ static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName, const char* i ret = RETURN_ERR; } - /* Remove the specific NDP proxy entry for the WAN address from the LAN bridge. - * This was added by wanmgr_construct_wan_address_from_IAPD() to proxy the - * WAN /128 address on brlan0 for DAD protection and reachability. */ - if (ipv6Address != NULL && ipv6Address[0] != '\0') - { - memset(acCmdLine, 0, sizeof(acCmdLine)); - snprintf(acCmdLine, sizeof(acCmdLine), "ip -6 neigh del proxy %s dev %s", ipv6Address, COSA_DML_DHCPV6_SERVER_IFNAME); - WanManager_DoSystemActionWithStatus(__FUNCTION__, acCmdLine); - } - return ret; } @@ -1427,6 +1485,17 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STARTED, 0); CcspTraceInfo(("%s %d - wan-status event set to started \n", __FUNCTION__, __LINE__)); + /* WAN failure time marker: print duration if HOTSPOT (non-primary) took over, + * or silently reset the timer if the primary WAN recovered. */ + if (pInterface->IfaceConnectionType != WAN_IFACE_CONN_TYPE_PRIMARY) + { + WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + } + else + { + WanMgr_ResetWanFailureTimer(); + } + if(p_VirtIf->IP.Ipv4Data.ifname[0] != '\0' && pInterface->IfaceType != REMOTE_IFACE && (WAN_IFACE_CONN_TYPE_COLD_STANDBY != pInterface->IfaceConnectionType)) { syscfg_set_commit(NULL, SYSCFG_WAN_INTERFACE_NAME, p_VirtIf->IP.Ipv4Data.ifname); @@ -1530,6 +1599,8 @@ static int wan_tearDownIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status event set to stopped \n", __FUNCTION__, __LINE__)); + /* WAN failure timer: record the moment WAN went down (IPv4 teardown path) */ + WanMgr_RecordWanFailureStart(); } return ret; @@ -1647,11 +1718,19 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STARTED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STARTED, 0); - - - CcspTraceInfo(("%s %d - wan-status event set to started \n", __FUNCTION__, __LINE__)); + /* WAN failure time marker: print duration if HOTSPOT (non-primary) took over, + * or silently reset the timer if the primary WAN recovered. */ + if (pInterface->IfaceConnectionType != WAN_IFACE_CONN_TYPE_PRIMARY) + { + WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + } + else + { + WanMgr_ResetWanFailureTimer(); + } + /* Set the current WAN Interface name */ sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_CURRENT_WAN_IFNAME, p_VirtIf->IP.Ipv6Data.ifname, 0); if(p_VirtIf->IP.Ipv6Data.ifname[0] != '\0' && pInterface->IfaceType != REMOTE_IFACE && (WAN_IFACE_CONN_TYPE_COLD_STANDBY != pInterface->IfaceConnectionType) ) @@ -1742,15 +1821,14 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } } #endif - /** Unconfig IPv6. */ - if ( WanManager_Ipv6AddrUtil(p_VirtIf, DEL_ADDR) < 0) + if ( WanManager_Ipv6PrefixUtil(p_VirtIf->Name, DEL_ADDR,0,0) < 0) { AnscTraceError(("%s %d - Failed to remove inactive address \n", __FUNCTION__,__LINE__)); } /* Remove IPv6 default route and global addresses */ - if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address) != RETURN_OK) + if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name) != RETURN_OK) { CcspTraceError(("%s %d - Failed to remove IPv6 route and address for '%s'\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); @@ -1777,7 +1855,6 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); //RBUS_WAN_IP -// TODO: Verify that the RBUS_WAN_IP IPv6 sysevent keys cleared below are correct for all product variants when WAN IPv6 goes down. #if defined (RBUS_WAN_IP) #if defined(_RDKB_GLOBAL_PRODUCT_REQ_) unsigned char ConfigureWANIPv6OnLANBridgeSupport = FALSE; @@ -1811,6 +1888,8 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status , wan_service-status event set to stopped \n", __FUNCTION__, __LINE__)); + /* WAN failure timer: record the moment WAN went down (IPv6 teardown path) */ + WanMgr_RecordWanFailureStart(); } return ret; @@ -1986,14 +2065,14 @@ static ANSC_STATUS WanMgr_SendMsgTo_ConnectivityCheck(WanMgr_IfaceSM_Controller_ //Restarting firewall to add IPOE_HEALTH_CHECK firewall rules. sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); } - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_UP, p_VirtIf); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_UP, p_VirtIf->Name); pWanIfaceCtrl->IhcV4Status = IHC_STARTED; } } else if(type == CONNECTION_MSG_IPV4 && ConnStatus == FALSE) { CcspTraceInfo(("%s %d Sending IPOE_MSG_WAN_CONNECTION_DOWN \n", __FUNCTION__, __LINE__)); - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_DOWN, p_VirtIf); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_DOWN, p_VirtIf->Name); pWanIfaceCtrl->IhcV4Status = IHC_STOPPED; } else if(type == CONNECTION_MSG_IPV6 && ConnStatus == TRUE) @@ -2009,14 +2088,14 @@ static ANSC_STATUS WanMgr_SendMsgTo_ConnectivityCheck(WanMgr_IfaceSM_Controller_ //Restarting firewall to add IPOE_HEALTH_CHECK firewall rules. sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); } - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_UP, p_VirtIf); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_UP, p_VirtIf->Name); pWanIfaceCtrl->IhcV6Status = IHC_STARTED; } } else if(type == CONNECTION_MSG_IPV6 && ConnStatus == FALSE) { CcspTraceInfo(("%s %d Sending IPOE_MSG_WAN_CONNECTION_IPV6_DOWN \n", __FUNCTION__, __LINE__)); - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_DOWN, p_VirtIf); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_DOWN, p_VirtIf->Name); pWanIfaceCtrl->IhcV6Status = IHC_STOPPED; } @@ -2942,8 +3021,9 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa WanMgr_Rbus_EventPublishHandler(param_name, "", RBUS_STRING); snprintf(param_name, sizeof(param_name), "Device.X_RDK_WanManager.Interface.%d.VirtualInterface.%d.IP.IPv6Prefix", p_VirtIf->baseIfIdx+1, p_VirtIf->VirIfIdx+1); WanMgr_Rbus_EventPublishHandler(param_name, "", RBUS_STRING); + WanManager_UpdateInterfaceStatus (p_VirtIf, WANMGR_IFACE_CONNECTION_IPV6_DOWN); - // Disable accept_ra + //Disable accept_ra WanMgr_Configure_accept_ra(p_VirtIf, FALSE); /* @@ -2955,7 +3035,7 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa if (WanMgr_IsVoiceInterface(p_VirtIf)) { /* Clean up IPv6 routes and addresses only */ - WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address); + WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name); CcspTraceInfo(("%s %d - Voice interface '%s' IPv6 down - removing routes/addresses only\n", __FUNCTION__, __LINE__, p_VirtIf->Alias)); @@ -2988,23 +3068,13 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa else { /* Remove IPv6 default route and global addresses */ - if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address) != RETURN_OK) + if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name) != RETURN_OK) { CcspTraceError(("%s %d - Failed to remove IPv6 route and address for '%s'\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } } - WanManager_UpdateInterfaceStatus (p_VirtIf, WANMGR_IFACE_CONNECTION_IPV6_DOWN); - //clear IPv6 lease from the interface data - memset(&(p_VirtIf->IP.Ipv6Data), 0, sizeof(WANMGR_IPV6_DATA)); - if (p_VirtIf->IP.pIpcIpv6Data != NULL ) - { - //free memory - free(p_VirtIf->IP.pIpcIpv6Data); - p_VirtIf->IP.pIpcIpv6Data = NULL; - } - #if defined(FEATURE_464XLAT) xlat_status = xlat_state_get(); if(xlat_status == XLAT_ON) @@ -3180,15 +3250,16 @@ static eWanState_t wan_transition_map_up(WanMgr_IfaceSM_Controller_t* pWanIfaceC CcspTraceInfo(("%s %d - net.ipv4.ip_forward set to 1 \n", __FUNCTION__, __LINE__)); v_secure_system("sysctl -w net.ipv4.ip_forward=1"); - +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (WanManager_ProcessMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig), pInterface->Name, p_VirtIf->IP.Ipv6Data.ifname) != RETURN_OK) { CcspTraceError(("%s %d - Error processing MAP-T Parameters \n", __FUNCTION__, __LINE__)); return p_VirtIf->eCurrentState; } - +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); wanmgr_services_restart(); + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); #endif } else if (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE) @@ -3893,7 +3964,7 @@ static eWanState_t wan_state_obtaining_ip_addresses(WanMgr_IfaceSM_Controller_t* p_VirtIf->IP.Ipv6Changed = FALSE; return WAN_STATE_OBTAINING_IP_ADDRESSES; } - if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) { return wan_transition_ipv6_up(pWanIfaceCtrl); } @@ -3964,7 +4035,7 @@ static eWanState_t wan_state_standby(WanMgr_IfaceSM_Controller_t* pWanIfaceCtrl) } p_VirtIf->IP.Ipv6Changed = FALSE; } - if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) { ret = wan_transition_ipv6_up(pWanIfaceCtrl); CcspTraceInfo((" %s %d - IPv6 Address Assigned to Bridge Yet.\n", __FUNCTION__, __LINE__)); @@ -4073,7 +4144,7 @@ static eWanState_t wan_state_ipv4_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC p_VirtIf->IP.Ipv6Changed = FALSE; return WAN_STATE_IPV4_LEASED; } - if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) { return wan_transition_ipv6_up(pWanIfaceCtrl); } @@ -4181,7 +4252,7 @@ static eWanState_t wan_state_ipv6_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC } #if defined(FEATURE_MAPT) || defined(FEATURE_SUPPORT_MAPT_NAT46) || defined(FEATURE_MAPE) else if (pInterface->Selection.Status == WAN_IFACE_ACTIVE && - ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6AddressIsReadyToUse(p_VirtIf) ==RETURN_OK) + ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6LanAddressIsReadyToUse(p_VirtIf) ==RETURN_OK) || (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE && p_VirtIf->Status == WAN_IFACE_STATUS_UP && p_VirtIf->MAP.MapeStatus == WAN_IFACE_MAPE_STATE_UP))) { CcspTraceInfo(("%s %d - calling wan_transition_map_up \n", __FUNCTION__, __LINE__)); @@ -4210,6 +4281,18 @@ static eWanState_t wan_state_ipv6_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC WanMgr_CheckDefaultRA(p_VirtIf); +#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) + if(lanState == LAN_STATE_STOPPED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); + lanState = LAN_STATE_RESET; + } + else if(lanState == LAN_STATE_STARTED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); + lanState = LAN_STATE_RESET; + } +#endif return WAN_STATE_IPV6_LEASED; } @@ -4308,7 +4391,7 @@ static eWanState_t wan_state_dual_stack_active(WanMgr_IfaceSM_Controller_t* pWan } #if defined(FEATURE_MAPT) || defined(FEATURE_SUPPORT_MAPT_NAT46) || defined(FEATURE_MAPE) else if (pInterface->Selection.Status == WAN_IFACE_ACTIVE && - ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6AddressIsReadyToUse(p_VirtIf) ==RETURN_OK) + ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6LanAddressIsReadyToUse(p_VirtIf) ==RETURN_OK) || (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE && p_VirtIf->Status == WAN_IFACE_STATUS_UP && p_VirtIf->MAP.MapeStatus == WAN_IFACE_MAPE_STATE_UP))) { CcspTraceInfo(("%s %d - calling wan_transition_map_up \n", __FUNCTION__, __LINE__)); @@ -4344,6 +4427,18 @@ static eWanState_t wan_state_dual_stack_active(WanMgr_IfaceSM_Controller_t* pWan WanMgr_MonitorDhcpApps(pWanIfaceCtrl); WanMgr_CheckDefaultRA(p_VirtIf); +#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) + if(lanState == LAN_STATE_STOPPED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); + lanState = LAN_STATE_RESET; + } + else if(lanState == LAN_STATE_STARTED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); + lanState = LAN_STATE_RESET; + } +#endif return WAN_STATE_DUAL_STACK_ACTIVE; } @@ -4439,19 +4534,22 @@ static eWanState_t wan_state_map_active(WanMgr_IfaceSM_Controller_t* pWanIfaceCt #if defined(FEATURE_MAPT) else if (p_VirtIf->MAP.MaptChanged == TRUE) { + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (wan_tearDownMapt() == RETURN_OK) { if (WanManager_ResetMAPTConfiguration(pInterface->Name, p_VirtIf->Name) != RETURN_OK) { CcspTraceError(("%s %d Error resetting MAP-T configuration", __FUNCTION__, __LINE__)); } - +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (wan_setUpMapt() == RETURN_OK) { memset(&(p_VirtIf->MAP.MaptConfig), 0, sizeof(WANMGR_MAPT_CONFIG_DATA)); + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (WanManager_VerifyMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig)) == ANSC_STATUS_SUCCESS) { CcspTraceInfo(("%s %d - MAPT Configuration verification success \n", __FUNCTION__, __LINE__)); + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (WanManager_ProcessMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig), pInterface->Name, p_VirtIf->IP.Ipv6Data.ifname) == RETURN_OK) { p_VirtIf->MAP.MaptChanged = FALSE; @@ -4461,6 +4559,7 @@ static eWanState_t wan_state_map_active(WanMgr_IfaceSM_Controller_t* pWanIfaceCt { CcspTraceError(("%s %d - Failed to configure MAP-T for %s Interface \n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); } else { @@ -4476,6 +4575,7 @@ static eWanState_t wan_state_map_active(WanMgr_IfaceSM_Controller_t* pWanIfaceCt { CcspTraceError(("%s %d - Failed to tear down MAP-T for %s Interface \n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } + CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); } #endif else if (p_VirtIf->IP.Ipv6Renewed == TRUE) @@ -4483,12 +4583,24 @@ static eWanState_t wan_state_map_active(WanMgr_IfaceSM_Controller_t* pWanIfaceCt WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); p_VirtIf->IP.Ipv6Renewed = FALSE; } - +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); // Start DHCP apps if not started WanMgr_MonitorDhcpApps(pWanIfaceCtrl); - +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); WanMgr_CheckDefaultRA(p_VirtIf); - +#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) + if(lanState == LAN_STATE_STOPPED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); + lanState = LAN_STATE_RESET; + } + else if(lanState == LAN_STATE_STARTED) + { + WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); + lanState = LAN_STATE_RESET; + } +#endif +CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); return WAN_STATE_MAP_ACTIVE; } From ef8d346bcb5767f518844cd5fb849229c10b212f Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Tue, 26 May 2026 16:03:56 +0100 Subject: [PATCH 02/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 186 ++++++++++-------------- 1 file changed, 74 insertions(+), 112 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 54324524..ad19fe68 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -106,10 +106,6 @@ static void WanMgr_ResetWanFailureTimer(void) memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); } -#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) -extern lanState_t lanState; -#endif - #if defined(FEATURE_464XLAT) typedef enum { @@ -245,7 +241,7 @@ static ANSC_STATUS WanManager_ClearDHCPData(DML_VIRTUAL_IFACE * pVirtIf); * lan ipv6 address ready to use. * @return RETURN_OK on success else RETURN_ERR *************************************************************************************/ -static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf); +static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf); #ifdef FEATURE_MAPE /************************************************************************************* @@ -1082,57 +1078,38 @@ int wan_updateDNS(WanMgr_IfaceSM_Controller_t* pWanIfaceCtrl, BOOL addIPv4, BOOL return ret; } -/* Check Duplicate Address Detection (DAD) status. The way it works is that - after an address is added to an interface, the operating system uses the - Neighbor Discovery Protocol to check if any other host on the network - has the same address. The whole process will take around 3 to 4 seconds - to complete. Also we need to check and ensure that the gateway has - a valid default route entry. + +/** + * @brief Checks if the IPv6 address is ready to use. + * + * This function checks the tentative address, detects Duplicate Address Detection (DAD) + * failure, and verifies that a default route is present. + * If the default route is missing, it triggers a Router Solicitation. + * + * @param p_VirtIf Pointer to the virtual interface structure. + * @return int 0 on success, negative value on failure. */ -static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) +static int checkIpv6AddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) { char buffer[BUFLEN_256] = {0}; - FILE *fp_dad = NULL; - FILE *fp_route = NULL; + FILE *fp_dad = NULL; + FILE *fp_route = NULL; int dad_flag = 0; int route_flag = 0; - int i; - char IfaceName[BUFLEN_16] = {0}; - int BridgeMode = 0; - { //TODO : temporary debug code to identify the bridgemode sysevent failure issue. - char Output[BUFLEN_16] = {0}; - if (sysevent_get(sysevent_fd, sysevent_token, "bridge_mode", Output, sizeof(Output)) !=0) - { - CcspTraceError(("%s-%d: bridge_mode sysevent get failed. \n", __FUNCTION__, __LINE__)); - } - BridgeMode = atoi(Output); - CcspTraceInfo(("%s-%d: <> bridge_mode sysevent value set to =%d \n", __FUNCTION__, __LINE__, BridgeMode)); - } - /*TODO: - *Below Code should be removed once V6 Prefix/IP is assigned on erouter0 Instead of brlan0 for sky Devices. - */ - strncpy(IfaceName, ETH_BRIDGE_NAME, sizeof(IfaceName)-1); - if (WanMgr_isBridgeModeEnabled() == TRUE) - { - CcspTraceInfo(("%s-%d: Device is in bridge mode. Assigning IPv6 address on WAN interface.\n", __FUNCTION__, __LINE__)); - memset(IfaceName, 0, sizeof(IfaceName)); - strncpy(IfaceName, p_VirtIf->Name, sizeof(IfaceName)-1); - } - CcspTraceInfo(("%s-%d: IfaceName=%s, BridgeMode=%d \n", __FUNCTION__, __LINE__, IfaceName, BridgeMode)); + /* Check Duplicate Address Detection (DAD) status. The way it works is that after an address is added to an interface, the operating system uses the + Neighbor Discovery Protocol to check if any other host on the network has the same address. The whole process will take around 3 to 4 seconds + to complete. Also we need to check and ensure that the gateway has a valid default route entry. + */ + // Note: This check is not strictly necessary and this check could delay the WAN up by 15 seconds in worst case. If the IPv6 address (IANA) is obtained via DHCPv6, and the DHCP client already performs the DAD check. + // However, it is beneficial to verify that the WAN IPv6 address is auto-calculated from the delegated prefix or via SLAAC. - /* TODO: the below code assumes if the LAN ipv6 address is tentaive for 15 seconds DAD has failed. Do we need additional check? - * IANA dad is handled in the DHCPv6 client for the Wan Interface. - * Should we remove the IP from LAN bridge and request a different Delegated prefix? - * Should we use EUI-64 based Interface identifiers for all platforms? - */ - - for(i=0; i<15; i++) + for(int i=0; i<15; i++) { buffer[0] = '\0'; if(dad_flag == 0) { - if ((fp_dad = v_secure_popen("r","ip address show dev %s tentative", IfaceName))) + if ((fp_dad = v_secure_popen("r","ip address show dev %s tentative", p_VirtIf->Name))) { if(fp_dad != NULL) { @@ -1145,7 +1122,6 @@ static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) } } } - if(dad_flag == 0) { sleep(1); @@ -1169,10 +1145,10 @@ static int checkIpv6LanAddressIsReadyToUse(DML_VIRTUAL_IFACE* p_VirtIf) } } - //if DAD failed on LAN bridge, log an ERROR message and continue with the WAN process. + //if DAD failed on WAN interface, log an ERROR message and continue with the WAN process. if(dad_flag == 0 || route_flag == 0) { - CcspTraceError(("%s %d dad_flag[%d] route_flag[%d] Failed \n", __FUNCTION__, __LINE__,dad_flag,route_flag)); + CcspTraceError(("%s %d dad_flag[%s] route_flag[%s] Failed \n", __FUNCTION__, __LINE__, dad_flag ? "SUCCESS" : "FAILED", route_flag ? "SUCCESS" : "FAILED")); } if(route_flag == 0) @@ -1278,13 +1254,15 @@ static void updateInterfaceToVoiceManager(WanMgr_IfaceSM_Controller_t* pWanIface * @brief Removes IPv6 default route and global addresses from interface * * @param ifaceName Interface name (e.g., "eth0", "erouter0") + * @param ipv6Address The IPv6 address to remove NDP proxy for (can be NULL or empty) * @return RETURN_OK on success, RETURN_ERR on failure * * @note This API performs the following operations: * 1. Deletes IPv6 default route for the interface * 2. Flushes all global scope IPv6 addresses from the interface + * 3. Removes the NDP proxy entry for the WAN address from the LAN bridge */ -static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName) +static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName, const char* ipv6Address) { if (ifaceName == NULL || strlen(ifaceName) == 0) { @@ -1316,6 +1294,16 @@ static int WanMgr_RemoveIPv6RouteAndAddress(const char* ifaceName) ret = RETURN_ERR; } + /* Remove the specific NDP proxy entry for the WAN address from the LAN bridge. + * This was added by wanmgr_construct_wan_address_from_IAPD() to proxy the + * WAN /128 address on brlan0 for DAD protection and reachability. */ + if (ipv6Address != NULL && ipv6Address[0] != '\0') + { + memset(acCmdLine, 0, sizeof(acCmdLine)); + snprintf(acCmdLine, sizeof(acCmdLine), "ip -6 neigh del proxy %s dev %s", ipv6Address, COSA_DML_DHCPV6_SERVER_IFNAME); + WanManager_DoSystemActionWithStatus(__FUNCTION__, acCmdLine); + } + return ret; } @@ -1599,6 +1587,7 @@ static int wan_tearDownIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status event set to stopped \n", __FUNCTION__, __LINE__)); + /* WAN failure timer: record the moment WAN went down (IPv4 teardown path) */ WanMgr_RecordWanFailureStart(); } @@ -1718,6 +1707,9 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STARTED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STARTED, 0); + + + CcspTraceInfo(("%s %d - wan-status event set to started \n", __FUNCTION__, __LINE__)); /* WAN failure time marker: print duration if HOTSPOT (non-primary) took over, @@ -1821,14 +1813,15 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } } #endif + /** Unconfig IPv6. */ - if ( WanManager_Ipv6PrefixUtil(p_VirtIf->Name, DEL_ADDR,0,0) < 0) + if ( WanManager_Ipv6AddrUtil(p_VirtIf, DEL_ADDR) < 0) { AnscTraceError(("%s %d - Failed to remove inactive address \n", __FUNCTION__,__LINE__)); } /* Remove IPv6 default route and global addresses */ - if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name) != RETURN_OK) + if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address) != RETURN_OK) { CcspTraceError(("%s %d - Failed to remove IPv6 route and address for '%s'\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); @@ -1855,6 +1848,7 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); //RBUS_WAN_IP +// TODO: Verify that the RBUS_WAN_IP IPv6 sysevent keys cleared below are correct for all product variants when WAN IPv6 goes down. #if defined (RBUS_WAN_IP) #if defined(_RDKB_GLOBAL_PRODUCT_REQ_) unsigned char ConfigureWANIPv6OnLANBridgeSupport = FALSE; @@ -1888,6 +1882,7 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status , wan_service-status event set to stopped \n", __FUNCTION__, __LINE__)); + /* WAN failure timer: record the moment WAN went down (IPv6 teardown path) */ WanMgr_RecordWanFailureStart(); } @@ -2065,14 +2060,14 @@ static ANSC_STATUS WanMgr_SendMsgTo_ConnectivityCheck(WanMgr_IfaceSM_Controller_ //Restarting firewall to add IPOE_HEALTH_CHECK firewall rules. sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); } - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_UP, p_VirtIf->Name); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_UP, p_VirtIf); pWanIfaceCtrl->IhcV4Status = IHC_STARTED; } } else if(type == CONNECTION_MSG_IPV4 && ConnStatus == FALSE) { CcspTraceInfo(("%s %d Sending IPOE_MSG_WAN_CONNECTION_DOWN \n", __FUNCTION__, __LINE__)); - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_DOWN, p_VirtIf->Name); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_DOWN, p_VirtIf); pWanIfaceCtrl->IhcV4Status = IHC_STOPPED; } else if(type == CONNECTION_MSG_IPV6 && ConnStatus == TRUE) @@ -2088,14 +2083,14 @@ static ANSC_STATUS WanMgr_SendMsgTo_ConnectivityCheck(WanMgr_IfaceSM_Controller_ //Restarting firewall to add IPOE_HEALTH_CHECK firewall rules. sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); } - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_UP, p_VirtIf->Name); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_UP, p_VirtIf); pWanIfaceCtrl->IhcV6Status = IHC_STARTED; } } else if(type == CONNECTION_MSG_IPV6 && ConnStatus == FALSE) { CcspTraceInfo(("%s %d Sending IPOE_MSG_WAN_CONNECTION_IPV6_DOWN \n", __FUNCTION__, __LINE__)); - WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_DOWN, p_VirtIf->Name); + WanMgr_SendMsgToIHC(IPOE_MSG_WAN_CONNECTION_IPV6_DOWN, p_VirtIf); pWanIfaceCtrl->IhcV6Status = IHC_STOPPED; } @@ -3021,9 +3016,8 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa WanMgr_Rbus_EventPublishHandler(param_name, "", RBUS_STRING); snprintf(param_name, sizeof(param_name), "Device.X_RDK_WanManager.Interface.%d.VirtualInterface.%d.IP.IPv6Prefix", p_VirtIf->baseIfIdx+1, p_VirtIf->VirIfIdx+1); WanMgr_Rbus_EventPublishHandler(param_name, "", RBUS_STRING); - WanManager_UpdateInterfaceStatus (p_VirtIf, WANMGR_IFACE_CONNECTION_IPV6_DOWN); - //Disable accept_ra + // Disable accept_ra WanMgr_Configure_accept_ra(p_VirtIf, FALSE); /* @@ -3035,7 +3029,7 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa if (WanMgr_IsVoiceInterface(p_VirtIf)) { /* Clean up IPv6 routes and addresses only */ - WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name); + WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address); CcspTraceInfo(("%s %d - Voice interface '%s' IPv6 down - removing routes/addresses only\n", __FUNCTION__, __LINE__, p_VirtIf->Alias)); @@ -3068,13 +3062,23 @@ static eWanState_t wan_transition_ipv6_down(WanMgr_IfaceSM_Controller_t* pWanIfa else { /* Remove IPv6 default route and global addresses */ - if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name) != RETURN_OK) + if (WanMgr_RemoveIPv6RouteAndAddress(p_VirtIf->Name, p_VirtIf->IP.Ipv6Data.address) != RETURN_OK) { CcspTraceError(("%s %d - Failed to remove IPv6 route and address for '%s'\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } } + WanManager_UpdateInterfaceStatus (p_VirtIf, WANMGR_IFACE_CONNECTION_IPV6_DOWN); + //clear IPv6 lease from the interface data + memset(&(p_VirtIf->IP.Ipv6Data), 0, sizeof(WANMGR_IPV6_DATA)); + if (p_VirtIf->IP.pIpcIpv6Data != NULL ) + { + //free memory + free(p_VirtIf->IP.pIpcIpv6Data); + p_VirtIf->IP.pIpcIpv6Data = NULL; + } + #if defined(FEATURE_464XLAT) xlat_status = xlat_state_get(); if(xlat_status == XLAT_ON) @@ -3250,16 +3254,15 @@ static eWanState_t wan_transition_map_up(WanMgr_IfaceSM_Controller_t* pWanIfaceC CcspTraceInfo(("%s %d - net.ipv4.ip_forward set to 1 \n", __FUNCTION__, __LINE__)); v_secure_system("sysctl -w net.ipv4.ip_forward=1"); -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + if (WanManager_ProcessMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig), pInterface->Name, p_VirtIf->IP.Ipv6Data.ifname) != RETURN_OK) { CcspTraceError(("%s %d - Error processing MAP-T Parameters \n", __FUNCTION__, __LINE__)); return p_VirtIf->eCurrentState; } -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_FIREWALL_RESTART, NULL, 0); wanmgr_services_restart(); - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); #endif } else if (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE) @@ -3964,7 +3967,7 @@ static eWanState_t wan_state_obtaining_ip_addresses(WanMgr_IfaceSM_Controller_t* p_VirtIf->IP.Ipv6Changed = FALSE; return WAN_STATE_OBTAINING_IP_ADDRESSES; } - if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) { return wan_transition_ipv6_up(pWanIfaceCtrl); } @@ -4035,7 +4038,7 @@ static eWanState_t wan_state_standby(WanMgr_IfaceSM_Controller_t* pWanIfaceCtrl) } p_VirtIf->IP.Ipv6Changed = FALSE; } - if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) { ret = wan_transition_ipv6_up(pWanIfaceCtrl); CcspTraceInfo((" %s %d - IPv6 Address Assigned to Bridge Yet.\n", __FUNCTION__, __LINE__)); @@ -4144,7 +4147,7 @@ static eWanState_t wan_state_ipv4_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC p_VirtIf->IP.Ipv6Changed = FALSE; return WAN_STATE_IPV4_LEASED; } - if (checkIpv6LanAddressIsReadyToUse(p_VirtIf) == RETURN_OK) + if (checkIpv6AddressIsReadyToUse(p_VirtIf) == RETURN_OK) { return wan_transition_ipv6_up(pWanIfaceCtrl); } @@ -4252,7 +4255,7 @@ static eWanState_t wan_state_ipv6_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC } #if defined(FEATURE_MAPT) || defined(FEATURE_SUPPORT_MAPT_NAT46) || defined(FEATURE_MAPE) else if (pInterface->Selection.Status == WAN_IFACE_ACTIVE && - ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6LanAddressIsReadyToUse(p_VirtIf) ==RETURN_OK) + ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6AddressIsReadyToUse(p_VirtIf) ==RETURN_OK) || (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE && p_VirtIf->Status == WAN_IFACE_STATUS_UP && p_VirtIf->MAP.MapeStatus == WAN_IFACE_MAPE_STATE_UP))) { CcspTraceInfo(("%s %d - calling wan_transition_map_up \n", __FUNCTION__, __LINE__)); @@ -4281,18 +4284,6 @@ static eWanState_t wan_state_ipv6_leased(WanMgr_IfaceSM_Controller_t* pWanIfaceC WanMgr_CheckDefaultRA(p_VirtIf); -#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) - if(lanState == LAN_STATE_STOPPED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); - lanState = LAN_STATE_RESET; - } - else if(lanState == LAN_STATE_STARTED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); - lanState = LAN_STATE_RESET; - } -#endif return WAN_STATE_IPV6_LEASED; } @@ -4391,7 +4382,7 @@ static eWanState_t wan_state_dual_stack_active(WanMgr_IfaceSM_Controller_t* pWan } #if defined(FEATURE_MAPT) || defined(FEATURE_SUPPORT_MAPT_NAT46) || defined(FEATURE_MAPE) else if (pInterface->Selection.Status == WAN_IFACE_ACTIVE && - ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6LanAddressIsReadyToUse(p_VirtIf) ==RETURN_OK) + ((p_VirtIf->EnableMAPT == TRUE && p_VirtIf->MAP.MaptStatus == WAN_IFACE_MAPT_STATE_UP && checkIpv6AddressIsReadyToUse(p_VirtIf) ==RETURN_OK) || (p_VirtIf->MAP.dhcp6cMAPparameters.mapType == MAP_TYPE_MAPE && p_VirtIf->Status == WAN_IFACE_STATUS_UP && p_VirtIf->MAP.MapeStatus == WAN_IFACE_MAPE_STATE_UP))) { CcspTraceInfo(("%s %d - calling wan_transition_map_up \n", __FUNCTION__, __LINE__)); @@ -4427,18 +4418,6 @@ static eWanState_t wan_state_dual_stack_active(WanMgr_IfaceSM_Controller_t* pWan WanMgr_MonitorDhcpApps(pWanIfaceCtrl); WanMgr_CheckDefaultRA(p_VirtIf); -#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) - if(lanState == LAN_STATE_STOPPED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); - lanState = LAN_STATE_RESET; - } - else if(lanState == LAN_STATE_STARTED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); - lanState = LAN_STATE_RESET; - } -#endif return WAN_STATE_DUAL_STACK_ACTIVE; } @@ -4534,22 +4513,19 @@ static eWanState_t wan_state_map_active(WanMgr_IfaceSM_Controller_t* pWanIfaceCt #if defined(FEATURE_MAPT) else if (p_VirtIf->MAP.MaptChanged == TRUE) { - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (wan_tearDownMapt() == RETURN_OK) { if (WanManager_ResetMAPTConfiguration(pInterface->Name, p_VirtIf->Name) != RETURN_OK) { CcspTraceError(("%s %d Error resetting MAP-T configuration", __FUNCTION__, __LINE__)); } -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + if (wan_setUpMapt() == RETURN_OK) { memset(&(p_VirtIf->MAP.MaptConfig), 0, sizeof(WANMGR_MAPT_CONFIG_DATA)); - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (WanManager_VerifyMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig)) == ANSC_STATUS_SUCCESS) { CcspTraceInfo(("%s %d - MAPT Configuration verification success \n", __FUNCTION__, __LINE__)); - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); if (WanManager_ProcessMAPTConfiguration(&(p_VirtIf->MAP.dhcp6cMAPparameters), &(p_VirtIf->MAP.MaptConfig), pInterface->Name, p_VirtIf->IP.Ipv6Data.ifname) == RETURN_OK) { p_VirtIf->MAP.MaptChanged = FALSE; @@ -4559,7 +4535,6 @@ CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); { CcspTraceError(("%s %d - Failed to configure MAP-T for %s Interface \n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); } else { @@ -4575,7 +4550,6 @@ CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); { CcspTraceError(("%s %d - Failed to tear down MAP-T for %s Interface \n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } - CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); } #endif else if (p_VirtIf->IP.Ipv6Renewed == TRUE) @@ -4583,24 +4557,12 @@ CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); p_VirtIf->IP.Ipv6Renewed = FALSE; } -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + // Start DHCP apps if not started WanMgr_MonitorDhcpApps(pWanIfaceCtrl); -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + WanMgr_CheckDefaultRA(p_VirtIf); -#if defined(FEATURE_IPOE_HEALTH_CHECK) && defined(IPOE_HEALTH_CHECK_LAN_SYNC_SUPPORT) - if(lanState == LAN_STATE_STOPPED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , FALSE); - lanState = LAN_STATE_RESET; - } - else if(lanState == LAN_STATE_STARTED) - { - WanMgr_SendMsgTo_ConnectivityCheck(pWanIfaceCtrl, CONNECTION_MSG_IPV6 , TRUE); - lanState = LAN_STATE_RESET; - } -#endif -CcspTraceInfo(("%s %d Trace \n", __FUNCTION__, __LINE__)); + return WAN_STATE_MAP_ACTIVE; } From 7a9be28bd9f67239e861232c159a131f0b42b0d7 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 27 May 2026 12:30:40 +0100 Subject: [PATCH 03/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index ad19fe68..44e9d688 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -73,7 +73,7 @@ static void WanMgr_RecordWanFailureStart(void) { clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); gWanFailureTimerActive = true; - CcspTraceInfo(("%s %d - WAN_FAILURE_TIME: failure timer started at %ld\n", + CcspTraceInfo(("%s %d - WAN failure timer started at %ld\n", __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec)); } } @@ -87,8 +87,8 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceName) struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC_RAW, &now); long duration = now.tv_sec - gWanFailureStartTime.tv_sec; - char durStr[64] = {0}; - snprintf(durStr, sizeof(durStr), "%ldsecs", duration); + char durStr[128] = {0}; + snprintf(durStr, sizeof(durStr), "%s|%ldsecs", (ifaceName ? ifaceName : "unknown"), duration); #ifdef ENABLE_FEATURE_TELEMETRY2_0 t2_event_s("WAN_FAILURE_TIME_split", durStr); @@ -2176,10 +2176,21 @@ static eWanState_t wan_transition_start(WanMgr_IfaceSM_Controller_t* pWanIfaceCt } /*If WanManger restarted, get the status of existing VLAN, PPP inetrfaces.*/ - if(WanMgr_RestartFindExistingLink(pWanIfaceCtrl) == TRUE) + BOOL bExistingLinkFound = WanMgr_RestartFindExistingLink(pWanIfaceCtrl); + if(bExistingLinkFound == TRUE) { CcspTraceInfo(("%s %d - Already WAN interface %s created\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } + else + { + /* Boot-up WAN down: WAN was never up, so teardown functions never fire and + * the failure timer never gets started via the normal dynamic path. + * Record the start time here so the duration from boot (WAN unavailable) + * to failover activation is captured correctly. + * The guard inside WanMgr_RecordWanFailureStart() ensures the timer is + * set only once — by whichever interface SM enters this path first. */ + WanMgr_RecordWanFailureStart(); + } /*Should Update available status */ Update_Interface_Status(); From 430742477d30bc7f91e1aa23b7acbba7afd65028 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Fri, 29 May 2026 12:45:04 +0100 Subject: [PATCH 04/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 67 ++++++++++++++----------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 44e9d688..0f3faabf 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -62,7 +62,7 @@ /* ── WAN Failure Time tracking ───────────────────────────────────────────── * Records how long WAN was down (wan-status: stopped → started) when HOTSPOT * (non-primary interface) becomes the active failover. - * Prints telemetry marker: WAN_FAILURE_TIME:secs + * Prints telemetry marker: WAN_FAILURE_TIME:recovered by-,secs * ──────────────────────────────────────────────────────────────────────── */ static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; @@ -88,13 +88,12 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceName) clock_gettime(CLOCK_MONOTONIC_RAW, &now); long duration = now.tv_sec - gWanFailureStartTime.tv_sec; char durStr[128] = {0}; - snprintf(durStr, sizeof(durStr), "%s|%ldsecs", (ifaceName ? ifaceName : "unknown"), duration); + snprintf(durStr, sizeof(durStr), "%s|%ld", (ifaceName ? ifaceName : "unknown"), duration); #ifdef ENABLE_FEATURE_TELEMETRY2_0 - t2_event_s("WAN_FAILURE_TIME_split", durStr); + t2_event_s("WAN_DOWN_DURATION", durStr); #endif - CcspTraceInfo(("%s %d - WAN_FAILURE_TIME:%s (failover iface: %s)\n", - __FUNCTION__, __LINE__, durStr, ifaceName ? ifaceName : "unknown")); + CcspTraceInfo(("%s %d - WAN_DOWN_DURATION:%s\n",__FUNCTION__, __LINE__, durStr)); gWanFailureTimerActive = false; memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); @@ -1473,17 +1472,6 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STARTED, 0); CcspTraceInfo(("%s %d - wan-status event set to started \n", __FUNCTION__, __LINE__)); - /* WAN failure time marker: print duration if HOTSPOT (non-primary) took over, - * or silently reset the timer if the primary WAN recovered. */ - if (pInterface->IfaceConnectionType != WAN_IFACE_CONN_TYPE_PRIMARY) - { - WanMgr_PrintWanFailureTimeMarker(pInterface->Name); - } - else - { - WanMgr_ResetWanFailureTimer(); - } - if(p_VirtIf->IP.Ipv4Data.ifname[0] != '\0' && pInterface->IfaceType != REMOTE_IFACE && (WAN_IFACE_CONN_TYPE_COLD_STANDBY != pInterface->IfaceConnectionType)) { syscfg_set_commit(NULL, SYSCFG_WAN_INTERFACE_NAME, p_VirtIf->IP.Ipv4Data.ifname); @@ -1496,6 +1484,23 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) WanManager_PrintBootEvents (WAN_INIT_COMPLETE); } + /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both + * non-primary (HOT_STANDBY) and REMOTE interfaces are covered — these + * interface types bypass the WAN-STATUS sysevent block above and would + * otherwise never trigger the marker. + * HOT_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION + * (time from WAN failure/boot to this recovery). + * All other types → primary WAN recovered: discard the timer + * so a stale duration is never reported later. */ + if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_HOT_STANDBY || pInterface->IfaceType == REMOTE_IFACE) + { + WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + } + else + { + WanMgr_ResetWanFailureTimer(); + } + #if defined(_DT_WAN_Manager_Enable_) wanmgr_setSharedCGNAddress(p_VirtIf->IP.Ipv4Data.ip); #endif @@ -1712,17 +1717,6 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) CcspTraceInfo(("%s %d - wan-status event set to started \n", __FUNCTION__, __LINE__)); - /* WAN failure time marker: print duration if HOTSPOT (non-primary) took over, - * or silently reset the timer if the primary WAN recovered. */ - if (pInterface->IfaceConnectionType != WAN_IFACE_CONN_TYPE_PRIMARY) - { - WanMgr_PrintWanFailureTimeMarker(pInterface->Name); - } - else - { - WanMgr_ResetWanFailureTimer(); - } - /* Set the current WAN Interface name */ sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_CURRENT_WAN_IFNAME, p_VirtIf->IP.Ipv6Data.ifname, 0); if(p_VirtIf->IP.Ipv6Data.ifname[0] != '\0' && pInterface->IfaceType != REMOTE_IFACE && (WAN_IFACE_CONN_TYPE_COLD_STANDBY != pInterface->IfaceConnectionType) ) @@ -1754,7 +1748,24 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } #endif } - + + /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both + * non-primary (HOT_STANDBY) and REMOTE interfaces are covered — these + * interface types bypass the WAN-STATUS sysevent block above and would + * otherwise never trigger the marker. + * HOT_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION + * (time from WAN failure/boot to this recovery). + * All other types → primary WAN recovered: discard the timer + * so a stale duration is never reported later. */ + if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_HOT_STANDBY || pInterface->IfaceType == REMOTE_IFACE) + { + WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + } + else + { + WanMgr_ResetWanFailureTimer(); + } + WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } From ad152a57f8e44444a0dc2f8bd857f1406192edb2 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Fri, 29 May 2026 16:28:45 +0100 Subject: [PATCH 05/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 0f3faabf..ae7264b3 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -1485,14 +1485,14 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both - * non-primary (HOT_STANDBY) and REMOTE interfaces are covered — these + * non-primary (COLD_STANDBY) and REMOTE interfaces are covered — these * interface types bypass the WAN-STATUS sysevent block above and would * otherwise never trigger the marker. - * HOT_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION + * COLD_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION * (time from WAN failure/boot to this recovery). * All other types → primary WAN recovered: discard the timer * so a stale duration is never reported later. */ - if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_HOT_STANDBY || pInterface->IfaceType == REMOTE_IFACE) + if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) { WanMgr_PrintWanFailureTimeMarker(pInterface->Name); } @@ -1750,14 +1750,14 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both - * non-primary (HOT_STANDBY) and REMOTE interfaces are covered — these + * non-primary (COLD_STANDBY) and REMOTE interfaces are covered — these * interface types bypass the WAN-STATUS sysevent block above and would * otherwise never trigger the marker. - * HOT_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION + * COLD_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION * (time from WAN failure/boot to this recovery). * All other types → primary WAN recovered: discard the timer * so a stale duration is never reported later. */ - if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_HOT_STANDBY || pInterface->IfaceType == REMOTE_IFACE) + if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) { WanMgr_PrintWanFailureTimeMarker(pInterface->Name); } From 405a0d652173c7969fc313e6baa132197335651c Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Mon, 1 Jun 2026 16:04:00 +0100 Subject: [PATCH 06/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index ae7264b3..493e7c1b 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -62,7 +62,9 @@ /* ── WAN Failure Time tracking ───────────────────────────────────────────── * Records how long WAN was down (wan-status: stopped → started) when HOTSPOT * (non-primary interface) becomes the active failover. - * Prints telemetry marker: WAN_FAILURE_TIME:recovered by-,secs + * Records how long the customer had no internet service from the moment a WAN + * outage is detected until service resumes via a non-primary (failover) interface. + * Telemetry marker (T2): t2_event_s("WAN_DOWN_DURATION", "|") * ──────────────────────────────────────────────────────────────────────── */ static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; @@ -78,7 +80,7 @@ static void WanMgr_RecordWanFailureStart(void) } } -static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceName) +static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) { if (!gWanFailureTimerActive) { @@ -88,7 +90,7 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceName) clock_gettime(CLOCK_MONOTONIC_RAW, &now); long duration = now.tv_sec - gWanFailureStartTime.tv_sec; char durStr[128] = {0}; - snprintf(durStr, sizeof(durStr), "%s|%ld", (ifaceName ? ifaceName : "unknown"), duration); + snprintf(durStr, sizeof(durStr), "%s|%ld", (ifaceAlias ? ifaceAlias : "unknown"), duration); #ifdef ENABLE_FEATURE_TELEMETRY2_0 t2_event_s("WAN_DOWN_DURATION", durStr); @@ -1494,7 +1496,7 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) * so a stale duration is never reported later. */ if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) { - WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + WanMgr_PrintWanFailureTimeMarker(pInterface->AliasName); } else { @@ -1759,7 +1761,7 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) * so a stale duration is never reported later. */ if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) { - WanMgr_PrintWanFailureTimeMarker(pInterface->Name); + WanMgr_PrintWanFailureTimeMarker(pInterface->AliasName); } else { From 576dfc48682ec286439454aa19c9d0b637fb8762 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 3 Jun 2026 11:59:57 +0100 Subject: [PATCH 07/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 148 +++++++++++++++++- .../middle_layer_src/wanmgr_rdkbus_apis.h | 1 + source/WanManager/wanmgr_interface_sm.c | 93 ----------- source/WanManager/wanmgr_main.c | 5 + 4 files changed, 153 insertions(+), 94 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index 54cf325c..32e1a797 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -38,6 +38,7 @@ #include "wanmgr_rdkbus_apis.h" #include "dmsb_tr181_psm_definitions.h" #include "wanmgr_net_utils.h" +#include #include "wanmgr_interface_sm.h" #ifdef RBUS_BUILD_FLAG_ENABLE #include "wanmgr_rbus_handler_apis.h" @@ -1953,6 +1954,77 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) return RETURN_OK; } +/* ── WAN Failure Time Tracking ──────────────────────────────────────────────── + * Measures the duration of service outage experienced by the customer: + * start : the primary WAN interface loses its ACTIVE status + * stop : a non-primary (backup/failover) interface becomes ACTIVE + * reset : the primary interface recovers without backup involvement + * + * Telemetry marker (T2): + * t2_event_s("WAN_DOWN_DURATION", + * "|") + * + * Ownership: Update_Interface_Status() — driven purely by comparing the + * previous vs. newly-computed CurrentActiveInterface on every status poll, + * without any per-state-machine hooks in wanmgr_interface_sm.c. + * ─────────────────────────────────────────────────────────────────────────── */ +static struct timespec gWanFailureStartTime = {0}; +static bool gWanFailureTimerActive = false; + +static void WanMgr_RecordWanFailureStart(void) +{ + if (!gWanFailureTimerActive) + { + clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); + gWanFailureTimerActive = true; + CcspTraceInfo(("%s %d - WAN failure timer started at %ld\n", + __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec)); + } +} + +static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) +{ + if (!gWanFailureTimerActive) + return; + + struct timespec now = {0}; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + long duration = now.tv_sec - gWanFailureStartTime.tv_sec; + + char durStr[128] = {0}; + snprintf(durStr, sizeof(durStr), "%s|%ld", + (ifaceAlias ? ifaceAlias : "unknown"), duration); + +#ifdef ENABLE_FEATURE_TELEMETRY2_0 + t2_event_s("WAN_DOWN_DURATION", durStr); +#endif + CcspTraceInfo(("%s %d - WAN_DOWN_DURATION:%s\n", + __FUNCTION__, __LINE__, durStr)); + + gWanFailureTimerActive = false; + memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); +} + +static void WanMgr_ResetWanFailureTimer(void) +{ + gWanFailureTimerActive = false; + memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); +} + +/** + * WanMgr_FailureTimer_Init - Start the WAN outage timer at process boot-up. + * + * Called once from wanmgr_main.c before WanMgr_Core_Init() so that the clock + * begins ticking from the very first moment wanmanager is alive, capturing the + * full time-to-first-WAN duration in the WAN_DOWN_DURATION telemetry marker. + */ +void WanMgr_FailureTimer_Init(void) +{ + CcspTraceInfo(("%s %d - WAN failure timer initialised at process start\n", + __FUNCTION__, __LINE__)); + WanMgr_RecordWanFailureStart(); +} + ANSC_STATUS Update_Interface_Status() { struct IFACE_INFO *head = NULL; @@ -1970,6 +2042,13 @@ ANSC_STATUS Update_Interface_Status() CHAR prevCurrentStandbyInterface[BUFLEN_64] = {0}; CHAR prevCurrentActiveDNS[BUFLEN_256] = {0}; + /* + * activeIfaceAlias : AliasName of the WAN interface that currently owns + * CurrentActiveInterface. Populated in the iface loop and used by the + * WAN failure timer to decide print-vs-reset on recovery. + */ + CHAR activeIfaceAlias[BUFLEN_64] = {0}; + #ifdef RBUS_BUILD_FLAG_ENABLE CHAR CurrentWanStatus[BUFLEN_16] = "Down"; bool publishAvailableStatus = FALSE; @@ -2008,7 +2087,15 @@ ANSC_STATUS Update_Interface_Status() { continue; } - + + /* Capture the alias of the interface that is currently ACTIVE, + * so the WAN failure timer can identify it as backup or primary. */ + if (pWanIfaceData->Selection.Status == WAN_IFACE_ACTIVE) + { + snprintf(activeIfaceAlias, sizeof(activeIfaceAlias), "%s", + pWanIfaceData->AliasName); + } + struct IFACE_INFO *newIface = calloc(1, sizeof( struct IFACE_INFO)); newIface->next = NULL; @@ -2112,6 +2199,16 @@ ANSC_STATUS Update_Interface_Status() if (pWanConfigData != NULL) { DML_WANMGR_CONFIG* pWanDmlData = &(pWanConfigData->data); + + /* + * Snapshot the current active interface BEFORE any field updates. + * The WAN failure timer logic compares this (old) value against the + * freshly-computed CurrentActiveInterface to detect transitions. + */ + CHAR prevActiveForTimer[BUFLEN_64] = {0}; + strncpy(prevActiveForTimer, pWanDmlData->CurrentActiveInterface, + sizeof(prevActiveForTimer) - 1); + if(strcmp(pWanDmlData->InterfaceAvailableStatus,InterfaceAvailableStatus) != 0) { strncpy(prevInterfaceAvailableStatus,pWanDmlData->InterfaceAvailableStatus, sizeof(prevInterfaceAvailableStatus)-1); @@ -2226,6 +2323,55 @@ ANSC_STATUS Update_Interface_Status() publishCurrentStandbyInf = TRUE; #endif //RBUS_BUILD_FLAG_ENABLE } + + /* ── WAN Failure Time Tracking ────────────────────────────────────────── + * + * Timer start (run-time): the active interface is gone + * (CurrentActiveInterface empty, timer not yet running). + * Boot-up start is handled by WanMgr_FailureTimer_Init() + * called from wanmgr_main.c — the guard !gWanFailureTimerActive + * prevents a double-start here. + * + * Timer stop : an interface just became active (CurrentActiveInterface + * non-empty and changed from prev). + * - If the newly-active interface alias contains "HOTSPOT" or "REMOTE" + * it is a backup/failover interface → emit WAN_DOWN_DURATION telemetry. + * - Otherwise it is a primary interface recovering → reset silently. + * ─────────────────────────────────────────────────────────────────────── */ + if (CurrentActiveInterface[0] == '\0' && !gWanFailureTimerActive) + { + /* No active WAN interface (boot-up or run-time loss) — start outage timer */ + CcspTraceInfo(("%s %d - No active WAN interface (prev='%s')," + " starting failure timer\n", + __FUNCTION__, __LINE__, prevActiveForTimer)); + WanMgr_RecordWanFailureStart(); + } + else if (CurrentActiveInterface[0] != '\0' && + strcmp(prevActiveForTimer, CurrentActiveInterface) != 0 && + gWanFailureTimerActive) + { + /* An interface became active while the outage timer was running */ + bool isBackup = (strstr(activeIfaceAlias, "HOTSPOT") != NULL || + strstr(activeIfaceAlias, "REMOTE_LTE") != NULL); + if (isBackup) + { + /* Backup/failover took over — emit downtime duration */ + CcspTraceInfo(("%s %d - Backup interface '%s' (alias '%s') became" + " active, emitting WAN_DOWN_DURATION\n", + __FUNCTION__, __LINE__, + CurrentActiveInterface, activeIfaceAlias)); + WanMgr_PrintWanFailureTimeMarker(activeIfaceAlias); + } + else + { + /* Primary recovered — discard timer silently */ + CcspTraceInfo(("%s %d - Primary interface '%s' recovered," + " resetting failure timer\n", + __FUNCTION__, __LINE__, CurrentActiveInterface)); + WanMgr_ResetWanFailureTimer(); + } + } + WanMgrDml_GetConfigData_release(pWanConfigData); } #ifdef RBUS_BUILD_FLAG_ENABLE diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.h b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.h index 39bf6be8..6ce477fe 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.h +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.h @@ -78,6 +78,7 @@ ANSC_STATUS WanMgr_WanIfaceMarkingInit (); ANSC_STATUS WanMgr_Publish_WanStatus(UINT IfaceIndex, UINT VirId); ANSC_STATUS DmlSetWanActiveLinkInPSMDB( UINT uiInterfaceIdx, bool flag ); ANSC_STATUS WanController_ClearWanConfigurationsInPSM(); +void WanMgr_FailureTimer_Init(void); ANSC_STATUS Update_Interface_Status(); void WanMgr_getRemoteWanParamsFromPSM(DML_VIRTUAL_IFACE * pVirtIf); int get_Wan_Interface_ParametersFromPSM(ULONG instancenum, DML_WAN_IFACE* p_Interface); diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 493e7c1b..0823e6e3 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -59,54 +59,6 @@ #define POSTD_START_FILE "/tmp/.postd_started" #define SELECTED_MODE_TIMEOUT_SECONDS 10 -/* ── WAN Failure Time tracking ───────────────────────────────────────────── - * Records how long WAN was down (wan-status: stopped → started) when HOTSPOT - * (non-primary interface) becomes the active failover. - * Records how long the customer had no internet service from the moment a WAN - * outage is detected until service resumes via a non-primary (failover) interface. - * Telemetry marker (T2): t2_event_s("WAN_DOWN_DURATION", "|") - * ──────────────────────────────────────────────────────────────────────── */ -static struct timespec gWanFailureStartTime = {0}; -static bool gWanFailureTimerActive = false; - -static void WanMgr_RecordWanFailureStart(void) -{ - if (!gWanFailureTimerActive) - { - clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); - gWanFailureTimerActive = true; - CcspTraceInfo(("%s %d - WAN failure timer started at %ld\n", - __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec)); - } -} - -static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) -{ - if (!gWanFailureTimerActive) - { - return; /* no failure was recorded, nothing to print */ - } - struct timespec now = {0}; - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - long duration = now.tv_sec - gWanFailureStartTime.tv_sec; - char durStr[128] = {0}; - snprintf(durStr, sizeof(durStr), "%s|%ld", (ifaceAlias ? ifaceAlias : "unknown"), duration); - -#ifdef ENABLE_FEATURE_TELEMETRY2_0 - t2_event_s("WAN_DOWN_DURATION", durStr); -#endif - CcspTraceInfo(("%s %d - WAN_DOWN_DURATION:%s\n",__FUNCTION__, __LINE__, durStr)); - - gWanFailureTimerActive = false; - memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); -} - -static void WanMgr_ResetWanFailureTimer(void) -{ - gWanFailureTimerActive = false; - memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); -} - #if defined(FEATURE_464XLAT) typedef enum { @@ -1487,22 +1439,6 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both - * non-primary (COLD_STANDBY) and REMOTE interfaces are covered — these - * interface types bypass the WAN-STATUS sysevent block above and would - * otherwise never trigger the marker. - * COLD_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION - * (time from WAN failure/boot to this recovery). - * All other types → primary WAN recovered: discard the timer - * so a stale duration is never reported later. */ - if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) - { - WanMgr_PrintWanFailureTimeMarker(pInterface->AliasName); - } - else - { - WanMgr_ResetWanFailureTimer(); - } - #if defined(_DT_WAN_Manager_Enable_) wanmgr_setSharedCGNAddress(p_VirtIf->IP.Ipv4Data.ip); #endif @@ -1594,9 +1530,6 @@ static int wan_tearDownIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status event set to stopped \n", __FUNCTION__, __LINE__)); - - /* WAN failure timer: record the moment WAN went down (IPv4 teardown path) */ - WanMgr_RecordWanFailureStart(); } return ret; @@ -1752,22 +1685,6 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both - * non-primary (COLD_STANDBY) and REMOTE interfaces are covered — these - * interface types bypass the WAN-STATUS sysevent block above and would - * otherwise never trigger the marker. - * COLD_STANDBY / REMOTE → failover is active: emit WAN_DOWN_DURATION - * (time from WAN failure/boot to this recovery). - * All other types → primary WAN recovered: discard the timer - * so a stale duration is never reported later. */ - if (pInterface->IfaceConnectionType == WAN_IFACE_CONN_TYPE_COLD_STANDBY || pInterface->IfaceType == REMOTE_IFACE) - { - WanMgr_PrintWanFailureTimeMarker(pInterface->AliasName); - } - else - { - WanMgr_ResetWanFailureTimer(); - } - WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } @@ -1895,9 +1812,6 @@ static int wan_tearDownIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_STATUS, WAN_STATUS_STOPPED, 0); sysevent_set(sysevent_fd, sysevent_token, SYSEVENT_WAN_SERVICE_STATUS, WAN_STATUS_STOPPED, 0); CcspTraceInfo(("%s %d - wan-status , wan_service-status event set to stopped \n", __FUNCTION__, __LINE__)); - - /* WAN failure timer: record the moment WAN went down (IPv6 teardown path) */ - WanMgr_RecordWanFailureStart(); } return ret; @@ -2196,13 +2110,6 @@ static eWanState_t wan_transition_start(WanMgr_IfaceSM_Controller_t* pWanIfaceCt } else { - /* Boot-up WAN down: WAN was never up, so teardown functions never fire and - * the failure timer never gets started via the normal dynamic path. - * Record the start time here so the duration from boot (WAN unavailable) - * to failover activation is captured correctly. - * The guard inside WanMgr_RecordWanFailureStart() ensures the timer is - * set only once — by whichever interface SM enters this path first. */ - WanMgr_RecordWanFailureStart(); } /*Should Update available status */ diff --git a/source/WanManager/wanmgr_main.c b/source/WanManager/wanmgr_main.c index 87c9fbe6..5a501448 100644 --- a/source/WanManager/wanmgr_main.c +++ b/source/WanManager/wanmgr_main.c @@ -60,6 +60,7 @@ #include "wanmgr_core.h" #include "wanmgr_data.h" #include "wanmgr_webconfig_apis.h" +#include "wanmgr_rdkbus_apis.h" #include "stdlib.h" #include "ccsp_dm_api.h" @@ -376,6 +377,10 @@ int main(int argc, char* argv[]) close(fd_ret); } + /* Start the WAN outage timer now so the full boot-to-first-WAN duration + * is captured by the WAN_DOWN_DURATION telemetry marker. */ + WanMgr_FailureTimer_Init(); + //CORE INT WanMgr_Core_Init(); From 21a4525ca7955b435d942831d878184f64a702eb Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 3 Jun 2026 12:04:43 +0100 Subject: [PATCH 08/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 0823e6e3..870a134a 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -59,6 +59,7 @@ #define POSTD_START_FILE "/tmp/.postd_started" #define SELECTED_MODE_TIMEOUT_SECONDS 10 + #if defined(FEATURE_464XLAT) typedef enum { @@ -1438,7 +1439,6 @@ static int wan_setUpIPv4(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) WanManager_PrintBootEvents (WAN_INIT_COMPLETE); } - /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both #if defined(_DT_WAN_Manager_Enable_) wanmgr_setSharedCGNAddress(p_VirtIf->IP.Ipv4Data.ip); #endif @@ -1684,7 +1684,6 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) #endif } - /* WAN_DOWN_DURATION telemetry: evaluated unconditionally so that both WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } @@ -2103,14 +2102,10 @@ static eWanState_t wan_transition_start(WanMgr_IfaceSM_Controller_t* pWanIfaceCt } /*If WanManger restarted, get the status of existing VLAN, PPP inetrfaces.*/ - BOOL bExistingLinkFound = WanMgr_RestartFindExistingLink(pWanIfaceCtrl); - if(bExistingLinkFound == TRUE) + if(WanMgr_RestartFindExistingLink(pWanIfaceCtrl) == TRUE) { CcspTraceInfo(("%s %d - Already WAN interface %s created\n", __FUNCTION__, __LINE__, p_VirtIf->Name)); } - else - { - } /*Should Update available status */ Update_Interface_Status(); From eddd9c6ac6b716faf1f080dd0be9ac0f3640ae48 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 3 Jun 2026 12:06:43 +0100 Subject: [PATCH 09/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 870a134a..344dc3b9 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -1683,7 +1683,6 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } #endif } - WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } From 0038b9199f365bd5c20c2c2b58d474e42bc5f1cb Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj <166714137+LakshminarayananShenbagaraj@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:09:29 +0100 Subject: [PATCH 10/20] Update wanmgr_interface_sm.c --- source/WanManager/wanmgr_interface_sm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 344dc3b9..3b0b8cac 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -1683,6 +1683,7 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } #endif } + WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } From ffb68d878e57da617a9d9bab27a4ff5348dc0d5a Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 3 Jun 2026 12:11:23 +0100 Subject: [PATCH 11/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- source/WanManager/wanmgr_interface_sm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/WanManager/wanmgr_interface_sm.c b/source/WanManager/wanmgr_interface_sm.c index 3b0b8cac..c858e368 100644 --- a/source/WanManager/wanmgr_interface_sm.c +++ b/source/WanManager/wanmgr_interface_sm.c @@ -1683,7 +1683,7 @@ static int wan_setUpIPv6(WanMgr_IfaceSM_Controller_t * pWanIfaceCtrl) } #endif } - + WanMgr_StartConnectivityCheck(pWanIfaceCtrl); return ret; } From 3396693582e01209a1f2a067d0ee644a4e3229c9 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Wed, 3 Jun 2026 14:21:36 +0100 Subject: [PATCH 12/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: 1. WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index 32e1a797..aeddeae4 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1964,9 +1964,9 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) * t2_event_s("WAN_DOWN_DURATION", * "|") * - * Ownership: Update_Interface_Status() — driven purely by comparing the - * previous vs. newly-computed CurrentActiveInterface on every status poll, - * without any per-state-machine hooks in wanmgr_interface_sm.c. + * Ownership: Update_Interface_Status() — driven by PHY/link status and + * VirtIf.Status on every poll cycle, without any per-state-machine hooks + * in wanmgr_interface_sm.c. * ─────────────────────────────────────────────────────────────────────────── */ static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; @@ -2043,11 +2043,17 @@ ANSC_STATUS Update_Interface_Status() CHAR prevCurrentActiveDNS[BUFLEN_256] = {0}; /* - * activeIfaceAlias : AliasName of the WAN interface that currently owns - * CurrentActiveInterface. Populated in the iface loop and used by the - * WAN failure timer to decide print-vs-reset on recovery. + * activeIfaceAlias : AliasName of the WAN interface that is ACTIVE+UP + * this poll cycle. Used by the WAN failure timer to decide + * print-vs-reset on recovery. + * hasFullyActiveIface : true if any non-voice interface currently has + * Selection.Status == WAN_IFACE_ACTIVE AND VirtIf.Status == UP. + * activeIfacePhyDown : true if the ACTIVE interface has + * BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN this cycle. */ CHAR activeIfaceAlias[BUFLEN_64] = {0}; + bool hasFullyActiveIface = false; + bool activeIfacePhyDown = false; #ifdef RBUS_BUILD_FLAG_ENABLE CHAR CurrentWanStatus[BUFLEN_16] = "Down"; @@ -2088,12 +2094,20 @@ ANSC_STATUS Update_Interface_Status() continue; } - /* Capture the alias of the interface that is currently ACTIVE, - * so the WAN failure timer can identify it as backup or primary. */ + /* Capture alias and PHY/link state of the ACTIVE interface for + * the WAN failure timer decision (backup vs. primary recovery). */ if (pWanIfaceData->Selection.Status == WAN_IFACE_ACTIVE) { snprintf(activeIfaceAlias, sizeof(activeIfaceAlias), "%s", pWanIfaceData->AliasName); + + /* VirtIf UP means WAN service is fully established */ + if (p_VirtIf->Status == WAN_IFACE_STATUS_UP) + hasFullyActiveIface = true; + + /* PHY_DOWN while still ACTIVE means physical link lost */ + if (pWanIfaceData->BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN) + activeIfacePhyDown = true; } struct IFACE_INFO *newIface = calloc(1, sizeof( struct IFACE_INFO)); @@ -2200,15 +2214,6 @@ ANSC_STATUS Update_Interface_Status() { DML_WANMGR_CONFIG* pWanDmlData = &(pWanConfigData->data); - /* - * Snapshot the current active interface BEFORE any field updates. - * The WAN failure timer logic compares this (old) value against the - * freshly-computed CurrentActiveInterface to detect transitions. - */ - CHAR prevActiveForTimer[BUFLEN_64] = {0}; - strncpy(prevActiveForTimer, pWanDmlData->CurrentActiveInterface, - sizeof(prevActiveForTimer) - 1); - if(strcmp(pWanDmlData->InterfaceAvailableStatus,InterfaceAvailableStatus) != 0) { strncpy(prevInterfaceAvailableStatus,pWanDmlData->InterfaceAvailableStatus, sizeof(prevInterfaceAvailableStatus)-1); @@ -2326,48 +2331,53 @@ ANSC_STATUS Update_Interface_Status() /* ── WAN Failure Time Tracking ────────────────────────────────────────── * - * Timer start (run-time): the active interface is gone - * (CurrentActiveInterface empty, timer not yet running). + * Timer start : WAN service is lost. Triggered when no interface is + * fully active (ACTIVE + VirtIf UP), OR the currently + * ACTIVE interface has PHY_STATUS_DOWN (physical link lost + * before the selection state has been updated). * Boot-up start is handled by WanMgr_FailureTimer_Init() - * called from wanmgr_main.c — the guard !gWanFailureTimerActive - * prevents a double-start here. + * called from wanmgr_main.c; the !gWanFailureTimerActive + * guard prevents a double-start. * - * Timer stop : an interface just became active (CurrentActiveInterface - * non-empty and changed from prev). - * - If the newly-active interface alias contains "HOTSPOT" or "REMOTE" - * it is a backup/failover interface → emit WAN_DOWN_DURATION telemetry. - * - Otherwise it is a primary interface recovering → reset silently. + * Timer stop : a fully-active interface (ACTIVE + VirtIf UP) exists + * while the timer is running. This covers both the case + * where a new interface took over and the case where the + * same interface recovered from PHY/link loss. + * - Alias contains "HOTSPOT" or "REMOTE_LTE" → backup took over, + * emit WAN_DOWN_DURATION telemetry marker. + * - Otherwise the primary recovered → reset the timer silently. * ─────────────────────────────────────────────────────────────────────── */ - if (CurrentActiveInterface[0] == '\0' && !gWanFailureTimerActive) + bool wanServiceLost = !hasFullyActiveIface || activeIfacePhyDown; + + if (wanServiceLost && !gWanFailureTimerActive) { - /* No active WAN interface (boot-up or run-time loss) — start outage timer */ - CcspTraceInfo(("%s %d - No active WAN interface (prev='%s')," - " starting failure timer\n", - __FUNCTION__, __LINE__, prevActiveForTimer)); + CcspTraceInfo(("%s %d - WAN service lost (hasFullyActive=%d phyDown=%d)" + " — starting failure timer\n", + __FUNCTION__, __LINE__, + hasFullyActiveIface, activeIfacePhyDown)); WanMgr_RecordWanFailureStart(); } - else if (CurrentActiveInterface[0] != '\0' && - strcmp(prevActiveForTimer, CurrentActiveInterface) != 0 && - gWanFailureTimerActive) + else if (!wanServiceLost && gWanFailureTimerActive) { - /* An interface became active while the outage timer was running */ + /* WAN service restored while outage timer was running */ bool isBackup = (strstr(activeIfaceAlias, "HOTSPOT") != NULL || strstr(activeIfaceAlias, "REMOTE_LTE") != NULL); if (isBackup) { - /* Backup/failover took over — emit downtime duration */ + /* Backup/failover interface carried the traffic — emit duration */ CcspTraceInfo(("%s %d - Backup interface '%s' (alias '%s') became" - " active, emitting WAN_DOWN_DURATION\n", + " fully active, emitting WAN_DOWN_DURATION\n", __FUNCTION__, __LINE__, CurrentActiveInterface, activeIfaceAlias)); WanMgr_PrintWanFailureTimeMarker(activeIfaceAlias); } else { - /* Primary recovered — discard timer silently */ - CcspTraceInfo(("%s %d - Primary interface '%s' recovered," - " resetting failure timer\n", - __FUNCTION__, __LINE__, CurrentActiveInterface)); + /* Primary interface recovered — discard timer silently */ + CcspTraceInfo(("%s %d - Primary interface '%s' (alias '%s') fully" + " recovered, resetting failure timer\n", + __FUNCTION__, __LINE__, + CurrentActiveInterface, activeIfaceAlias)); WanMgr_ResetWanFailureTimer(); } } From 90da3d0930424ea5df9f8dbb033a093ef10bd36b Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Tue, 7 Jul 2026 11:17:34 +0100 Subject: [PATCH 13/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index aeddeae4..c1c47f87 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1970,19 +1970,24 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) * ─────────────────────────────────────────────────────────────────────────── */ static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; +static char gPrevActiveIfaceAlias[BUFLEN_64] = {0}; -static void WanMgr_RecordWanFailureStart(void) +static void WanMgr_RecordWanFailureStart(const char *prevAlias) { if (!gWanFailureTimerActive) { clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); gWanFailureTimerActive = true; - CcspTraceInfo(("%s %d - WAN failure timer started at %ld\n", - __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec)); + memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); + if (prevAlias && prevAlias[0] != '\0') + snprintf(gPrevActiveIfaceAlias, sizeof(gPrevActiveIfaceAlias), "%s", prevAlias); + CcspTraceInfo(("%s %d - WAN failure timer started at %ld (prev active: %s)\n", + __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec, + gPrevActiveIfaceAlias[0] ? gPrevActiveIfaceAlias : "NONE")); } } -static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) +static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) { if (!gWanFailureTimerActive) return; @@ -1991,9 +1996,13 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) clock_gettime(CLOCK_MONOTONIC_RAW, &now); long duration = now.tv_sec - gWanFailureStartTime.tv_sec; + const char *prevAlias = (gPrevActiveIfaceAlias[0] != '\0') ? gPrevActiveIfaceAlias : "NONE"; + char durStr[128] = {0}; - snprintf(durStr, sizeof(durStr), "%s|%ld", - (ifaceAlias ? ifaceAlias : "unknown"), duration); + snprintf(durStr, sizeof(durStr), "%s|%s|%ld", + prevAlias, + (currentAlias ? currentAlias : "unknown"), + duration); #ifdef ENABLE_FEATURE_TELEMETRY2_0 t2_event_s("WAN_DOWN_DURATION", durStr); @@ -2003,12 +2012,14 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *ifaceAlias) gWanFailureTimerActive = false; memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); + memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); } static void WanMgr_ResetWanFailureTimer(void) { gWanFailureTimerActive = false; memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); + memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); } /** @@ -2022,7 +2033,7 @@ void WanMgr_FailureTimer_Init(void) { CcspTraceInfo(("%s %d - WAN failure timer initialised at process start\n", __FUNCTION__, __LINE__)); - WanMgr_RecordWanFailureStart(); + WanMgr_RecordWanFailureStart(NULL); } ANSC_STATUS Update_Interface_Status() @@ -2052,8 +2063,8 @@ ANSC_STATUS Update_Interface_Status() * BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN this cycle. */ CHAR activeIfaceAlias[BUFLEN_64] = {0}; - bool hasFullyActiveIface = false; - bool activeIfacePhyDown = false; + bool bIsInterfaceActive = false; + bool bIsActiveIfaceWanDown = false; #ifdef RBUS_BUILD_FLAG_ENABLE CHAR CurrentWanStatus[BUFLEN_16] = "Down"; @@ -2103,11 +2114,11 @@ ANSC_STATUS Update_Interface_Status() /* VirtIf UP means WAN service is fully established */ if (p_VirtIf->Status == WAN_IFACE_STATUS_UP) - hasFullyActiveIface = true; + bIsInterfaceActive = true; - /* PHY_DOWN while still ACTIVE means physical link lost */ - if (pWanIfaceData->BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN) - activeIfacePhyDown = true; + /* PHY_DOWN while still ACTIVE means physical link lost and Virtual Interface Down when WAN refresh or reconnection case */ + if ( pWanIfaceData->BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN || p_VirtIf->Status != WAN_IFACE_STATUS_UP ) + bIsActiveIfaceWanDown = true; } struct IFACE_INFO *newIface = calloc(1, sizeof( struct IFACE_INFO)); @@ -2347,15 +2358,15 @@ ANSC_STATUS Update_Interface_Status() * emit WAN_DOWN_DURATION telemetry marker. * - Otherwise the primary recovered → reset the timer silently. * ─────────────────────────────────────────────────────────────────────── */ - bool wanServiceLost = !hasFullyActiveIface || activeIfacePhyDown; + bool wanServiceLost = !bIsInterfaceActive || bIsActiveIfaceWanDown; if (wanServiceLost && !gWanFailureTimerActive) { - CcspTraceInfo(("%s %d - WAN service lost (hasFullyActive=%d phyDown=%d)" + CcspTraceInfo(("%s %d - WAN service lost (IsIfaceActive=%d wanDown=%d)" " — starting failure timer\n", __FUNCTION__, __LINE__, - hasFullyActiveIface, activeIfacePhyDown)); - WanMgr_RecordWanFailureStart(); + bIsInterfaceActive, bIsActiveIfaceWanDown)); + WanMgr_RecordWanFailureStart(activeIfaceAlias[0] ? activeIfaceAlias : NULL); } else if (!wanServiceLost && gWanFailureTimerActive) { From 2857a2644b0ab9b467cda152f5ea2f153672d5d5 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Tue, 7 Jul 2026 11:23:47 +0100 Subject: [PATCH 14/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_FAILURE_TIME event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_FAILURE_TIME Emitted as:t2_event_s("WAN_FAILURE_TIME_split", "secs") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index c1c47f87..01ece953 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1954,20 +1954,6 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) return RETURN_OK; } -/* ── WAN Failure Time Tracking ──────────────────────────────────────────────── - * Measures the duration of service outage experienced by the customer: - * start : the primary WAN interface loses its ACTIVE status - * stop : a non-primary (backup/failover) interface becomes ACTIVE - * reset : the primary interface recovers without backup involvement - * - * Telemetry marker (T2): - * t2_event_s("WAN_DOWN_DURATION", - * "|") - * - * Ownership: Update_Interface_Status() — driven by PHY/link status and - * VirtIf.Status on every poll cycle, without any per-state-machine hooks - * in wanmgr_interface_sm.c. - * ─────────────────────────────────────────────────────────────────────────── */ static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; static char gPrevActiveIfaceAlias[BUFLEN_64] = {0}; @@ -2053,15 +2039,6 @@ ANSC_STATUS Update_Interface_Status() CHAR prevCurrentStandbyInterface[BUFLEN_64] = {0}; CHAR prevCurrentActiveDNS[BUFLEN_256] = {0}; - /* - * activeIfaceAlias : AliasName of the WAN interface that is ACTIVE+UP - * this poll cycle. Used by the WAN failure timer to decide - * print-vs-reset on recovery. - * hasFullyActiveIface : true if any non-voice interface currently has - * Selection.Status == WAN_IFACE_ACTIVE AND VirtIf.Status == UP. - * activeIfacePhyDown : true if the ACTIVE interface has - * BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN this cycle. - */ CHAR activeIfaceAlias[BUFLEN_64] = {0}; bool bIsInterfaceActive = false; bool bIsActiveIfaceWanDown = false; @@ -2340,24 +2317,6 @@ ANSC_STATUS Update_Interface_Status() #endif //RBUS_BUILD_FLAG_ENABLE } - /* ── WAN Failure Time Tracking ────────────────────────────────────────── - * - * Timer start : WAN service is lost. Triggered when no interface is - * fully active (ACTIVE + VirtIf UP), OR the currently - * ACTIVE interface has PHY_STATUS_DOWN (physical link lost - * before the selection state has been updated). - * Boot-up start is handled by WanMgr_FailureTimer_Init() - * called from wanmgr_main.c; the !gWanFailureTimerActive - * guard prevents a double-start. - * - * Timer stop : a fully-active interface (ACTIVE + VirtIf UP) exists - * while the timer is running. This covers both the case - * where a new interface took over and the case where the - * same interface recovered from PHY/link loss. - * - Alias contains "HOTSPOT" or "REMOTE_LTE" → backup took over, - * emit WAN_DOWN_DURATION telemetry marker. - * - Otherwise the primary recovered → reset the timer silently. - * ─────────────────────────────────────────────────────────────────────── */ bool wanServiceLost = !bIsInterfaceActive || bIsActiveIfaceWanDown; if (wanServiceLost && !gWanFailureTimerActive) From 3e8b6ac695d3483461a030aca389d32fda688fbc Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Tue, 7 Jul 2026 16:41:31 +0100 Subject: [PATCH 15/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_DOWN_DURATION event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_DOWN_DURATION Emitted as:t2_event_s("WAN_DOWN_DURATION", "||") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index 01ece953..3f6dc95a 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1957,6 +1957,12 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; static char gPrevActiveIfaceAlias[BUFLEN_64] = {0}; +/* Sticky: records the alias of the last interface that was ACTIVE+VirtIf-UP. + * Updated on every poll cycle where WAN service is fully established. Never + * cleared by the timer — survives across failover events so that if the SM + * has already deactivated an interface by the time the poll cycle runs, the + * correct "previously active" alias is still available for the marker. */ +static char gLastKnownActiveAlias[BUFLEN_64] = {0}; static void WanMgr_RecordWanFailureStart(const char *prevAlias) { @@ -2319,13 +2325,23 @@ ANSC_STATUS Update_Interface_Status() bool wanServiceLost = !bIsInterfaceActive || bIsActiveIfaceWanDown; + /* Keep gLastKnownActiveAlias current while WAN service is healthy. + * Do this before the timer logic so the alias is already recorded + * if wanServiceLost flips true in the same poll cycle. */ + if (bIsInterfaceActive && activeIfaceAlias[0] != '\0') + { + snprintf(gLastKnownActiveAlias, sizeof(gLastKnownActiveAlias), + "%s", activeIfaceAlias); + } + if (wanServiceLost && !gWanFailureTimerActive) { CcspTraceInfo(("%s %d - WAN service lost (IsIfaceActive=%d wanDown=%d)" - " — starting failure timer\n", + " — starting failure timer (last known active: %s)\n", __FUNCTION__, __LINE__, - bIsInterfaceActive, bIsActiveIfaceWanDown)); - WanMgr_RecordWanFailureStart(activeIfaceAlias[0] ? activeIfaceAlias : NULL); + bIsInterfaceActive, bIsActiveIfaceWanDown, + gLastKnownActiveAlias[0] ? gLastKnownActiveAlias : "NONE")); + WanMgr_RecordWanFailureStart(gLastKnownActiveAlias[0] ? gLastKnownActiveAlias : NULL); } else if (!wanServiceLost && gWanFailureTimerActive) { From edf79395ca8aac678cc00b1df71983afbf62fa3f Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj <166714137+LakshminarayananShenbagaraj@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:33:17 +0100 Subject: [PATCH 16/20] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index eb0fc00b..9e34c978 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1999,7 +1999,8 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC_RAW, &now); long duration = now.tv_sec - gWanFailureStartTime.tv_sec; - + if (duration < 0) + duration = 0; const char *prevAlias = (gPrevActiveIfaceAlias[0] != '\0') ? gPrevActiveIfaceAlias : "NONE"; char durStr[128] = {0}; From 503dca3ffb3b5b939f3f4f5b177c1f79594f4a32 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Thu, 9 Jul 2026 16:18:13 +0100 Subject: [PATCH 17/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_DOWN_DURATION event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_DOWN_DURATION Emitted as:t2_event_s("WAN_DOWN_DURATION", "||") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 47 +++---------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index 9e34c978..d91f2ac0 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1969,11 +1969,6 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) static struct timespec gWanFailureStartTime = {0}; static bool gWanFailureTimerActive = false; static char gPrevActiveIfaceAlias[BUFLEN_64] = {0}; -/* Sticky: records the alias of the last interface that was ACTIVE+VirtIf-UP. - * Updated on every poll cycle where WAN service is fully established. Never - * cleared by the timer — survives across failover events so that if the SM - * has already deactivated an interface by the time the poll cycle runs, the - * correct "previously active" alias is still available for the marker. */ static char gLastKnownActiveAlias[BUFLEN_64] = {0}; static void WanMgr_RecordWanFailureStart(const char *prevAlias) @@ -2020,20 +2015,6 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); } -static void WanMgr_ResetWanFailureTimer(void) -{ - gWanFailureTimerActive = false; - memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); - memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); -} - -/** - * WanMgr_FailureTimer_Init - Start the WAN outage timer at process boot-up. - * - * Called once from wanmgr_main.c before WanMgr_Core_Init() so that the clock - * begins ticking from the very first moment wanmanager is alive, capturing the - * full time-to-first-WAN duration in the WAN_DOWN_DURATION telemetry marker. - */ void WanMgr_FailureTimer_Init(void) { CcspTraceInfo(("%s %d - WAN failure timer initialised at process start\n", @@ -2358,27 +2339,13 @@ ANSC_STATUS Update_Interface_Status() } else if (!wanServiceLost && gWanFailureTimerActive) { - /* WAN service restored while outage timer was running */ - bool isBackup = (strstr(activeIfaceAlias, "HOTSPOT") != NULL || - strstr(activeIfaceAlias, "REMOTE_LTE") != NULL); - if (isBackup) - { - /* Backup/failover interface carried the traffic — emit duration */ - CcspTraceInfo(("%s %d - Backup interface '%s' (alias '%s') became" - " fully active, emitting WAN_DOWN_DURATION\n", - __FUNCTION__, __LINE__, - CurrentActiveInterface, activeIfaceAlias)); - WanMgr_PrintWanFailureTimeMarker(activeIfaceAlias); - } - else - { - /* Primary interface recovered — discard timer silently */ - CcspTraceInfo(("%s %d - Primary interface '%s' (alias '%s') fully" - " recovered, resetting failure timer\n", - __FUNCTION__, __LINE__, - CurrentActiveInterface, activeIfaceAlias)); - WanMgr_ResetWanFailureTimer(); - } + /* WAN service restored while outage timer was running — emit duration + * regardless of which interface became active. */ + CcspTraceInfo(("%s %d - Interface '%s' (alias '%s') became fully active," + " emitting WAN_DOWN_DURATION\n", + __FUNCTION__, __LINE__, + CurrentActiveInterface, activeIfaceAlias)); + WanMgr_PrintWanFailureTimeMarker(activeIfaceAlias); } WanMgrDml_GetConfigData_release(pWanConfigData); From b9b625a6f94fd5c5169d1f10349a78e3242540b8 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Fri, 10 Jul 2026 11:25:46 +0100 Subject: [PATCH 18/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_DOWN_DURATION event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_DOWN_DURATION Emitted as:t2_event_s("WAN_DOWN_DURATION", "||") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index d91f2ac0..ac1b6d19 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1966,39 +1966,46 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) return RETURN_OK; } -static struct timespec gWanFailureStartTime = {0}; -static bool gWanFailureTimerActive = false; -static char gPrevActiveIfaceAlias[BUFLEN_64] = {0}; -static char gLastKnownActiveAlias[BUFLEN_64] = {0}; +/* ── WAN failure timer state ───────────────────────────────────────────────── + * All outage-tracking state collected in one struct; zeroing it resets everything. + * ─────────────────────────────────────────────────────────────────────────── */ +typedef struct { + struct timespec startTime; ///< Monotonic clock at outage start + bool active; ///< Timer is running + char prevAlias[BUFLEN_64]; ///< Alias active when the outage started + char lastKnownAlias[BUFLEN_64]; ///< Last fully-active alias (sticky, never cleared by timer) +} WanFailureTimer_t; + +static WanFailureTimer_t gWanFailureTimer = {0}; static void WanMgr_RecordWanFailureStart(const char *prevAlias) { - if (!gWanFailureTimerActive) + if (!gWanFailureTimer.active) { - clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureStartTime); - gWanFailureTimerActive = true; - memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); + clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureTimer.startTime); + gWanFailureTimer.active = true; + memset(gWanFailureTimer.prevAlias, 0, sizeof(gWanFailureTimer.prevAlias)); if (prevAlias && prevAlias[0] != '\0') - snprintf(gPrevActiveIfaceAlias, sizeof(gPrevActiveIfaceAlias), "%s", prevAlias); + snprintf(gWanFailureTimer.prevAlias, sizeof(gWanFailureTimer.prevAlias), "%s", prevAlias); CcspTraceInfo(("%s %d - WAN failure timer started at %ld (prev active: %s)\n", - __FUNCTION__, __LINE__, gWanFailureStartTime.tv_sec, - gPrevActiveIfaceAlias[0] ? gPrevActiveIfaceAlias : "NONE")); + __FUNCTION__, __LINE__, gWanFailureTimer.startTime.tv_sec, + gWanFailureTimer.prevAlias[0] ? gWanFailureTimer.prevAlias : "NONE")); } } static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) { - if (!gWanFailureTimerActive) + if (!gWanFailureTimer.active) return; struct timespec now = {0}; clock_gettime(CLOCK_MONOTONIC_RAW, &now); - long duration = now.tv_sec - gWanFailureStartTime.tv_sec; + long duration = now.tv_sec - gWanFailureTimer.startTime.tv_sec; if (duration < 0) duration = 0; - const char *prevAlias = (gPrevActiveIfaceAlias[0] != '\0') ? gPrevActiveIfaceAlias : "NONE"; + const char *prevAlias = (gWanFailureTimer.prevAlias[0] != '\0') ? gWanFailureTimer.prevAlias : "NONE"; - char durStr[128] = {0}; + char durStr[BUFLEN_256] = {0}; snprintf(durStr, sizeof(durStr), "%s|%s|%ld", prevAlias, (currentAlias ? currentAlias : "unknown"), @@ -2010,9 +2017,9 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) CcspTraceInfo(("%s %d - WAN_DOWN_DURATION:%s\n", __FUNCTION__, __LINE__, durStr)); - gWanFailureTimerActive = false; - memset(&gWanFailureStartTime, 0, sizeof(gWanFailureStartTime)); - memset(gPrevActiveIfaceAlias, 0, sizeof(gPrevActiveIfaceAlias)); + gWanFailureTimer.active = false; + memset(&gWanFailureTimer.startTime, 0, sizeof(gWanFailureTimer.startTime)); + memset(gWanFailureTimer.prevAlias, 0, sizeof(gWanFailureTimer.prevAlias)); } void WanMgr_FailureTimer_Init(void) @@ -2041,7 +2048,6 @@ ANSC_STATUS Update_Interface_Status() CHAR activeIfaceAlias[BUFLEN_64] = {0}; bool bIsInterfaceActive = false; - bool bIsActiveIfaceWanDown = false; #ifdef RBUS_BUILD_FLAG_ENABLE CHAR CurrentWanStatus[BUFLEN_16] = "Down"; @@ -2092,10 +2098,6 @@ ANSC_STATUS Update_Interface_Status() /* VirtIf UP means WAN service is fully established */ if (p_VirtIf->Status == WAN_IFACE_STATUS_UP) bIsInterfaceActive = true; - - /* PHY_DOWN while still ACTIVE means physical link lost and Virtual Interface Down when WAN refresh or reconnection case */ - if ( pWanIfaceData->BaseInterfaceStatus == WAN_IFACE_PHY_STATUS_DOWN || p_VirtIf->Status != WAN_IFACE_STATUS_UP ) - bIsActiveIfaceWanDown = true; } struct IFACE_INFO *newIface = calloc(1, sizeof( struct IFACE_INFO)); @@ -2317,27 +2319,27 @@ ANSC_STATUS Update_Interface_Status() #endif //RBUS_BUILD_FLAG_ENABLE } - bool wanServiceLost = !bIsInterfaceActive || bIsActiveIfaceWanDown; + bool wanServiceLost = !bIsInterfaceActive; - /* Keep gLastKnownActiveAlias current while WAN service is healthy. + /* Keep gWanFailureTimer.lastKnownAlias current while WAN service is healthy. * Do this before the timer logic so the alias is already recorded * if wanServiceLost flips true in the same poll cycle. */ if (bIsInterfaceActive && activeIfaceAlias[0] != '\0') { - snprintf(gLastKnownActiveAlias, sizeof(gLastKnownActiveAlias), + snprintf(gWanFailureTimer.lastKnownAlias, sizeof(gWanFailureTimer.lastKnownAlias), "%s", activeIfaceAlias); } - if (wanServiceLost && !gWanFailureTimerActive) + if (wanServiceLost && !gWanFailureTimer.active) { - CcspTraceInfo(("%s %d - WAN service lost (IsIfaceActive=%d wanDown=%d)" + CcspTraceInfo(("%s %d - WAN service lost (bIsInterfaceActive=%d)" " — starting failure timer (last known active: %s)\n", __FUNCTION__, __LINE__, - bIsInterfaceActive, bIsActiveIfaceWanDown, - gLastKnownActiveAlias[0] ? gLastKnownActiveAlias : "NONE")); - WanMgr_RecordWanFailureStart(gLastKnownActiveAlias[0] ? gLastKnownActiveAlias : NULL); + bIsInterfaceActive, + gWanFailureTimer.lastKnownAlias[0] ? gWanFailureTimer.lastKnownAlias : "NONE")); + WanMgr_RecordWanFailureStart(gWanFailureTimer.lastKnownAlias[0] ? gWanFailureTimer.lastKnownAlias : NULL); } - else if (!wanServiceLost && gWanFailureTimerActive) + else if (!wanServiceLost && gWanFailureTimer.active) { /* WAN service restored while outage timer was running — emit duration * regardless of which interface became active. */ From 673c055a73dae1de48f89e28ae80679c45925eb1 Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Fri, 10 Jul 2026 15:29:06 +0100 Subject: [PATCH 19/20] RDKB-65187 - WAN Manager - Telemetry for Ignite. Reason for change: Wan Manager MUST send WAN_DOWN_DURATION event with total time the customer has no internet service, from the moment WAN outage is detected to when internet service resumes via any available interface (HOTSPOT failover). The measured time MUST be reported as a positive integer in seconds and not be affected by NTP adjustments or system clock changes during the measurement window. Marker name:WAN_DOWN_DURATION Emitted as:t2_event_s("WAN_DOWN_DURATION", "||") Test Procedure: WANManager should run without any issue Risks: Medium Signed-off-by: LakshminarayananShenbagaraj --- .../middle_layer_src/wanmgr_rdkbus_apis.c | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index ac1b6d19..c5242f92 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1970,26 +1970,24 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) * All outage-tracking state collected in one struct; zeroing it resets everything. * ─────────────────────────────────────────────────────────────────────────── */ typedef struct { - struct timespec startTime; ///< Monotonic clock at outage start - bool active; ///< Timer is running - char prevAlias[BUFLEN_64]; ///< Alias active when the outage started - char lastKnownAlias[BUFLEN_64]; ///< Last fully-active alias (sticky, never cleared by timer) + struct timespec startTime; ///< Monotonic clock at outage start + bool active; ///< Timer is running + char lastKnownAlias[BUFLEN_64]; ///< Alias of the last fully-active interface. + ///< Holds the *previous* iface at marker-fire + ///< because the update runs after the timer logic. } WanFailureTimer_t; static WanFailureTimer_t gWanFailureTimer = {0}; -static void WanMgr_RecordWanFailureStart(const char *prevAlias) +static void WanMgr_RecordWanFailureStart(void) { if (!gWanFailureTimer.active) { clock_gettime(CLOCK_MONOTONIC_RAW, &gWanFailureTimer.startTime); gWanFailureTimer.active = true; - memset(gWanFailureTimer.prevAlias, 0, sizeof(gWanFailureTimer.prevAlias)); - if (prevAlias && prevAlias[0] != '\0') - snprintf(gWanFailureTimer.prevAlias, sizeof(gWanFailureTimer.prevAlias), "%s", prevAlias); CcspTraceInfo(("%s %d - WAN failure timer started at %ld (prev active: %s)\n", __FUNCTION__, __LINE__, gWanFailureTimer.startTime.tv_sec, - gWanFailureTimer.prevAlias[0] ? gWanFailureTimer.prevAlias : "NONE")); + gWanFailureTimer.lastKnownAlias[0] ? gWanFailureTimer.lastKnownAlias : "NONE")); } } @@ -2003,7 +2001,7 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) long duration = now.tv_sec - gWanFailureTimer.startTime.tv_sec; if (duration < 0) duration = 0; - const char *prevAlias = (gWanFailureTimer.prevAlias[0] != '\0') ? gWanFailureTimer.prevAlias : "NONE"; + const char *prevAlias = (gWanFailureTimer.lastKnownAlias[0] != '\0') ? gWanFailureTimer.lastKnownAlias : "NONE"; char durStr[BUFLEN_256] = {0}; snprintf(durStr, sizeof(durStr), "%s|%s|%ld", @@ -2019,14 +2017,13 @@ static void WanMgr_PrintWanFailureTimeMarker(const char *currentAlias) gWanFailureTimer.active = false; memset(&gWanFailureTimer.startTime, 0, sizeof(gWanFailureTimer.startTime)); - memset(gWanFailureTimer.prevAlias, 0, sizeof(gWanFailureTimer.prevAlias)); } void WanMgr_FailureTimer_Init(void) { CcspTraceInfo(("%s %d - WAN failure timer initialised at process start\n", __FUNCTION__, __LINE__)); - WanMgr_RecordWanFailureStart(NULL); + WanMgr_RecordWanFailureStart(); } ANSC_STATUS Update_Interface_Status() @@ -2319,30 +2316,23 @@ ANSC_STATUS Update_Interface_Status() #endif //RBUS_BUILD_FLAG_ENABLE } - bool wanServiceLost = !bIsInterfaceActive; - - /* Keep gWanFailureTimer.lastKnownAlias current while WAN service is healthy. - * Do this before the timer logic so the alias is already recorded - * if wanServiceLost flips true in the same poll cycle. */ - if (bIsInterfaceActive && activeIfaceAlias[0] != '\0') - { - snprintf(gWanFailureTimer.lastKnownAlias, sizeof(gWanFailureTimer.lastKnownAlias), - "%s", activeIfaceAlias); - } - - if (wanServiceLost && !gWanFailureTimer.active) + /* Timer logic runs BEFORE updating lastKnownAlias so that at marker-fire + * the alias still reflects the PREVIOUS interface, not the recovering one. + * At timer-start (!bIsInterfaceActive), lastKnownAlias is also already correct + * because the update block below is guarded by bIsInterfaceActive. */ + if (!bIsInterfaceActive && !gWanFailureTimer.active) { CcspTraceInfo(("%s %d - WAN service lost (bIsInterfaceActive=%d)" " — starting failure timer (last known active: %s)\n", __FUNCTION__, __LINE__, bIsInterfaceActive, gWanFailureTimer.lastKnownAlias[0] ? gWanFailureTimer.lastKnownAlias : "NONE")); - WanMgr_RecordWanFailureStart(gWanFailureTimer.lastKnownAlias[0] ? gWanFailureTimer.lastKnownAlias : NULL); + WanMgr_RecordWanFailureStart(); } - else if (!wanServiceLost && gWanFailureTimer.active) + else if (bIsInterfaceActive && gWanFailureTimer.active) { - /* WAN service restored while outage timer was running — emit duration - * regardless of which interface became active. */ + /* WAN service restored — lastKnownAlias still holds the previous + * interface alias because we haven't updated it yet this cycle. */ CcspTraceInfo(("%s %d - Interface '%s' (alias '%s') became fully active," " emitting WAN_DOWN_DURATION\n", __FUNCTION__, __LINE__, @@ -2350,6 +2340,13 @@ ANSC_STATUS Update_Interface_Status() WanMgr_PrintWanFailureTimeMarker(activeIfaceAlias); } + /* Update lastKnownAlias AFTER timer logic (see comment above). */ + if (bIsInterfaceActive && activeIfaceAlias[0] != '\0') + { + snprintf(gWanFailureTimer.lastKnownAlias, sizeof(gWanFailureTimer.lastKnownAlias), + "%s", activeIfaceAlias); + } + WanMgrDml_GetConfigData_release(pWanConfigData); } #ifdef RBUS_BUILD_FLAG_ENABLE From d34fc11f07a2f8df2dffba2308d49fac3095efca Mon Sep 17 00:00:00 2001 From: LakshminarayananShenbagaraj Date: Mon, 13 Jul 2026 11:27:27 +0100 Subject: [PATCH 20/20] Updated code comments. Signed-off-by: LakshminarayananShenbagaraj --- source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c index c5242f92..b0f8f19f 100644 --- a/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c +++ b/source/TR-181/middle_layer_src/wanmgr_rdkbus_apis.c @@ -1972,9 +1972,7 @@ int Update_Current_ActiveDNS(char* CurrentActiveDNS) typedef struct { struct timespec startTime; ///< Monotonic clock at outage start bool active; ///< Timer is running - char lastKnownAlias[BUFLEN_64]; ///< Alias of the last fully-active interface. - ///< Holds the *previous* iface at marker-fire - ///< because the update runs after the timer logic. + char lastKnownAlias[BUFLEN_64]; ///< Alias of the last fully-active interface } WanFailureTimer_t; static WanFailureTimer_t gWanFailureTimer = {0}; @@ -2316,10 +2314,6 @@ ANSC_STATUS Update_Interface_Status() #endif //RBUS_BUILD_FLAG_ENABLE } - /* Timer logic runs BEFORE updating lastKnownAlias so that at marker-fire - * the alias still reflects the PREVIOUS interface, not the recovering one. - * At timer-start (!bIsInterfaceActive), lastKnownAlias is also already correct - * because the update block below is guarded by bIsInterfaceActive. */ if (!bIsInterfaceActive && !gWanFailureTimer.active) { CcspTraceInfo(("%s %d - WAN service lost (bIsInterfaceActive=%d)"