Skip to content

Commit

Permalink
IPv6: addrconf timer race
Browse files Browse the repository at this point in the history
The Router Solicitation timer races with device state changes
because it doesn't lock the device. Use local variable to avoid
one repeated dereference.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
stephen hemminger authored and David S. Miller committed Mar 4, 2010
1 parent 122e451 commit 5b2a195
Showing 1 changed file with 15 additions and 13 deletions.
28 changes: 15 additions & 13 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2739,39 +2739,41 @@ static int addrconf_ifdown(struct net_device *dev, int how)
static void addrconf_rs_timer(unsigned long data)
{
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
struct inet6_dev *idev = ifp->idev;

if (ifp->idev->cnf.forwarding)
read_lock(&idev->lock);
if (idev->dead || !(idev->if_flags & IF_READY))
goto out;

if (ifp->idev->if_flags & IF_RA_RCVD) {
/*
* Announcement received after solicitation
* was sent
*/
if (idev->cnf.forwarding)
goto out;

/* Announcement received after solicitation was sent */
if (idev->if_flags & IF_RA_RCVD)
goto out;
}

spin_lock(&ifp->lock);
if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) {
if (ifp->probes++ < idev->cnf.rtr_solicits) {
/* The wait after the last probe can be shorter */
addrconf_mod_timer(ifp, AC_RS,
(ifp->probes == ifp->idev->cnf.rtr_solicits) ?
ifp->idev->cnf.rtr_solicit_delay :
ifp->idev->cnf.rtr_solicit_interval);
(ifp->probes == idev->cnf.rtr_solicits) ?
idev->cnf.rtr_solicit_delay :
idev->cnf.rtr_solicit_interval);
spin_unlock(&ifp->lock);

ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
} else {
spin_unlock(&ifp->lock);
/*
* Note: we do not support deprecated "all on-link"
* assumption any longer.
*/
printk(KERN_DEBUG "%s: no IPv6 routers present\n",
ifp->idev->dev->name);
idev->dev->name);
}

out:
read_unlock(&idev->lock);
in6_ifa_put(ifp);
}

Expand Down

0 comments on commit 5b2a195

Please sign in to comment.