diff options
-rw-r--r-- | net/ipv6/addrconf.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3ef3fe20283f..8ea1e36bf8eb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2895,6 +2895,55 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2895 | } | 2895 | } |
2896 | 2896 | ||
2897 | static int | 2897 | static int |
2898 | inet6_addr_modify(int ifindex, struct in6_addr *pfx, | ||
2899 | __u32 prefered_lft, __u32 valid_lft) | ||
2900 | { | ||
2901 | struct inet6_ifaddr *ifp = NULL; | ||
2902 | struct net_device *dev; | ||
2903 | int ifa_flags = 0; | ||
2904 | |||
2905 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | ||
2906 | return -ENODEV; | ||
2907 | |||
2908 | if (!(dev->flags&IFF_UP)) | ||
2909 | return -ENETDOWN; | ||
2910 | |||
2911 | if (!valid_lft || (prefered_lft > valid_lft)) | ||
2912 | return -EINVAL; | ||
2913 | |||
2914 | ifp = ipv6_get_ifaddr(pfx, dev, 1); | ||
2915 | if (ifp == NULL) | ||
2916 | return -ENOENT; | ||
2917 | |||
2918 | if (valid_lft == INFINITY_LIFE_TIME) | ||
2919 | ifa_flags = IFA_F_PERMANENT; | ||
2920 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
2921 | valid_lft = 0x7FFFFFFF/HZ; | ||
2922 | |||
2923 | if (prefered_lft == 0) | ||
2924 | ifa_flags = IFA_F_DEPRECATED; | ||
2925 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
2926 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
2927 | prefered_lft = 0x7FFFFFFF/HZ; | ||
2928 | |||
2929 | spin_lock_bh(&ifp->lock); | ||
2930 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags; | ||
2931 | |||
2932 | ifp->tstamp = jiffies; | ||
2933 | ifp->valid_lft = valid_lft; | ||
2934 | ifp->prefered_lft = prefered_lft; | ||
2935 | |||
2936 | spin_unlock_bh(&ifp->lock); | ||
2937 | if (!(ifp->flags&IFA_F_TENTATIVE)) | ||
2938 | ipv6_ifa_notify(0, ifp); | ||
2939 | in6_ifa_put(ifp); | ||
2940 | |||
2941 | addrconf_verify(0); | ||
2942 | |||
2943 | return 0; | ||
2944 | } | ||
2945 | |||
2946 | static int | ||
2898 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2947 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2899 | { | 2948 | { |
2900 | struct rtattr **rta = arg; | 2949 | struct rtattr **rta = arg; |
@@ -2926,6 +2975,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2926 | prefered_lft = ci->ifa_prefered; | 2975 | prefered_lft = ci->ifa_prefered; |
2927 | } | 2976 | } |
2928 | 2977 | ||
2978 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | ||
2979 | int ret; | ||
2980 | ret = inet6_addr_modify(ifm->ifa_index, pfx, | ||
2981 | prefered_lft, valid_lft); | ||
2982 | if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | ||
2983 | return ret; | ||
2984 | } | ||
2985 | |||
2929 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | 2986 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, |
2930 | prefered_lft, valid_lft); | 2987 | prefered_lft, valid_lft); |
2931 | 2988 | ||