aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoriaki TAKAMIYA <takamiya@po.ntts.co.jp>2006-09-22 17:45:27 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:20:28 -0400
commit55ebaef1d5db9c1c76ba01a87fd986db5dee550d (patch)
treef06df5c635a1313ae6628d15a784076e5929c496
parentfc26d0abd5afd2b5268a7dbdbf8be1095ce5703e (diff)
[IPV6] ADDRCONF: Allow non-DAD'able addresses.
IFA_F_NODAD flag, similar to IN6_IFF_NODAD in BSDs, is introduced to skip DAD. This flag should be set to Mobile IPv6 Home Address(es) on Mobile Node because DAD would fail if we should perform DAD; our Home Agent protects our Home Address(es). Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_addr.h1
-rw-r--r--net/ipv6/addrconf.c31
2 files changed, 17 insertions, 15 deletions
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index e1590454db59..ca24b9de13fb 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -38,6 +38,7 @@ enum
38#define IFA_F_SECONDARY 0x01 38#define IFA_F_SECONDARY 0x01
39#define IFA_F_TEMPORARY IFA_F_SECONDARY 39#define IFA_F_TEMPORARY IFA_F_SECONDARY
40 40
41#define IFA_F_NODAD 0x02
41#define IFA_F_DEPRECATED 0x20 42#define IFA_F_DEPRECATED 0x20
42#define IFA_F_TENTATIVE 0x40 43#define IFA_F_TENTATIVE 0x40
43#define IFA_F_PERMANENT 0x80 44#define IFA_F_PERMANENT 0x80
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c09ebb7bb98a..adb583a26151 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1873,12 +1873,11 @@ err_exit:
1873 * Manual configuration of address on an interface 1873 * Manual configuration of address on an interface
1874 */ 1874 */
1875static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, 1875static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
1876 __u32 prefered_lft, __u32 valid_lft) 1876 __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft)
1877{ 1877{
1878 struct inet6_ifaddr *ifp; 1878 struct inet6_ifaddr *ifp;
1879 struct inet6_dev *idev; 1879 struct inet6_dev *idev;
1880 struct net_device *dev; 1880 struct net_device *dev;
1881 __u8 ifa_flags = 0;
1882 int scope; 1881 int scope;
1883 1882
1884 ASSERT_RTNL(); 1883 ASSERT_RTNL();
@@ -1971,7 +1970,7 @@ int addrconf_add_ifaddr(void __user *arg)
1971 1970
1972 rtnl_lock(); 1971 rtnl_lock();
1973 err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, 1972 err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
1974 INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); 1973 IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
1975 rtnl_unlock(); 1974 rtnl_unlock();
1976 return err; 1975 return err;
1977} 1976}
@@ -2514,7 +2513,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2514 spin_lock_bh(&ifp->lock); 2513 spin_lock_bh(&ifp->lock);
2515 2514
2516 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || 2515 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
2517 !(ifp->flags&IFA_F_TENTATIVE)) { 2516 !(ifp->flags&IFA_F_TENTATIVE) ||
2517 ifp->flags & IFA_F_NODAD) {
2518 ifp->flags &= ~IFA_F_TENTATIVE; 2518 ifp->flags &= ~IFA_F_TENTATIVE;
2519 spin_unlock_bh(&ifp->lock); 2519 spin_unlock_bh(&ifp->lock);
2520 read_unlock_bh(&idev->lock); 2520 read_unlock_bh(&idev->lock);
@@ -2912,28 +2912,25 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2912 return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); 2912 return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
2913} 2913}
2914 2914
2915static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 prefered_lft, 2915static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
2916 u32 valid_lft) 2916 u32 prefered_lft, u32 valid_lft)
2917{ 2917{
2918 int ifa_flags = 0;
2919
2920 if (!valid_lft || (prefered_lft > valid_lft)) 2918 if (!valid_lft || (prefered_lft > valid_lft))
2921 return -EINVAL; 2919 return -EINVAL;
2922 2920
2923 if (valid_lft == INFINITY_LIFE_TIME) 2921 if (valid_lft == INFINITY_LIFE_TIME)
2924 ifa_flags = IFA_F_PERMANENT; 2922 ifa_flags |= IFA_F_PERMANENT;
2925 else if (valid_lft >= 0x7FFFFFFF/HZ) 2923 else if (valid_lft >= 0x7FFFFFFF/HZ)
2926 valid_lft = 0x7FFFFFFF/HZ; 2924 valid_lft = 0x7FFFFFFF/HZ;
2927 2925
2928 if (prefered_lft == 0) 2926 if (prefered_lft == 0)
2929 ifa_flags = IFA_F_DEPRECATED; 2927 ifa_flags |= IFA_F_DEPRECATED;
2930 else if ((prefered_lft >= 0x7FFFFFFF/HZ) && 2928 else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
2931 (prefered_lft != INFINITY_LIFE_TIME)) 2929 (prefered_lft != INFINITY_LIFE_TIME))
2932 prefered_lft = 0x7FFFFFFF/HZ; 2930 prefered_lft = 0x7FFFFFFF/HZ;
2933 2931
2934 spin_lock_bh(&ifp->lock); 2932 spin_lock_bh(&ifp->lock);
2935 ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags; 2933 ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD)) | ifa_flags;
2936
2937 ifp->tstamp = jiffies; 2934 ifp->tstamp = jiffies;
2938 ifp->valid_lft = valid_lft; 2935 ifp->valid_lft = valid_lft;
2939 ifp->prefered_lft = prefered_lft; 2936 ifp->prefered_lft = prefered_lft;
@@ -2955,7 +2952,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2955 struct in6_addr *pfx; 2952 struct in6_addr *pfx;
2956 struct inet6_ifaddr *ifa; 2953 struct inet6_ifaddr *ifa;
2957 struct net_device *dev; 2954 struct net_device *dev;
2958 u32 valid_lft, preferred_lft; 2955 u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
2956 u8 ifa_flags;
2959 int err; 2957 int err;
2960 2958
2961 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); 2959 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
@@ -2982,6 +2980,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2982 if (dev == NULL) 2980 if (dev == NULL)
2983 return -ENODEV; 2981 return -ENODEV;
2984 2982
2983 /* We ignore other flags so far. */
2984 ifa_flags = ifm->ifa_flags & IFA_F_NODAD;
2985
2985 ifa = ipv6_get_ifaddr(pfx, dev, 1); 2986 ifa = ipv6_get_ifaddr(pfx, dev, 1);
2986 if (ifa == NULL) { 2987 if (ifa == NULL) {
2987 /* 2988 /*
@@ -2989,14 +2990,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2989 * userspace alreay relies on not having to provide this. 2990 * userspace alreay relies on not having to provide this.
2990 */ 2991 */
2991 return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, 2992 return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
2992 preferred_lft, valid_lft); 2993 ifa_flags, preferred_lft, valid_lft);
2993 } 2994 }
2994 2995
2995 if (nlh->nlmsg_flags & NLM_F_EXCL || 2996 if (nlh->nlmsg_flags & NLM_F_EXCL ||
2996 !(nlh->nlmsg_flags & NLM_F_REPLACE)) 2997 !(nlh->nlmsg_flags & NLM_F_REPLACE))
2997 err = -EEXIST; 2998 err = -EEXIST;
2998 else 2999 else
2999 err = inet6_addr_modify(ifa, preferred_lft, valid_lft); 3000 err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft);
3000 3001
3001 in6_ifa_put(ifa); 3002 in6_ifa_put(ifa);
3002 3003