Commit 7198f8cec12ccec6d6f2e18c08ecc8c66c8aaf93

Authored by Thomas Graf
Committed by David S. Miller
1 parent 680a27a23a

[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

... ... @@ -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,