Commit c9d55d5b authored by Paul Marks's avatar Paul Marks Committed by David S. Miller

ipv6: Fix preferred_lft not updating in some cases

Consider the scenario where an IPv6 router is advertising a fixed
preferred_lft of 1800 seconds, while the valid_lft begins at 3600
seconds and counts down in realtime.

A client should reset its preferred_lft to 1800 every time the RA is
received, but a bug is causing Linux to ignore the update.

The core problem is here:
  if (prefered_lft != ifp->prefered_lft) {

Note that ifp->prefered_lft is an offset, so it doesn't decrease over
time.  Thus, the comparison is always (1800 != 1800), which fails to
trigger an update.

The most direct solution would be to compute a "stored_prefered_lft",
and use that value in the comparison.  But I think that trying to filter
out unnecessary updates here is a premature optimization.  In order for
the filter to apply, both of these would need to hold:

  - The advertised valid_lft and preferred_lft are both declining in
    real time.
  - No clock skew exists between the router & client.

So in this patch, I've set "update_lft = 1" unconditionally, which
allows the surrounding code to be greatly simplified.
Signed-off-by: default avatarPaul Marks <pmarks@google.com>
Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d4a71b15
...@@ -2220,44 +2220,22 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) ...@@ -2220,44 +2220,22 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
else else
stored_lft = 0; stored_lft = 0;
if (!update_lft && !create && stored_lft) { if (!update_lft && !create && stored_lft) {
if (valid_lft > MIN_VALID_LIFETIME || const u32 minimum_lft = min(
valid_lft > stored_lft) stored_lft, (u32)MIN_VALID_LIFETIME);
update_lft = 1; valid_lft = max(valid_lft, minimum_lft);
else if (stored_lft <= MIN_VALID_LIFETIME) {
/* valid_lft <= stored_lft is always true */ /* RFC4862 Section 5.5.3e:
/* * "Note that the preferred lifetime of the
* RFC 4862 Section 5.5.3e: * corresponding address is always reset to
* "Note that the preferred lifetime of * the Preferred Lifetime in the received
* the corresponding address is always * Prefix Information option, regardless of
* reset to the Preferred Lifetime in * whether the valid lifetime is also reset or
* the received Prefix Information
* option, regardless of whether the
* valid lifetime is also reset or
* ignored." * ignored."
* *
* So if the preferred lifetime in * So we should always update prefered_lft here.
* this advertisement is different
* than what we have stored, but the
* valid lifetime is invalid, just
* reset prefered_lft.
*
* We must set the valid lifetime
* to the stored lifetime since we'll
* be updating the timestamp below,
* else we'll set it back to the
* minimum.
*/ */
if (prefered_lft != ifp->prefered_lft) {
valid_lft = stored_lft;
update_lft = 1; update_lft = 1;
} }
} else {
valid_lft = MIN_VALID_LIFETIME;
if (valid_lft < prefered_lft)
prefered_lft = valid_lft;
update_lft = 1;
}
}
if (update_lft) { if (update_lft) {
ifp->valid_lft = valid_lft; ifp->valid_lft = valid_lft;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment