diff --git a/source/TR-181/include/wanmgr_dml.h b/source/TR-181/include/wanmgr_dml.h index feee2ebe..720364cb 100644 --- a/source/TR-181/include/wanmgr_dml.h +++ b/source/TR-181/include/wanmgr_dml.h @@ -393,6 +393,7 @@ typedef struct _WANMGR_IPV6_DATA uint32_t ipv6_TimeOffset; /* Params to store the IPv6 IPC message */ bool addrAssigned; /**< Have we been assigned an IPv6 address ? */ + bool addrConstructedFromIAPD; /**< TRUE if the WAN address was derived from the delegated prefix (IAPD) instead of a real IANA lease */ uint32_t addrCmd; bool prefixAssigned; /**< Have we been assigned a site prefix ? */ uint32_t prefixCmd; diff --git a/source/WanManager/wanmgr_dhcp_event_handler.c b/source/WanManager/wanmgr_dhcp_event_handler.c index 1f0e1184..263f4c92 100644 --- a/source/WanManager/wanmgr_dhcp_event_handler.c +++ b/source/WanManager/wanmgr_dhcp_event_handler.c @@ -114,6 +114,7 @@ static void copyDhcpv6Data(WANMGR_IPV6_DATA* pDhcpv6Data, const DHCP_MGR_IPV6_MS #ifdef FEATURE_DSLITE_V2 strncpy(pDhcpv6Data->aftr, leaseInfo->aftr, sizeof(pDhcpv6Data->aftr) - 1); #endif + pDhcpv6Data->addrConstructedFromIAPD = false; if(!pDhcpv6Data->addrAssigned && pDhcpv6Data->prefixAssigned) { /* In an IPv6 lease, if only IAPD is received and we never received IANA, diff --git a/source/WanManager/wanmgr_dhcpv6_apis.c b/source/WanManager/wanmgr_dhcpv6_apis.c index 2aafa2dd..c6f9f4d1 100644 --- a/source/WanManager/wanmgr_dhcpv6_apis.c +++ b/source/WanManager/wanmgr_dhcpv6_apis.c @@ -1671,6 +1671,7 @@ int wanmgr_construct_wan_address_from_IAPD(WANMGR_IPV6_DATA *pIpv6DataNew) } pIpv6DataNew->addrAssigned = true; + pIpv6DataNew->addrConstructedFromIAPD = true; pIpv6DataNew->addrCmd = IFADDRCONF_ADD; CcspTraceInfo(("%s %d Calculated WAN address %s/128\n", __FUNCTION__, __LINE__, pIpv6DataNew->address)); @@ -1774,12 +1775,17 @@ ANSC_STATUS wanmgr_handle_dhcpv6_event_data(DML_VIRTUAL_IFACE * pVirtIf) */ } } - else if(pDhcp6cInfoCur->addrAssigned && Ipv6DataNew.prefixAssigned) + else if(pDhcp6cInfoCur->addrAssigned && !pDhcp6cInfoCur->addrConstructedFromIAPD && Ipv6DataNew.prefixAssigned) { /* In an IPv6 lease, both IANA and IAPD details are sent together in a struct. * If only one of them is renewed, the other field will be set to its default value. * In this scenario, we should not consider IANA or IAPD as deleted. * If we reach this point, only IAPD has been renewed. Use the previous IANA details. + * + * Note: This only applies when the previous address was a real IANA lease. If the previous + * address was derived from the delegated prefix (addrConstructedFromIAPD), we fall through + * to the branch below so the WAN address is re-derived from the newly delegated prefix + * instead of reusing the stale address from the old prefix. */ CcspTraceWarning(("%s %d IANA is not assigned in this IPC msg, but we have IANA configured from previous lease. Assuming only IAPD renewed. \n", __FUNCTION__, __LINE__)); @@ -1792,7 +1798,9 @@ ANSC_STATUS wanmgr_handle_dhcpv6_event_data(DML_VIRTUAL_IFACE * pVirtIf) { /* In an IPv6 lease, if only IAPD is received and we never received IANA, * We can use the received IAPD to construct a Ipv6 /128 address which can be used for managerment and voice ... - * If we reach this point, only IAPD has been received. Calculate Wan Ipv6 address + * If we reach this point, only IAPD has been received (either for the first time, or the + * previously assigned address was itself derived from a now-stale prefix). Calculate the + * WAN Ipv6 address from the newly delegated prefix. */ CcspTraceInfo(("IANA is not assigned by DHCPV6. Constructing WAN address from the IAPD for Wan Interface \n")); @@ -1838,6 +1846,17 @@ ANSC_STATUS wanmgr_handle_dhcpv6_event_data(DML_VIRTUAL_IFACE * pVirtIf) CcspTraceWarning(("%s %d IAPD is not assigned in this IPC msg, but we have IAPD configured from previous lease. Assuming only IANA renewed. \n", __FUNCTION__, __LINE__)); WanMgr_CopyPreviousPrefix(pDhcp6cInfoCur, &Ipv6DataNew); } + else if(!pNewIpcMsg->addrAssigned && !pNewIpcMsg->prefixAssigned && + !IS_EMPTY_STRING(pNewIpcMsg->sitePrefix) && + strcmp(pDhcp6cInfoCur->sitePrefix, pNewIpcMsg->sitePrefix) == 0) + { + /* Neither IANA nor IAPD was assigned in this lease (e.g. a DHCPv6 renew failure reports the + * previously delegated prefix with zero lifetimes). As the reported prefix matches the one + * currently in use, treat this as the WAN IPv6 lease no longer being valid and bring the + * IPv6 connection down. */ + CcspTraceInfo(("%s %d Neither IANA nor IAPD assigned and prefix matches the current lease. Marking IPv6 connection down. \n", __FUNCTION__, __LINE__)); + WanManager_UpdateInterfaceStatus(pVirtIf, WANMGR_IFACE_CONNECTION_IPV6_DOWN); + } #else /* dhcp6c receives an IPv6 address for WAN interface */ @@ -1949,9 +1968,13 @@ ANSC_STATUS wanmgr_handle_dhcpv6_event_data(DML_VIRTUAL_IFACE * pVirtIf) /* Even when dhcp6c is not used to get the WAN interface IP address, * * use this message as a trigger to check the WAN interface IP. - * * Maybe we've been assigned an address by SLAAC.*/ + * * Maybe we've been assigned an address by SLAAC. + * Skip this SLAAC detection when our current WAN address was derived from the delegated prefix + * (addrConstructedFromIAPD): in that case a global address still lingering on the interface is + * our own stale IAPD-derived /128, not a genuine SLAAC address, and must not be used to keep + * IPv6 up. Letting the code continue leaves 'connected' FALSE so IPv6 is not marked up. */ - if (!pNewIpcMsg->addrAssigned) + if (!pNewIpcMsg->addrAssigned && !pDhcp6cInfoCur->addrConstructedFromIAPD) { char guAddrPrefix[IP_ADDR_LENGTH] = {0}; char guAddr[IP_ADDR_LENGTH] = {0};