diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-09-18 03:13:46 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:19:02 -0400 |
commit | 7198f8cec12ccec6d6f2e18c08ecc8c66c8aaf93 (patch) | |
tree | f75e2cd8b76ce7a73c0160245da11cd89e30f7a1 /net/ipv6/addrconf.c | |
parent | 680a27a23af45307095ae432dd0bc859e1fbe219 (diff) |
[IPV6] address: Support NLM_F_EXCL when adding addresses
iproute2 doesn't provide the NLM_F_CREATE flag when adding addresses,
it is assumed to be implied. The existing code issues a check on
said flag when the modify operation fails (likely due to ENOENT)
before continueing to create it, this leads to a hard to predict
result, therefore the NLM_F_CREATE check is removed.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index bb18b9c3a5cb..1e5a296d0a82 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2908,24 +2908,14 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2908 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2908 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
2909 | } | 2909 | } |
2910 | 2910 | ||
2911 | static int | 2911 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 prefered_lft, |
2912 | inet6_addr_modify(int ifindex, struct in6_addr *pfx, | 2912 | u32 valid_lft) |
2913 | __u32 prefered_lft, __u32 valid_lft) | ||
2914 | { | 2913 | { |
2915 | struct inet6_ifaddr *ifp = NULL; | ||
2916 | struct net_device *dev; | ||
2917 | int ifa_flags = 0; | 2914 | int ifa_flags = 0; |
2918 | 2915 | ||
2919 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | ||
2920 | return -ENODEV; | ||
2921 | |||
2922 | if (!valid_lft || (prefered_lft > valid_lft)) | 2916 | if (!valid_lft || (prefered_lft > valid_lft)) |
2923 | return -EINVAL; | 2917 | return -EINVAL; |
2924 | 2918 | ||
2925 | ifp = ipv6_get_ifaddr(pfx, dev, 1); | ||
2926 | if (ifp == NULL) | ||
2927 | return -ENOENT; | ||
2928 | |||
2929 | if (valid_lft == INFINITY_LIFE_TIME) | 2919 | if (valid_lft == INFINITY_LIFE_TIME) |
2930 | ifa_flags = IFA_F_PERMANENT; | 2920 | ifa_flags = IFA_F_PERMANENT; |
2931 | else if (valid_lft >= 0x7FFFFFFF/HZ) | 2921 | else if (valid_lft >= 0x7FFFFFFF/HZ) |
@@ -2947,7 +2937,6 @@ inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |||
2947 | spin_unlock_bh(&ifp->lock); | 2937 | spin_unlock_bh(&ifp->lock); |
2948 | if (!(ifp->flags&IFA_F_TENTATIVE)) | 2938 | if (!(ifp->flags&IFA_F_TENTATIVE)) |
2949 | ipv6_ifa_notify(0, ifp); | 2939 | ipv6_ifa_notify(0, ifp); |
2950 | in6_ifa_put(ifp); | ||
2951 | 2940 | ||
2952 | addrconf_verify(0); | 2941 | addrconf_verify(0); |
2953 | 2942 | ||
@@ -2960,6 +2949,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2960 | struct ifaddrmsg *ifm; | 2949 | struct ifaddrmsg *ifm; |
2961 | struct nlattr *tb[IFA_MAX+1]; | 2950 | struct nlattr *tb[IFA_MAX+1]; |
2962 | struct in6_addr *pfx; | 2951 | struct in6_addr *pfx; |
2952 | struct inet6_ifaddr *ifa; | ||
2953 | struct net_device *dev; | ||
2963 | u32 valid_lft, preferred_lft; | 2954 | u32 valid_lft, preferred_lft; |
2964 | int err; | 2955 | int err; |
2965 | 2956 | ||
@@ -2983,15 +2974,29 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2983 | valid_lft = INFINITY_LIFE_TIME; | 2974 | valid_lft = INFINITY_LIFE_TIME; |
2984 | } | 2975 | } |
2985 | 2976 | ||
2986 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | 2977 | dev = __dev_get_by_index(ifm->ifa_index); |
2987 | err = inet6_addr_modify(ifm->ifa_index, pfx, | 2978 | if (dev == NULL) |
2988 | preferred_lft, valid_lft); | 2979 | return -ENODEV; |
2989 | if (err == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | 2980 | |
2990 | return err; | 2981 | ifa = ipv6_get_ifaddr(pfx, dev, 1); |
2982 | if (ifa == NULL) { | ||
2983 | /* | ||
2984 | * It would be best to check for !NLM_F_CREATE here but | ||
2985 | * userspace alreay relies on not having to provide this. | ||
2986 | */ | ||
2987 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | ||
2988 | preferred_lft, valid_lft); | ||
2991 | } | 2989 | } |
2992 | 2990 | ||
2993 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | 2991 | if (nlh->nlmsg_flags & NLM_F_EXCL || |
2994 | preferred_lft, valid_lft); | 2992 | !(nlh->nlmsg_flags & NLM_F_REPLACE)) |
2993 | err = -EEXIST; | ||
2994 | else | ||
2995 | err = inet6_addr_modify(ifa, preferred_lft, valid_lft); | ||
2996 | |||
2997 | in6_ifa_put(ifa); | ||
2998 | |||
2999 | return err; | ||
2995 | } | 3000 | } |
2996 | 3001 | ||
2997 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, | 3002 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, |