diff options
author | Noriaki TAKAMIYA <takamiya@po.ntts.co.jp> | 2006-09-22 17:45:27 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:20:28 -0400 |
commit | 55ebaef1d5db9c1c76ba01a87fd986db5dee550d (patch) | |
tree | f06df5c635a1313ae6628d15a784076e5929c496 | |
parent | fc26d0abd5afd2b5268a7dbdbf8be1095ce5703e (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.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 31 |
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 | */ |
1875 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | 1875 | static 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 | ||
2915 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 prefered_lft, | 2915 | static 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 | ||