aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c102
1 files changed, 62 insertions, 40 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 88fd8c5877ee..6cf3ee14ace3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2615,7 +2615,7 @@ static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
2615static int addrconf_ifdown(struct net_device *dev, int how) 2615static int addrconf_ifdown(struct net_device *dev, int how)
2616{ 2616{
2617 struct inet6_dev *idev; 2617 struct inet6_dev *idev;
2618 struct inet6_ifaddr *ifa, **bifa; 2618 struct inet6_ifaddr *ifa, *keep_list, **bifa;
2619 struct net *net = dev_net(dev); 2619 struct net *net = dev_net(dev);
2620 int i; 2620 int i;
2621 2621
@@ -2649,11 +2649,11 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2649 write_lock_bh(&addrconf_hash_lock); 2649 write_lock_bh(&addrconf_hash_lock);
2650 while ((ifa = *bifa) != NULL) { 2650 while ((ifa = *bifa) != NULL) {
2651 if (ifa->idev == idev && 2651 if (ifa->idev == idev &&
2652 (how || !(ifa->flags&IFA_F_PERMANENT))) { 2652 (how || !(ifa->flags&IFA_F_PERMANENT) ||
2653 ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2653 *bifa = ifa->lst_next; 2654 *bifa = ifa->lst_next;
2654 ifa->lst_next = NULL; 2655 ifa->lst_next = NULL;
2655 addrconf_del_timer(ifa); 2656 __in6_ifa_put(ifa);
2656 in6_ifa_put(ifa);
2657 continue; 2657 continue;
2658 } 2658 }
2659 bifa = &ifa->lst_next; 2659 bifa = &ifa->lst_next;
@@ -2689,31 +2689,51 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2689 write_lock_bh(&idev->lock); 2689 write_lock_bh(&idev->lock);
2690 } 2690 }
2691#endif 2691#endif
2692 bifa = &idev->addr_list; 2692 keep_list = NULL;
2693 while ((ifa = *bifa) != NULL) { 2693 bifa = &keep_list;
2694 if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { 2694 while ((ifa = idev->addr_list) != NULL) {
2695 /* Retain permanent address on admin down */ 2695 idev->addr_list = ifa->if_next;
2696 ifa->if_next = NULL;
2697
2698 addrconf_del_timer(ifa);
2699
2700 /* If just doing link down, and address is permanent
2701 and not link-local, then retain it. */
2702 if (how == 0 &&
2703 (ifa->flags&IFA_F_PERMANENT) &&
2704 !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2705
2706 /* Move to holding list */
2707 *bifa = ifa;
2696 bifa = &ifa->if_next; 2708 bifa = &ifa->if_next;
2697 2709
2698 /* Restart DAD if needed when link comes back up */ 2710 /* If not doing DAD on this address, just keep it. */
2699 if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || 2711 if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2700 idev->cnf.accept_dad <= 0 || 2712 idev->cnf.accept_dad <= 0 ||
2701 (ifa->flags & IFA_F_NODAD))) 2713 (ifa->flags & IFA_F_NODAD))
2702 ifa->flags |= IFA_F_TENTATIVE; 2714 continue;
2703 } else {
2704 *bifa = ifa->if_next;
2705 ifa->if_next = NULL;
2706 2715
2716 /* If it was tentative already, no need to notify */
2717 if (ifa->flags & IFA_F_TENTATIVE)
2718 continue;
2719
2720 /* Flag it for later restoration when link comes up */
2721 ifa->flags |= IFA_F_TENTATIVE;
2722 in6_ifa_hold(ifa);
2723 } else {
2707 ifa->dead = 1; 2724 ifa->dead = 1;
2708 write_unlock_bh(&idev->lock); 2725 }
2726 write_unlock_bh(&idev->lock);
2709 2727
2710 __ipv6_ifa_notify(RTM_DELADDR, ifa); 2728 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2711 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); 2729 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2712 in6_ifa_put(ifa); 2730 in6_ifa_put(ifa);
2713 2731
2714 write_lock_bh(&idev->lock); 2732 write_lock_bh(&idev->lock);
2715 }
2716 } 2733 }
2734
2735 idev->addr_list = keep_list;
2736
2717 write_unlock_bh(&idev->lock); 2737 write_unlock_bh(&idev->lock);
2718 2738
2719 /* Step 5: Discard multicast list */ 2739 /* Step 5: Discard multicast list */
@@ -2739,28 +2759,29 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2739static void addrconf_rs_timer(unsigned long data) 2759static void addrconf_rs_timer(unsigned long data)
2740{ 2760{
2741 struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; 2761 struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
2762 struct inet6_dev *idev = ifp->idev;
2742 2763
2743 if (ifp->idev->cnf.forwarding) 2764 read_lock(&idev->lock);
2765 if (idev->dead || !(idev->if_flags & IF_READY))
2744 goto out; 2766 goto out;
2745 2767
2746 if (ifp->idev->if_flags & IF_RA_RCVD) { 2768 if (idev->cnf.forwarding)
2747 /* 2769 goto out;
2748 * Announcement received after solicitation 2770
2749 * was sent 2771 /* Announcement received after solicitation was sent */
2750 */ 2772 if (idev->if_flags & IF_RA_RCVD)
2751 goto out; 2773 goto out;
2752 }
2753 2774
2754 spin_lock(&ifp->lock); 2775 spin_lock(&ifp->lock);
2755 if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { 2776 if (ifp->probes++ < idev->cnf.rtr_solicits) {
2756 /* The wait after the last probe can be shorter */ 2777 /* The wait after the last probe can be shorter */
2757 addrconf_mod_timer(ifp, AC_RS, 2778 addrconf_mod_timer(ifp, AC_RS,
2758 (ifp->probes == ifp->idev->cnf.rtr_solicits) ? 2779 (ifp->probes == idev->cnf.rtr_solicits) ?
2759 ifp->idev->cnf.rtr_solicit_delay : 2780 idev->cnf.rtr_solicit_delay :
2760 ifp->idev->cnf.rtr_solicit_interval); 2781 idev->cnf.rtr_solicit_interval);
2761 spin_unlock(&ifp->lock); 2782 spin_unlock(&ifp->lock);
2762 2783
2763 ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); 2784 ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
2764 } else { 2785 } else {
2765 spin_unlock(&ifp->lock); 2786 spin_unlock(&ifp->lock);
2766 /* 2787 /*
@@ -2768,10 +2789,11 @@ static void addrconf_rs_timer(unsigned long data)
2768 * assumption any longer. 2789 * assumption any longer.
2769 */ 2790 */
2770 printk(KERN_DEBUG "%s: no IPv6 routers present\n", 2791 printk(KERN_DEBUG "%s: no IPv6 routers present\n",
2771 ifp->idev->dev->name); 2792 idev->dev->name);
2772 } 2793 }
2773 2794
2774out: 2795out:
2796 read_unlock(&idev->lock);
2775 in6_ifa_put(ifp); 2797 in6_ifa_put(ifp);
2776} 2798}
2777 2799
@@ -2850,9 +2872,9 @@ static void addrconf_dad_timer(unsigned long data)
2850 struct inet6_dev *idev = ifp->idev; 2872 struct inet6_dev *idev = ifp->idev;
2851 struct in6_addr mcaddr; 2873 struct in6_addr mcaddr;
2852 2874
2853 read_lock_bh(&idev->lock); 2875 read_lock(&idev->lock);
2854 if (idev->dead) { 2876 if (idev->dead || !(idev->if_flags & IF_READY)) {
2855 read_unlock_bh(&idev->lock); 2877 read_unlock(&idev->lock);
2856 goto out; 2878 goto out;
2857 } 2879 }
2858 2880
@@ -2864,7 +2886,7 @@ static void addrconf_dad_timer(unsigned long data)
2864 2886
2865 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); 2887 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
2866 spin_unlock(&ifp->lock); 2888 spin_unlock(&ifp->lock);
2867 read_unlock_bh(&idev->lock); 2889 read_unlock(&idev->lock);
2868 2890
2869 addrconf_dad_completed(ifp); 2891 addrconf_dad_completed(ifp);
2870 2892
@@ -2874,7 +2896,7 @@ static void addrconf_dad_timer(unsigned long data)
2874 ifp->probes--; 2896 ifp->probes--;
2875 addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); 2897 addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
2876 spin_unlock(&ifp->lock); 2898 spin_unlock(&ifp->lock);
2877 read_unlock_bh(&idev->lock); 2899 read_unlock(&idev->lock);
2878 2900
2879 /* send a neighbour solicitation for our addr */ 2901 /* send a neighbour solicitation for our addr */
2880 addrconf_addr_solict_mult(&ifp->addr, &mcaddr); 2902 addrconf_addr_solict_mult(&ifp->addr, &mcaddr);