diff --git a/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc b/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc index 9785d3f5522..cc8c368c16f 100644 --- a/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc +++ b/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc @@ -2489,6 +2489,7 @@ void Ipv6NeighbourDiscovery::processRaPrefixInfoForAddrAutoConf(const Ipv6NdPref // changed structure of code below, 12.9.07 - CB bool isPrefixAssignedToInterface = false; + int assignedAddrIndex = -1; bool returnedHome = false; // 4.9.07 - CB for (int i = 0; i < ie->getProtocolData()->getNumAddresses(); i++) { @@ -2516,11 +2517,49 @@ void Ipv6NeighbourDiscovery::processRaPrefixInfoForAddrAutoConf(const Ipv6NdPref returnedHome = true; else { isPrefixAssignedToInterface = true; + assignedAddrIndex = i; EV_INFO << "The received Prefix is already assigned to the interface" << endl; // Zarrar Yousaf 19.07.07 break; } } } + + /*e) If the advertised prefix is equal to the prefix of an address + configured by stateless autoconfiguration in the list, the preferred + lifetime of the address is reset to the Preferred Lifetime in the + received advertisement. The specific action to perform for the valid + lifetime of the address depends on the Valid Lifetime in the received + advertisement and the remaining time to the valid lifetime expiration + of the previously autoconfigured address.*/ + if (isPrefixAssignedToInterface) { + auto *ipv6Data = ie->getProtocolDataForUpdate(); + simtime_t expiryTime = ipv6Data->getAddressExpiryTime(assignedAddrIndex); + // An address with an infinite valid lifetime was not autoconfigured from a + // Prefix Information option, so step (e) does not speak about it. + if (expiryTime != SIMTIME_ZERO) { + // RFC 4862 Section 5.5.3 (e) writes the remaining valid lifetime of the + // address as RemainingLifetime, and caps how far an unauthenticated + // advertisement may shorten it. Without that cap a single forged + // advertisement carrying short valid lifetimes could expire every + // address of a node; a legitimate advertisement, which the router + // repeats, always passes the first case and takes effect immediately. + const simtime_t twoHours = 7200; + simtime_t remainingLifetime = expiryTime - simTime(); + simtime_t newValidLifetime; + + if (validLifetime > twoHours || validLifetime > remainingLifetime) + newValidLifetime = validLifetime; // (e)(1) + else if (remainingLifetime <= twoHours) + newValidLifetime = remainingLifetime; // (e)(2), the advertisement is not authenticated + else + newValidLifetime = twoHours; // (e)(3) + + EV_INFO << "Prefix already assigned to the interface, refreshing lifetimes: valid " + << newValidLifetime << ", preferred " << preferredLifetime << endl; + ipv6Data->updateMatchingAddressExpiryTimes(prefix, prefixLength, + simTime() + newValidLifetime, simTime() + preferredLifetime); + } + } /*d) If the prefix advertised does not match the prefix of an address already in the list, and the Valid Lifetime is not 0, form an address (and add it to the list) by combining the advertised prefix with the link's diff --git a/src/inet/networklayer/ipv6/Ipv6InterfaceData.cc b/src/inet/networklayer/ipv6/Ipv6InterfaceData.cc index 9ee9a54cc13..b53266af3b3 100644 --- a/src/inet/networklayer/ipv6/Ipv6InterfaceData.cc +++ b/src/inet/networklayer/ipv6/Ipv6InterfaceData.cc @@ -362,6 +362,12 @@ Ipv6InterfaceData::AddressType Ipv6InterfaceData::getAddressType(int i) const return addresses[i].addrType; } +simtime_t Ipv6InterfaceData::getAddressExpiryTime(int i) const +{ + ASSERT(i >= 0 && i < (int)addresses.size()); + return addresses[i].expiryTime; +} + Ipv6InterfaceData::AddressType Ipv6InterfaceData::getAddressType(const Ipv6Address& addr) const { return getAddressType(findAddress(addr)); diff --git a/src/inet/networklayer/ipv6/Ipv6InterfaceData.h b/src/inet/networklayer/ipv6/Ipv6InterfaceData.h index e8389a19e35..7521eafbb69 100644 --- a/src/inet/networklayer/ipv6/Ipv6InterfaceData.h +++ b/src/inet/networklayer/ipv6/Ipv6InterfaceData.h @@ -490,6 +490,12 @@ class INET_API Ipv6InterfaceData : public InterfaceProtocolData */ AddressType getAddressType(int i) const; + /** + * Returns the time at which the valid lifetime of the ith address of the + * interface expires, or zero if that lifetime is infinite. + */ + simtime_t getAddressExpiryTime(int i) const; + /** * Returns the address type (HoA, CoA) of the provided address of the interface. */ diff --git a/tests/module/Ipv6_prefix_lifetime_refresh.test b/tests/module/Ipv6_prefix_lifetime_refresh.test new file mode 100644 index 00000000000..8e58cf26627 --- /dev/null +++ b/tests/module/Ipv6_prefix_lifetime_refresh.test @@ -0,0 +1,78 @@ +%description: +Tests that a repeated Prefix Information option refreshes the lifetimes of the +address the host already holds from that prefix (RFC 4862 Section 5.5.3 step e). + +The router advertises a prefix whose valid lifetime (20 s) and preferred +lifetime (10 s) are much shorter than the 60 s run, and re-advertises it every +4 s to 6 s. The host forms one address from the prefix and must then keep it +alive from the repeated advertisements, instead of forming a second address or +letting the first one lapse at the lifetime the first advertisement carried. + +%#-------------------------------------------------------------------------------------------------------------- +%file: test.ned +import inet.networklayer.configurator.ipv6.Ipv6NetworkConfigurator; +import inet.node.ipv6.Router6; +import inet.node.ipv6.StandardHost6; +import ned.DatarateChannel; + +network PrefixLifetimeRefreshNetwork +{ + types: + channel ethline extends DatarateChannel + { + delay = 0.1us; + datarate = 100Mbps; + } + submodules: + configurator: Ipv6NetworkConfigurator; + router: Router6; + host: StandardHost6; + connections: + host.ethg++ <--> ethline <--> router.ethg++; +} +%#-------------------------------------------------------------------------------------------------------------- +%file: config.xml + + + +%#-------------------------------------------------------------------------------------------------------------- +%inifile: omnetpp.ini +[General] +record-vector-results = false +ned-path = ../../../../src +network = PrefixLifetimeRefreshNetwork +sim-time-limit = 60s +cmdenv-express-mode = false +cmdenv-log-prefix = "%C: " + +**.ipv6.configurator.networkConfiguratorModule = "configurator" +*.configurator.assignAddressesToHosts = false +*.configurator.config = xmldoc("config.xml") + +# Advertise far more often than the advertised lifetimes, so that the address +# would lapse many times over if the advertisements did not refresh it. +**.neighbourDiscovery.minIntervalBetweenRAs = 4s +**.neighbourDiscovery.maxIntervalBetweenRAs = 6s + +# Ethernet NIC configuration +**.eth[*].queue.typename = "EthernetQosQueue" +**.eth[*].queue.dataQueue.typename = "DropTailQueue" +**.eth[*].queue.dataQueue.packetCapacity = 10 + +%#-------------------------------------------------------------------------------------------------------------- +%subst: /omnetpp::// +%#-------------------------------------------------------------------------------------------------------------- +%contains: stdout +PrefixLifetimeRefreshNetwork.host.ipv6.neighbourDiscovery: DAD completed for address aaaa:1:: +%#-------------------------------------------------------------------------------------------------------------- +%contains: stdout +PrefixLifetimeRefreshNetwork.host.ipv6.neighbourDiscovery: Prefix already assigned to the interface, refreshing lifetimes: valid 20, preferred 10 +%#-------------------------------------------------------------------------------------------------------------- +%postrun-command: grep -c "Assigning new address to: eth0" test.out > test_newaddr.out || true +%contains: test_newaddr.out +1 +%#-------------------------------------------------------------------------------------------------------------- +%postrun-command: grep "undisposed object:" test.out > test_undisposed.out || true +%not-contains: test_undisposed.out +undisposed object: ( +%#--------------------------------------------------------------------------------------------------------------