diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 273 |
1 files changed, 178 insertions, 95 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 12c97d8aa6bb..9418ca375132 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -442,6 +442,8 @@ static int inet6_netconf_msgsize_devconf(int type) | |||
442 | if (type == -1 || type == NETCONFA_MC_FORWARDING) | 442 | if (type == -1 || type == NETCONFA_MC_FORWARDING) |
443 | size += nla_total_size(4); | 443 | size += nla_total_size(4); |
444 | #endif | 444 | #endif |
445 | if (type == -1 || type == NETCONFA_PROXY_NEIGH) | ||
446 | size += nla_total_size(4); | ||
445 | 447 | ||
446 | return size; | 448 | return size; |
447 | } | 449 | } |
@@ -475,6 +477,10 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | |||
475 | devconf->mc_forwarding) < 0) | 477 | devconf->mc_forwarding) < 0) |
476 | goto nla_put_failure; | 478 | goto nla_put_failure; |
477 | #endif | 479 | #endif |
480 | if ((type == -1 || type == NETCONFA_PROXY_NEIGH) && | ||
481 | nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) | ||
482 | goto nla_put_failure; | ||
483 | |||
478 | return nlmsg_end(skb, nlh); | 484 | return nlmsg_end(skb, nlh); |
479 | 485 | ||
480 | nla_put_failure: | 486 | nla_put_failure: |
@@ -509,6 +515,7 @@ errout: | |||
509 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | 515 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { |
510 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | 516 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, |
511 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | 517 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, |
518 | [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, | ||
512 | }; | 519 | }; |
513 | 520 | ||
514 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | 521 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, |
@@ -834,6 +841,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
834 | goto out; | 841 | goto out; |
835 | } | 842 | } |
836 | 843 | ||
844 | neigh_parms_data_state_setall(idev->nd_parms); | ||
845 | |||
837 | ifa->addr = *addr; | 846 | ifa->addr = *addr; |
838 | if (peer_addr) | 847 | if (peer_addr) |
839 | ifa->peer_addr = *peer_addr; | 848 | ifa->peer_addr = *peer_addr; |
@@ -986,12 +995,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
986 | * --yoshfuji | 995 | * --yoshfuji |
987 | */ | 996 | */ |
988 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { | 997 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { |
989 | struct in6_addr prefix; | ||
990 | struct rt6_info *rt; | 998 | struct rt6_info *rt; |
991 | 999 | ||
992 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); | 1000 | rt = addrconf_get_prefix_route(&ifp->addr, |
993 | |||
994 | rt = addrconf_get_prefix_route(&prefix, | ||
995 | ifp->prefix_len, | 1001 | ifp->prefix_len, |
996 | ifp->idev->dev, | 1002 | ifp->idev->dev, |
997 | 0, RTF_GATEWAY | RTF_DEFAULT); | 1003 | 0, RTF_GATEWAY | RTF_DEFAULT); |
@@ -1024,7 +1030,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
1024 | u32 addr_flags; | 1030 | u32 addr_flags; |
1025 | unsigned long now = jiffies; | 1031 | unsigned long now = jiffies; |
1026 | 1032 | ||
1027 | write_lock(&idev->lock); | 1033 | write_lock_bh(&idev->lock); |
1028 | if (ift) { | 1034 | if (ift) { |
1029 | spin_lock_bh(&ift->lock); | 1035 | spin_lock_bh(&ift->lock); |
1030 | memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); | 1036 | memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); |
@@ -1036,7 +1042,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
1036 | retry: | 1042 | retry: |
1037 | in6_dev_hold(idev); | 1043 | in6_dev_hold(idev); |
1038 | if (idev->cnf.use_tempaddr <= 0) { | 1044 | if (idev->cnf.use_tempaddr <= 0) { |
1039 | write_unlock(&idev->lock); | 1045 | write_unlock_bh(&idev->lock); |
1040 | pr_info("%s: use_tempaddr is disabled\n", __func__); | 1046 | pr_info("%s: use_tempaddr is disabled\n", __func__); |
1041 | in6_dev_put(idev); | 1047 | in6_dev_put(idev); |
1042 | ret = -1; | 1048 | ret = -1; |
@@ -1046,7 +1052,7 @@ retry: | |||
1046 | if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { | 1052 | if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { |
1047 | idev->cnf.use_tempaddr = -1; /*XXX*/ | 1053 | idev->cnf.use_tempaddr = -1; /*XXX*/ |
1048 | spin_unlock_bh(&ifp->lock); | 1054 | spin_unlock_bh(&ifp->lock); |
1049 | write_unlock(&idev->lock); | 1055 | write_unlock_bh(&idev->lock); |
1050 | pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", | 1056 | pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", |
1051 | __func__); | 1057 | __func__); |
1052 | in6_dev_put(idev); | 1058 | in6_dev_put(idev); |
@@ -1071,8 +1077,8 @@ retry: | |||
1071 | 1077 | ||
1072 | regen_advance = idev->cnf.regen_max_retry * | 1078 | regen_advance = idev->cnf.regen_max_retry * |
1073 | idev->cnf.dad_transmits * | 1079 | idev->cnf.dad_transmits * |
1074 | idev->nd_parms->retrans_time / HZ; | 1080 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; |
1075 | write_unlock(&idev->lock); | 1081 | write_unlock_bh(&idev->lock); |
1076 | 1082 | ||
1077 | /* A temporary address is created only if this calculated Preferred | 1083 | /* A temporary address is created only if this calculated Preferred |
1078 | * Lifetime is greater than REGEN_ADVANCE time units. In particular, | 1084 | * Lifetime is greater than REGEN_ADVANCE time units. In particular, |
@@ -1099,7 +1105,7 @@ retry: | |||
1099 | in6_dev_put(idev); | 1105 | in6_dev_put(idev); |
1100 | pr_info("%s: retry temporary address regeneration\n", __func__); | 1106 | pr_info("%s: retry temporary address regeneration\n", __func__); |
1101 | tmpaddr = &addr; | 1107 | tmpaddr = &addr; |
1102 | write_lock(&idev->lock); | 1108 | write_lock_bh(&idev->lock); |
1103 | goto retry; | 1109 | goto retry; |
1104 | } | 1110 | } |
1105 | 1111 | ||
@@ -1407,7 +1413,7 @@ try_nextdev: | |||
1407 | EXPORT_SYMBOL(ipv6_dev_get_saddr); | 1413 | EXPORT_SYMBOL(ipv6_dev_get_saddr); |
1408 | 1414 | ||
1409 | int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, | 1415 | int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, |
1410 | unsigned char banned_flags) | 1416 | u32 banned_flags) |
1411 | { | 1417 | { |
1412 | struct inet6_ifaddr *ifp; | 1418 | struct inet6_ifaddr *ifp; |
1413 | int err = -EADDRNOTAVAIL; | 1419 | int err = -EADDRNOTAVAIL; |
@@ -1424,7 +1430,7 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, | |||
1424 | } | 1430 | } |
1425 | 1431 | ||
1426 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, | 1432 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, |
1427 | unsigned char banned_flags) | 1433 | u32 banned_flags) |
1428 | { | 1434 | { |
1429 | struct inet6_dev *idev; | 1435 | struct inet6_dev *idev; |
1430 | int err = -EADDRNOTAVAIL; | 1436 | int err = -EADDRNOTAVAIL; |
@@ -1888,7 +1894,8 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1888 | 1894 | ||
1889 | expires = jiffies + | 1895 | expires = jiffies + |
1890 | idev->cnf.temp_prefered_lft * HZ - | 1896 | idev->cnf.temp_prefered_lft * HZ - |
1891 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - | 1897 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * |
1898 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) - | ||
1892 | idev->cnf.max_desync_factor * HZ; | 1899 | idev->cnf.max_desync_factor * HZ; |
1893 | if (time_before(expires, jiffies)) { | 1900 | if (time_before(expires, jiffies)) { |
1894 | pr_warn("%s: too short regeneration interval; timer disabled for %s\n", | 1901 | pr_warn("%s: too short regeneration interval; timer disabled for %s\n", |
@@ -2016,6 +2023,73 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) | |||
2016 | return idev; | 2023 | return idev; |
2017 | } | 2024 | } |
2018 | 2025 | ||
2026 | static void manage_tempaddrs(struct inet6_dev *idev, | ||
2027 | struct inet6_ifaddr *ifp, | ||
2028 | __u32 valid_lft, __u32 prefered_lft, | ||
2029 | bool create, unsigned long now) | ||
2030 | { | ||
2031 | u32 flags; | ||
2032 | struct inet6_ifaddr *ift; | ||
2033 | |||
2034 | read_lock_bh(&idev->lock); | ||
2035 | /* update all temporary addresses in the list */ | ||
2036 | list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) { | ||
2037 | int age, max_valid, max_prefered; | ||
2038 | |||
2039 | if (ifp != ift->ifpub) | ||
2040 | continue; | ||
2041 | |||
2042 | /* RFC 4941 section 3.3: | ||
2043 | * If a received option will extend the lifetime of a public | ||
2044 | * address, the lifetimes of temporary addresses should | ||
2045 | * be extended, subject to the overall constraint that no | ||
2046 | * temporary addresses should ever remain "valid" or "preferred" | ||
2047 | * for a time longer than (TEMP_VALID_LIFETIME) or | ||
2048 | * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. | ||
2049 | */ | ||
2050 | age = (now - ift->cstamp) / HZ; | ||
2051 | max_valid = idev->cnf.temp_valid_lft - age; | ||
2052 | if (max_valid < 0) | ||
2053 | max_valid = 0; | ||
2054 | |||
2055 | max_prefered = idev->cnf.temp_prefered_lft - | ||
2056 | idev->cnf.max_desync_factor - age; | ||
2057 | if (max_prefered < 0) | ||
2058 | max_prefered = 0; | ||
2059 | |||
2060 | if (valid_lft > max_valid) | ||
2061 | valid_lft = max_valid; | ||
2062 | |||
2063 | if (prefered_lft > max_prefered) | ||
2064 | prefered_lft = max_prefered; | ||
2065 | |||
2066 | spin_lock(&ift->lock); | ||
2067 | flags = ift->flags; | ||
2068 | ift->valid_lft = valid_lft; | ||
2069 | ift->prefered_lft = prefered_lft; | ||
2070 | ift->tstamp = now; | ||
2071 | if (prefered_lft > 0) | ||
2072 | ift->flags &= ~IFA_F_DEPRECATED; | ||
2073 | |||
2074 | spin_unlock(&ift->lock); | ||
2075 | if (!(flags&IFA_F_TENTATIVE)) | ||
2076 | ipv6_ifa_notify(0, ift); | ||
2077 | } | ||
2078 | |||
2079 | if ((create || list_empty(&idev->tempaddr_list)) && | ||
2080 | idev->cnf.use_tempaddr > 0) { | ||
2081 | /* When a new public address is created as described | ||
2082 | * in [ADDRCONF], also create a new temporary address. | ||
2083 | * Also create a temporary address if it's enabled but | ||
2084 | * no temporary address currently exists. | ||
2085 | */ | ||
2086 | read_unlock_bh(&idev->lock); | ||
2087 | ipv6_create_tempaddr(ifp, NULL); | ||
2088 | } else { | ||
2089 | read_unlock_bh(&idev->lock); | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2019 | void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | 2093 | void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) |
2020 | { | 2094 | { |
2021 | struct prefix_info *pinfo; | 2095 | struct prefix_info *pinfo; |
@@ -2170,6 +2244,7 @@ ok: | |||
2170 | return; | 2244 | return; |
2171 | } | 2245 | } |
2172 | 2246 | ||
2247 | ifp->flags |= IFA_F_MANAGETEMPADDR; | ||
2173 | update_lft = 0; | 2248 | update_lft = 0; |
2174 | create = 1; | 2249 | create = 1; |
2175 | ifp->cstamp = jiffies; | 2250 | ifp->cstamp = jiffies; |
@@ -2178,9 +2253,8 @@ ok: | |||
2178 | } | 2253 | } |
2179 | 2254 | ||
2180 | if (ifp) { | 2255 | if (ifp) { |
2181 | int flags; | 2256 | u32 flags; |
2182 | unsigned long now; | 2257 | unsigned long now; |
2183 | struct inet6_ifaddr *ift; | ||
2184 | u32 stored_lft; | 2258 | u32 stored_lft; |
2185 | 2259 | ||
2186 | /* update lifetime (RFC2462 5.5.3 e) */ | 2260 | /* update lifetime (RFC2462 5.5.3 e) */ |
@@ -2221,70 +2295,8 @@ ok: | |||
2221 | } else | 2295 | } else |
2222 | spin_unlock(&ifp->lock); | 2296 | spin_unlock(&ifp->lock); |
2223 | 2297 | ||
2224 | read_lock_bh(&in6_dev->lock); | 2298 | manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, |
2225 | /* update all temporary addresses in the list */ | 2299 | create, now); |
2226 | list_for_each_entry(ift, &in6_dev->tempaddr_list, | ||
2227 | tmp_list) { | ||
2228 | int age, max_valid, max_prefered; | ||
2229 | |||
2230 | if (ifp != ift->ifpub) | ||
2231 | continue; | ||
2232 | |||
2233 | /* | ||
2234 | * RFC 4941 section 3.3: | ||
2235 | * If a received option will extend the lifetime | ||
2236 | * of a public address, the lifetimes of | ||
2237 | * temporary addresses should be extended, | ||
2238 | * subject to the overall constraint that no | ||
2239 | * temporary addresses should ever remain | ||
2240 | * "valid" or "preferred" for a time longer than | ||
2241 | * (TEMP_VALID_LIFETIME) or | ||
2242 | * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), | ||
2243 | * respectively. | ||
2244 | */ | ||
2245 | age = (now - ift->cstamp) / HZ; | ||
2246 | max_valid = in6_dev->cnf.temp_valid_lft - age; | ||
2247 | if (max_valid < 0) | ||
2248 | max_valid = 0; | ||
2249 | |||
2250 | max_prefered = in6_dev->cnf.temp_prefered_lft - | ||
2251 | in6_dev->cnf.max_desync_factor - | ||
2252 | age; | ||
2253 | if (max_prefered < 0) | ||
2254 | max_prefered = 0; | ||
2255 | |||
2256 | if (valid_lft > max_valid) | ||
2257 | valid_lft = max_valid; | ||
2258 | |||
2259 | if (prefered_lft > max_prefered) | ||
2260 | prefered_lft = max_prefered; | ||
2261 | |||
2262 | spin_lock(&ift->lock); | ||
2263 | flags = ift->flags; | ||
2264 | ift->valid_lft = valid_lft; | ||
2265 | ift->prefered_lft = prefered_lft; | ||
2266 | ift->tstamp = now; | ||
2267 | if (prefered_lft > 0) | ||
2268 | ift->flags &= ~IFA_F_DEPRECATED; | ||
2269 | |||
2270 | spin_unlock(&ift->lock); | ||
2271 | if (!(flags&IFA_F_TENTATIVE)) | ||
2272 | ipv6_ifa_notify(0, ift); | ||
2273 | } | ||
2274 | |||
2275 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { | ||
2276 | /* | ||
2277 | * When a new public address is created as | ||
2278 | * described in [ADDRCONF], also create a new | ||
2279 | * temporary address. Also create a temporary | ||
2280 | * address if it's enabled but no temporary | ||
2281 | * address currently exists. | ||
2282 | */ | ||
2283 | read_unlock_bh(&in6_dev->lock); | ||
2284 | ipv6_create_tempaddr(ifp, NULL); | ||
2285 | } else { | ||
2286 | read_unlock_bh(&in6_dev->lock); | ||
2287 | } | ||
2288 | 2300 | ||
2289 | in6_ifa_put(ifp); | 2301 | in6_ifa_put(ifp); |
2290 | addrconf_verify(0); | 2302 | addrconf_verify(0); |
@@ -2363,10 +2375,11 @@ err_exit: | |||
2363 | /* | 2375 | /* |
2364 | * Manual configuration of address on an interface | 2376 | * Manual configuration of address on an interface |
2365 | */ | 2377 | */ |
2366 | static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, | 2378 | static int inet6_addr_add(struct net *net, int ifindex, |
2379 | const struct in6_addr *pfx, | ||
2367 | const struct in6_addr *peer_pfx, | 2380 | const struct in6_addr *peer_pfx, |
2368 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, | 2381 | unsigned int plen, __u32 ifa_flags, |
2369 | __u32 valid_lft) | 2382 | __u32 prefered_lft, __u32 valid_lft) |
2370 | { | 2383 | { |
2371 | struct inet6_ifaddr *ifp; | 2384 | struct inet6_ifaddr *ifp; |
2372 | struct inet6_dev *idev; | 2385 | struct inet6_dev *idev; |
@@ -2385,6 +2398,9 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p | |||
2385 | if (!valid_lft || prefered_lft > valid_lft) | 2398 | if (!valid_lft || prefered_lft > valid_lft) |
2386 | return -EINVAL; | 2399 | return -EINVAL; |
2387 | 2400 | ||
2401 | if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64) | ||
2402 | return -EINVAL; | ||
2403 | |||
2388 | dev = __dev_get_by_index(net, ifindex); | 2404 | dev = __dev_get_by_index(net, ifindex); |
2389 | if (!dev) | 2405 | if (!dev) |
2390 | return -ENODEV; | 2406 | return -ENODEV; |
@@ -2425,6 +2441,9 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p | |||
2425 | * manually configured addresses | 2441 | * manually configured addresses |
2426 | */ | 2442 | */ |
2427 | addrconf_dad_start(ifp); | 2443 | addrconf_dad_start(ifp); |
2444 | if (ifa_flags & IFA_F_MANAGETEMPADDR) | ||
2445 | manage_tempaddrs(idev, ifp, valid_lft, prefered_lft, | ||
2446 | true, jiffies); | ||
2428 | in6_ifa_put(ifp); | 2447 | in6_ifa_put(ifp); |
2429 | addrconf_verify(0); | 2448 | addrconf_verify(0); |
2430 | return 0; | 2449 | return 0; |
@@ -2613,7 +2632,7 @@ static void init_loopback(struct net_device *dev) | |||
2613 | if (sp_ifa->rt) | 2632 | if (sp_ifa->rt) |
2614 | continue; | 2633 | continue; |
2615 | 2634 | ||
2616 | sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0); | 2635 | sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); |
2617 | 2636 | ||
2618 | /* Failure cases are ignored */ | 2637 | /* Failure cases are ignored */ |
2619 | if (!IS_ERR(sp_rt)) { | 2638 | if (!IS_ERR(sp_rt)) { |
@@ -3176,7 +3195,8 @@ static void addrconf_dad_timer(unsigned long data) | |||
3176 | } | 3195 | } |
3177 | 3196 | ||
3178 | ifp->dad_probes--; | 3197 | ifp->dad_probes--; |
3179 | addrconf_mod_dad_timer(ifp, ifp->idev->nd_parms->retrans_time); | 3198 | addrconf_mod_dad_timer(ifp, |
3199 | NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); | ||
3180 | spin_unlock(&ifp->lock); | 3200 | spin_unlock(&ifp->lock); |
3181 | write_unlock(&idev->lock); | 3201 | write_unlock(&idev->lock); |
3182 | 3202 | ||
@@ -3356,7 +3376,7 @@ static int if6_seq_show(struct seq_file *seq, void *v) | |||
3356 | ifp->idev->dev->ifindex, | 3376 | ifp->idev->dev->ifindex, |
3357 | ifp->prefix_len, | 3377 | ifp->prefix_len, |
3358 | ifp->scope, | 3378 | ifp->scope, |
3359 | ifp->flags, | 3379 | (u8) ifp->flags, |
3360 | ifp->idev->dev->name); | 3380 | ifp->idev->dev->name); |
3361 | return 0; | 3381 | return 0; |
3362 | } | 3382 | } |
@@ -3497,7 +3517,7 @@ restart: | |||
3497 | !(ifp->flags&IFA_F_TENTATIVE)) { | 3517 | !(ifp->flags&IFA_F_TENTATIVE)) { |
3498 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * | 3518 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * |
3499 | ifp->idev->cnf.dad_transmits * | 3519 | ifp->idev->cnf.dad_transmits * |
3500 | ifp->idev->nd_parms->retrans_time / HZ; | 3520 | NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ; |
3501 | 3521 | ||
3502 | if (age >= ifp->prefered_lft - regen_advance) { | 3522 | if (age >= ifp->prefered_lft - regen_advance) { |
3503 | struct inet6_ifaddr *ifpub = ifp->ifpub; | 3523 | struct inet6_ifaddr *ifpub = ifp->ifpub; |
@@ -3572,6 +3592,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { | |||
3572 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, | 3592 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, |
3573 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, | 3593 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, |
3574 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, | 3594 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, |
3595 | [IFA_FLAGS] = { .len = sizeof(u32) }, | ||
3575 | }; | 3596 | }; |
3576 | 3597 | ||
3577 | static int | 3598 | static int |
@@ -3595,16 +3616,21 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
3595 | return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 3616 | return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
3596 | } | 3617 | } |
3597 | 3618 | ||
3598 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | 3619 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, |
3599 | u32 prefered_lft, u32 valid_lft) | 3620 | u32 prefered_lft, u32 valid_lft) |
3600 | { | 3621 | { |
3601 | u32 flags; | 3622 | u32 flags; |
3602 | clock_t expires; | 3623 | clock_t expires; |
3603 | unsigned long timeout; | 3624 | unsigned long timeout; |
3625 | bool was_managetempaddr; | ||
3604 | 3626 | ||
3605 | if (!valid_lft || (prefered_lft > valid_lft)) | 3627 | if (!valid_lft || (prefered_lft > valid_lft)) |
3606 | return -EINVAL; | 3628 | return -EINVAL; |
3607 | 3629 | ||
3630 | if (ifa_flags & IFA_F_MANAGETEMPADDR && | ||
3631 | (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64)) | ||
3632 | return -EINVAL; | ||
3633 | |||
3608 | timeout = addrconf_timeout_fixup(valid_lft, HZ); | 3634 | timeout = addrconf_timeout_fixup(valid_lft, HZ); |
3609 | if (addrconf_finite_timeout(timeout)) { | 3635 | if (addrconf_finite_timeout(timeout)) { |
3610 | expires = jiffies_to_clock_t(timeout * HZ); | 3636 | expires = jiffies_to_clock_t(timeout * HZ); |
@@ -3624,7 +3650,10 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3624 | } | 3650 | } |
3625 | 3651 | ||
3626 | spin_lock_bh(&ifp->lock); | 3652 | spin_lock_bh(&ifp->lock); |
3627 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; | 3653 | was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; |
3654 | ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | | ||
3655 | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR); | ||
3656 | ifp->flags |= ifa_flags; | ||
3628 | ifp->tstamp = jiffies; | 3657 | ifp->tstamp = jiffies; |
3629 | ifp->valid_lft = valid_lft; | 3658 | ifp->valid_lft = valid_lft; |
3630 | ifp->prefered_lft = prefered_lft; | 3659 | ifp->prefered_lft = prefered_lft; |
@@ -3635,6 +3664,14 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | |||
3635 | 3664 | ||
3636 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, | 3665 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, |
3637 | expires, flags); | 3666 | expires, flags); |
3667 | |||
3668 | if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) { | ||
3669 | if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR)) | ||
3670 | valid_lft = prefered_lft = 0; | ||
3671 | manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft, | ||
3672 | !was_managetempaddr, jiffies); | ||
3673 | } | ||
3674 | |||
3638 | addrconf_verify(0); | 3675 | addrconf_verify(0); |
3639 | 3676 | ||
3640 | return 0; | 3677 | return 0; |
@@ -3650,7 +3687,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
3650 | struct inet6_ifaddr *ifa; | 3687 | struct inet6_ifaddr *ifa; |
3651 | struct net_device *dev; | 3688 | struct net_device *dev; |
3652 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; | 3689 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; |
3653 | u8 ifa_flags; | 3690 | u32 ifa_flags; |
3654 | int err; | 3691 | int err; |
3655 | 3692 | ||
3656 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); | 3693 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
@@ -3677,8 +3714,10 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
3677 | if (dev == NULL) | 3714 | if (dev == NULL) |
3678 | return -ENODEV; | 3715 | return -ENODEV; |
3679 | 3716 | ||
3717 | ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; | ||
3718 | |||
3680 | /* We ignore other flags so far. */ | 3719 | /* We ignore other flags so far. */ |
3681 | ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS); | 3720 | ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR; |
3682 | 3721 | ||
3683 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); | 3722 | ifa = ipv6_get_ifaddr(net, pfx, dev, 1); |
3684 | if (ifa == NULL) { | 3723 | if (ifa == NULL) { |
@@ -3702,7 +3741,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
3702 | return err; | 3741 | return err; |
3703 | } | 3742 | } |
3704 | 3743 | ||
3705 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, | 3744 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags, |
3706 | u8 scope, int ifindex) | 3745 | u8 scope, int ifindex) |
3707 | { | 3746 | { |
3708 | struct ifaddrmsg *ifm; | 3747 | struct ifaddrmsg *ifm; |
@@ -3745,7 +3784,8 @@ static inline int inet6_ifaddr_msgsize(void) | |||
3745 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) | 3784 | return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) |
3746 | + nla_total_size(16) /* IFA_LOCAL */ | 3785 | + nla_total_size(16) /* IFA_LOCAL */ |
3747 | + nla_total_size(16) /* IFA_ADDRESS */ | 3786 | + nla_total_size(16) /* IFA_ADDRESS */ |
3748 | + nla_total_size(sizeof(struct ifa_cacheinfo)); | 3787 | + nla_total_size(sizeof(struct ifa_cacheinfo)) |
3788 | + nla_total_size(4) /* IFA_FLAGS */; | ||
3749 | } | 3789 | } |
3750 | 3790 | ||
3751 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3791 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
@@ -3793,6 +3833,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | |||
3793 | if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) | 3833 | if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) |
3794 | goto error; | 3834 | goto error; |
3795 | 3835 | ||
3836 | if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) | ||
3837 | goto error; | ||
3838 | |||
3796 | return nlmsg_end(skb, nlh); | 3839 | return nlmsg_end(skb, nlh); |
3797 | 3840 | ||
3798 | error: | 3841 | error: |
@@ -4196,7 +4239,7 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | |||
4196 | ci.max_reasm_len = IPV6_MAXPLEN; | 4239 | ci.max_reasm_len = IPV6_MAXPLEN; |
4197 | ci.tstamp = cstamp_delta(idev->tstamp); | 4240 | ci.tstamp = cstamp_delta(idev->tstamp); |
4198 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | 4241 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); |
4199 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | 4242 | ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME)); |
4200 | if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) | 4243 | if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) |
4201 | goto nla_put_failure; | 4244 | goto nla_put_failure; |
4202 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | 4245 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); |
@@ -4689,6 +4732,46 @@ int addrconf_sysctl_disable(struct ctl_table *ctl, int write, | |||
4689 | return ret; | 4732 | return ret; |
4690 | } | 4733 | } |
4691 | 4734 | ||
4735 | static | ||
4736 | int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, | ||
4737 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
4738 | { | ||
4739 | int *valp = ctl->data; | ||
4740 | int ret; | ||
4741 | int old, new; | ||
4742 | |||
4743 | old = *valp; | ||
4744 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
4745 | new = *valp; | ||
4746 | |||
4747 | if (write && old != new) { | ||
4748 | struct net *net = ctl->extra2; | ||
4749 | |||
4750 | if (!rtnl_trylock()) | ||
4751 | return restart_syscall(); | ||
4752 | |||
4753 | if (valp == &net->ipv6.devconf_dflt->proxy_ndp) | ||
4754 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
4755 | NETCONFA_IFINDEX_DEFAULT, | ||
4756 | net->ipv6.devconf_dflt); | ||
4757 | else if (valp == &net->ipv6.devconf_all->proxy_ndp) | ||
4758 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
4759 | NETCONFA_IFINDEX_ALL, | ||
4760 | net->ipv6.devconf_all); | ||
4761 | else { | ||
4762 | struct inet6_dev *idev = ctl->extra1; | ||
4763 | |||
4764 | inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, | ||
4765 | idev->dev->ifindex, | ||
4766 | &idev->cnf); | ||
4767 | } | ||
4768 | rtnl_unlock(); | ||
4769 | } | ||
4770 | |||
4771 | return ret; | ||
4772 | } | ||
4773 | |||
4774 | |||
4692 | static struct addrconf_sysctl_table | 4775 | static struct addrconf_sysctl_table |
4693 | { | 4776 | { |
4694 | struct ctl_table_header *sysctl_header; | 4777 | struct ctl_table_header *sysctl_header; |
@@ -4875,7 +4958,7 @@ static struct addrconf_sysctl_table | |||
4875 | .data = &ipv6_devconf.proxy_ndp, | 4958 | .data = &ipv6_devconf.proxy_ndp, |
4876 | .maxlen = sizeof(int), | 4959 | .maxlen = sizeof(int), |
4877 | .mode = 0644, | 4960 | .mode = 0644, |
4878 | .proc_handler = proc_dointvec, | 4961 | .proc_handler = addrconf_sysctl_proxy_ndp, |
4879 | }, | 4962 | }, |
4880 | { | 4963 | { |
4881 | .procname = "accept_source_route", | 4964 | .procname = "accept_source_route", |
@@ -4991,7 +5074,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4991 | 5074 | ||
4992 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 5075 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
4993 | { | 5076 | { |
4994 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", | 5077 | neigh_sysctl_register(idev->dev, idev->nd_parms, |
4995 | &ndisc_ifinfo_sysctl_change); | 5078 | &ndisc_ifinfo_sysctl_change); |
4996 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 5079 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
4997 | idev, &idev->cnf); | 5080 | idev, &idev->cnf); |