Commit 7198f8cec12ccec6d6f2e18c08ecc8c66c8aaf93
Committed by
David S. Miller
1 parent
680a27a23a
Exists in
master
and in
4 other branches
[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>
Showing 1 changed file with 25 additions and 20 deletions Side-by-side Diff
net/ipv6/addrconf.c
| ... | ... | @@ -2908,24 +2908,14 @@ |
| 2908 | 2908 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
| 2909 | 2909 | } |
| 2910 | 2910 | |
| 2911 | -static int | |
| 2912 | -inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |
| 2913 | - __u32 prefered_lft, __u32 valid_lft) | |
| 2911 | +static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 prefered_lft, | |
| 2912 | + u32 valid_lft) | |
| 2914 | 2913 | { |
| 2915 | - struct inet6_ifaddr *ifp = NULL; | |
| 2916 | - struct net_device *dev; | |
| 2917 | 2914 | int ifa_flags = 0; |
| 2918 | 2915 | |
| 2919 | - if ((dev = __dev_get_by_index(ifindex)) == NULL) | |
| 2920 | - return -ENODEV; | |
| 2921 | - | |
| 2922 | 2916 | if (!valid_lft || (prefered_lft > valid_lft)) |
| 2923 | 2917 | return -EINVAL; |
| 2924 | 2918 | |
| 2925 | - ifp = ipv6_get_ifaddr(pfx, dev, 1); | |
| 2926 | - if (ifp == NULL) | |
| 2927 | - return -ENOENT; | |
| 2928 | - | |
| 2929 | 2919 | if (valid_lft == INFINITY_LIFE_TIME) |
| 2930 | 2920 | ifa_flags = IFA_F_PERMANENT; |
| 2931 | 2921 | else if (valid_lft >= 0x7FFFFFFF/HZ) |
| ... | ... | @@ -2947,7 +2937,6 @@ |
| 2947 | 2937 | spin_unlock_bh(&ifp->lock); |
| 2948 | 2938 | if (!(ifp->flags&IFA_F_TENTATIVE)) |
| 2949 | 2939 | ipv6_ifa_notify(0, ifp); |
| 2950 | - in6_ifa_put(ifp); | |
| 2951 | 2940 | |
| 2952 | 2941 | addrconf_verify(0); |
| 2953 | 2942 | |
| ... | ... | @@ -2960,6 +2949,8 @@ |
| 2960 | 2949 | struct ifaddrmsg *ifm; |
| 2961 | 2950 | struct nlattr *tb[IFA_MAX+1]; |
| 2962 | 2951 | struct in6_addr *pfx; |
| 2952 | + struct inet6_ifaddr *ifa; | |
| 2953 | + struct net_device *dev; | |
| 2963 | 2954 | u32 valid_lft, preferred_lft; |
| 2964 | 2955 | int err; |
| 2965 | 2956 | |
| 2966 | 2957 | |
| ... | ... | @@ -2983,15 +2974,29 @@ |
| 2983 | 2974 | valid_lft = INFINITY_LIFE_TIME; |
| 2984 | 2975 | } |
| 2985 | 2976 | |
| 2986 | - if (nlh->nlmsg_flags & NLM_F_REPLACE) { | |
| 2987 | - err = inet6_addr_modify(ifm->ifa_index, pfx, | |
| 2988 | - preferred_lft, valid_lft); | |
| 2989 | - if (err == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | |
| 2990 | - return err; | |
| 2977 | + dev = __dev_get_by_index(ifm->ifa_index); | |
| 2978 | + if (dev == NULL) | |
| 2979 | + return -ENODEV; | |
| 2980 | + | |
| 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, | |
| 2994 | - preferred_lft, valid_lft); | |
| 2991 | + if (nlh->nlmsg_flags & NLM_F_EXCL || | |
| 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 | 3002 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, |