net: neigh: disallow transition to NUD_STALE if lladdr is unchanged in neigh_update()
NUD_STALE is used when the caller(e.g. arp_process()) can't guarantee neighbour reachability. If the entry was NUD_VALID and lladdr is unchanged, the entry state should not be changed. Currently the code puts an extra "NUD_CONNECTED" condition. So if old state was NUD_DELAY or NUD_PROBE (they are NUD_VALID but not NUD_CONNECTED), the state can be changed to NUD_STALE. This may cause problem. Because NUD_STALE lladdr doesn't guarantee reachability, when we send traffic, the state will be changed to NUD_DELAY. In normal case, if we get no confirmation (by dst_confirm()), we will change the state to NUD_PROBE and send probe traffic. But now the state may be reset to NUD_STALE again(e.g. by broadcast ARP packets), so the probe traffic will not be sent. This situation may happen again and again, and packets will be sent to an non-reachable lladdr forever. The fix is to remove the "NUD_CONNECTED" condition. After that the "NEIGH_UPDATE_F_WEAK_OVERRIDE" condition (used by IPv6) in that branch will be redundant, so remove it. This change may increase probe traffic, but it's essential since NUD_STALE lladdr is unreliable. To ensure correctness, we prefer to resolve lladdr, when we can't get confirmation, even while remote packets try to set NUD_STALE state. Signed-off-by: Chunhui He <hchunhui@mail.ustc.edu.cn> Signed-off-by: Julian Anastasov <ja@ssi.bg> Reviewed-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ee591f46a5
commit
d1c2b5010d
|
@ -1060,8 +1060,6 @@ static void neigh_update_hhs(struct neighbour *neigh)
|
|||
NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
|
||||
lladdr instead of overriding it
|
||||
if it is different.
|
||||
It also allows to retain current state
|
||||
if lladdr is unchanged.
|
||||
NEIGH_UPDATE_F_ADMIN means that the change is administrative.
|
||||
|
||||
NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
|
||||
|
@ -1150,10 +1148,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
|
|||
} else
|
||||
goto out;
|
||||
} else {
|
||||
if (lladdr == neigh->ha && new == NUD_STALE &&
|
||||
((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
|
||||
(old & NUD_CONNECTED))
|
||||
)
|
||||
if (lladdr == neigh->ha && new == NUD_STALE)
|
||||
new = old;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue