diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 240 |
1 files changed, 195 insertions, 45 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 452a82ce4796..e04e49373505 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #endif | 81 | #endif |
82 | 82 | ||
83 | #include <asm/uaccess.h> | 83 | #include <asm/uaccess.h> |
84 | #include <asm/unaligned.h> | ||
84 | 85 | ||
85 | #include <linux/proc_fs.h> | 86 | #include <linux/proc_fs.h> |
86 | #include <linux/seq_file.h> | 87 | #include <linux/seq_file.h> |
@@ -208,9 +209,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
208 | }; | 209 | }; |
209 | 210 | ||
210 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 211 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
211 | #if 0 | ||
212 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | 212 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; |
213 | #endif | ||
214 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | 213 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; |
215 | 214 | ||
216 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 215 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -246,6 +245,37 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
246 | add_timer(&ifp->timer); | 245 | add_timer(&ifp->timer); |
247 | } | 246 | } |
248 | 247 | ||
248 | static int snmp6_alloc_dev(struct inet6_dev *idev) | ||
249 | { | ||
250 | int err = -ENOMEM; | ||
251 | |||
252 | if (!idev || !idev->dev) | ||
253 | return -EINVAL; | ||
254 | |||
255 | if (snmp_mib_init((void **)idev->stats.ipv6, | ||
256 | sizeof(struct ipstats_mib), | ||
257 | __alignof__(struct ipstats_mib)) < 0) | ||
258 | goto err_ip; | ||
259 | if (snmp_mib_init((void **)idev->stats.icmpv6, | ||
260 | sizeof(struct icmpv6_mib), | ||
261 | __alignof__(struct icmpv6_mib)) < 0) | ||
262 | goto err_icmp; | ||
263 | |||
264 | return 0; | ||
265 | |||
266 | err_icmp: | ||
267 | snmp_mib_free((void **)idev->stats.ipv6); | ||
268 | err_ip: | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | static int snmp6_free_dev(struct inet6_dev *idev) | ||
273 | { | ||
274 | snmp_mib_free((void **)idev->stats.icmpv6); | ||
275 | snmp_mib_free((void **)idev->stats.ipv6); | ||
276 | return 0; | ||
277 | } | ||
278 | |||
249 | /* Nobody refers to this device, we may destroy it. */ | 279 | /* Nobody refers to this device, we may destroy it. */ |
250 | 280 | ||
251 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | 281 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) |
@@ -271,6 +301,8 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
271 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); | 301 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); |
272 | } | 302 | } |
273 | 303 | ||
304 | EXPORT_SYMBOL(in6_dev_finish_destroy); | ||
305 | |||
274 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | 306 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) |
275 | { | 307 | { |
276 | struct inet6_dev *ndev; | 308 | struct inet6_dev *ndev; |
@@ -528,6 +560,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
528 | 560 | ||
529 | ifa->rt = rt; | 561 | ifa->rt = rt; |
530 | 562 | ||
563 | /* | ||
564 | * part one of RFC 4429, section 3.3 | ||
565 | * We should not configure an address as | ||
566 | * optimistic if we do not yet know the link | ||
567 | * layer address of our nexhop router | ||
568 | */ | ||
569 | |||
570 | if (rt->rt6i_nexthop == NULL) | ||
571 | ifa->flags &= ~IFA_F_OPTIMISTIC; | ||
572 | |||
531 | ifa->idev = idev; | 573 | ifa->idev = idev; |
532 | in6_dev_hold(idev); | 574 | in6_dev_hold(idev); |
533 | /* For caller */ | 575 | /* For caller */ |
@@ -704,6 +746,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
704 | int tmp_plen; | 746 | int tmp_plen; |
705 | int ret = 0; | 747 | int ret = 0; |
706 | int max_addresses; | 748 | int max_addresses; |
749 | u32 addr_flags; | ||
707 | 750 | ||
708 | write_lock(&idev->lock); | 751 | write_lock(&idev->lock); |
709 | if (ift) { | 752 | if (ift) { |
@@ -761,10 +804,17 @@ retry: | |||
761 | spin_unlock_bh(&ifp->lock); | 804 | spin_unlock_bh(&ifp->lock); |
762 | 805 | ||
763 | write_unlock(&idev->lock); | 806 | write_unlock(&idev->lock); |
807 | |||
808 | addr_flags = IFA_F_TEMPORARY; | ||
809 | /* set in addrconf_prefix_rcv() */ | ||
810 | if (ifp->flags & IFA_F_OPTIMISTIC) | ||
811 | addr_flags |= IFA_F_OPTIMISTIC; | ||
812 | |||
764 | ift = !max_addresses || | 813 | ift = !max_addresses || |
765 | ipv6_count_addresses(idev) < max_addresses ? | 814 | ipv6_count_addresses(idev) < max_addresses ? |
766 | ipv6_add_addr(idev, &addr, tmp_plen, | 815 | ipv6_add_addr(idev, &addr, tmp_plen, |
767 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; | 816 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, |
817 | addr_flags) : NULL; | ||
768 | if (!ift || IS_ERR(ift)) { | 818 | if (!ift || IS_ERR(ift)) { |
769 | in6_ifa_put(ifp); | 819 | in6_ifa_put(ifp); |
770 | in6_dev_put(idev); | 820 | in6_dev_put(idev); |
@@ -896,13 +946,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
896 | * - Tentative Address (RFC2462 section 5.4) | 946 | * - Tentative Address (RFC2462 section 5.4) |
897 | * - A tentative address is not considered | 947 | * - A tentative address is not considered |
898 | * "assigned to an interface" in the traditional | 948 | * "assigned to an interface" in the traditional |
899 | * sense. | 949 | * sense, unless it is also flagged as optimistic. |
900 | * - Candidate Source Address (section 4) | 950 | * - Candidate Source Address (section 4) |
901 | * - In any case, anycast addresses, multicast | 951 | * - In any case, anycast addresses, multicast |
902 | * addresses, and the unspecified address MUST | 952 | * addresses, and the unspecified address MUST |
903 | * NOT be included in a candidate set. | 953 | * NOT be included in a candidate set. |
904 | */ | 954 | */ |
905 | if (ifa->flags & IFA_F_TENTATIVE) | 955 | if ((ifa->flags & IFA_F_TENTATIVE) && |
956 | (!(ifa->flags & IFA_F_OPTIMISTIC))) | ||
906 | continue; | 957 | continue; |
907 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || | 958 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || |
908 | score.addr_type & IPV6_ADDR_MULTICAST)) { | 959 | score.addr_type & IPV6_ADDR_MULTICAST)) { |
@@ -961,15 +1012,17 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
961 | } | 1012 | } |
962 | } | 1013 | } |
963 | 1014 | ||
964 | /* Rule 3: Avoid deprecated address */ | 1015 | /* Rule 3: Avoid deprecated and optimistic addresses */ |
965 | if (hiscore.rule < 3) { | 1016 | if (hiscore.rule < 3) { |
966 | if (ipv6_saddr_preferred(hiscore.addr_type) || | 1017 | if (ipv6_saddr_preferred(hiscore.addr_type) || |
967 | !(ifa_result->flags & IFA_F_DEPRECATED)) | 1018 | (((ifa_result->flags & |
1019 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) | ||
968 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; | 1020 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; |
969 | hiscore.rule++; | 1021 | hiscore.rule++; |
970 | } | 1022 | } |
971 | if (ipv6_saddr_preferred(score.addr_type) || | 1023 | if (ipv6_saddr_preferred(score.addr_type) || |
972 | !(ifa->flags & IFA_F_DEPRECATED)) { | 1024 | (((ifa_result->flags & |
1025 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) { | ||
973 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; | 1026 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; |
974 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { | 1027 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { |
975 | score.rule = 3; | 1028 | score.rule = 3; |
@@ -1107,8 +1160,10 @@ int ipv6_get_saddr(struct dst_entry *dst, | |||
1107 | return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); | 1160 | return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); |
1108 | } | 1161 | } |
1109 | 1162 | ||
1163 | EXPORT_SYMBOL(ipv6_get_saddr); | ||
1110 | 1164 | ||
1111 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | 1165 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, |
1166 | unsigned char banned_flags) | ||
1112 | { | 1167 | { |
1113 | struct inet6_dev *idev; | 1168 | struct inet6_dev *idev; |
1114 | int err = -EADDRNOTAVAIL; | 1169 | int err = -EADDRNOTAVAIL; |
@@ -1119,7 +1174,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1119 | 1174 | ||
1120 | read_lock_bh(&idev->lock); | 1175 | read_lock_bh(&idev->lock); |
1121 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | 1176 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { |
1122 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { | 1177 | if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { |
1123 | ipv6_addr_copy(addr, &ifp->addr); | 1178 | ipv6_addr_copy(addr, &ifp->addr); |
1124 | err = 0; | 1179 | err = 0; |
1125 | break; | 1180 | break; |
@@ -1161,6 +1216,8 @@ int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict) | |||
1161 | return ifp != NULL; | 1216 | return ifp != NULL; |
1162 | } | 1217 | } |
1163 | 1218 | ||
1219 | EXPORT_SYMBOL(ipv6_chk_addr); | ||
1220 | |||
1164 | static | 1221 | static |
1165 | int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev) | 1222 | int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev) |
1166 | { | 1223 | { |
@@ -1669,6 +1726,13 @@ ok: | |||
1669 | 1726 | ||
1670 | if (ifp == NULL && valid_lft) { | 1727 | if (ifp == NULL && valid_lft) { |
1671 | int max_addresses = in6_dev->cnf.max_addresses; | 1728 | int max_addresses = in6_dev->cnf.max_addresses; |
1729 | u32 addr_flags = 0; | ||
1730 | |||
1731 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
1732 | if (in6_dev->cnf.optimistic_dad && | ||
1733 | !ipv6_devconf.forwarding) | ||
1734 | addr_flags = IFA_F_OPTIMISTIC; | ||
1735 | #endif | ||
1672 | 1736 | ||
1673 | /* Do not allow to create too much of autoconfigured | 1737 | /* Do not allow to create too much of autoconfigured |
1674 | * addresses; this would be too easy way to crash kernel. | 1738 | * addresses; this would be too easy way to crash kernel. |
@@ -1676,7 +1740,8 @@ ok: | |||
1676 | if (!max_addresses || | 1740 | if (!max_addresses || |
1677 | ipv6_count_addresses(in6_dev) < max_addresses) | 1741 | ipv6_count_addresses(in6_dev) < max_addresses) |
1678 | ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, | 1742 | ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, |
1679 | addr_type&IPV6_ADDR_SCOPE_MASK, 0); | 1743 | addr_type&IPV6_ADDR_SCOPE_MASK, |
1744 | addr_flags); | ||
1680 | 1745 | ||
1681 | if (!ifp || IS_ERR(ifp)) { | 1746 | if (!ifp || IS_ERR(ifp)) { |
1682 | in6_dev_put(in6_dev); | 1747 | in6_dev_put(in6_dev); |
@@ -1884,6 +1949,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | |||
1884 | 1949 | ||
1885 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 1950 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
1886 | jiffies_to_clock_t(valid_lft * HZ), flags); | 1951 | jiffies_to_clock_t(valid_lft * HZ), flags); |
1952 | /* | ||
1953 | * Note that section 3.1 of RFC 4429 indicates | ||
1954 | * that the Optimistic flag should not be set for | ||
1955 | * manually configured addresses | ||
1956 | */ | ||
1887 | addrconf_dad_start(ifp, 0); | 1957 | addrconf_dad_start(ifp, 0); |
1888 | in6_ifa_put(ifp); | 1958 | in6_ifa_put(ifp); |
1889 | addrconf_verify(0); | 1959 | addrconf_verify(0); |
@@ -2060,8 +2130,16 @@ static void init_loopback(struct net_device *dev) | |||
2060 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) | 2130 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) |
2061 | { | 2131 | { |
2062 | struct inet6_ifaddr * ifp; | 2132 | struct inet6_ifaddr * ifp; |
2133 | u32 addr_flags = IFA_F_PERMANENT; | ||
2134 | |||
2135 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
2136 | if (idev->cnf.optimistic_dad && | ||
2137 | !ipv6_devconf.forwarding) | ||
2138 | addr_flags |= IFA_F_OPTIMISTIC; | ||
2139 | #endif | ||
2063 | 2140 | ||
2064 | ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); | 2141 | |
2142 | ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); | ||
2065 | if (!IS_ERR(ifp)) { | 2143 | if (!IS_ERR(ifp)) { |
2066 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); | 2144 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); |
2067 | addrconf_dad_start(ifp, 0); | 2145 | addrconf_dad_start(ifp, 0); |
@@ -2129,7 +2207,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) | |||
2129 | { | 2207 | { |
2130 | struct in6_addr lladdr; | 2208 | struct in6_addr lladdr; |
2131 | 2209 | ||
2132 | if (!ipv6_get_lladdr(link_dev, &lladdr)) { | 2210 | if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) { |
2133 | addrconf_add_linklocal(idev, &lladdr); | 2211 | addrconf_add_linklocal(idev, &lladdr); |
2134 | return 0; | 2212 | return 0; |
2135 | } | 2213 | } |
@@ -2240,7 +2318,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2240 | default: | 2318 | default: |
2241 | addrconf_dev_config(dev); | 2319 | addrconf_dev_config(dev); |
2242 | break; | 2320 | break; |
2243 | }; | 2321 | } |
2244 | if (idev) { | 2322 | if (idev) { |
2245 | if (run_pending) | 2323 | if (run_pending) |
2246 | addrconf_dad_run(idev); | 2324 | addrconf_dad_run(idev); |
@@ -2293,7 +2371,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2293 | } | 2371 | } |
2294 | #endif | 2372 | #endif |
2295 | break; | 2373 | break; |
2296 | }; | 2374 | } |
2297 | 2375 | ||
2298 | return NOTIFY_OK; | 2376 | return NOTIFY_OK; |
2299 | } | 2377 | } |
@@ -2474,7 +2552,11 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp) | |||
2474 | unsigned long rand_num; | 2552 | unsigned long rand_num; |
2475 | struct inet6_dev *idev = ifp->idev; | 2553 | struct inet6_dev *idev = ifp->idev; |
2476 | 2554 | ||
2477 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | 2555 | if (ifp->flags & IFA_F_OPTIMISTIC) |
2556 | rand_num = 0; | ||
2557 | else | ||
2558 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2559 | |||
2478 | ifp->probes = idev->cnf.dad_transmits; | 2560 | ifp->probes = idev->cnf.dad_transmits; |
2479 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | 2561 | addrconf_mod_timer(ifp, AC_DAD, rand_num); |
2480 | } | 2562 | } |
@@ -2496,7 +2578,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2496 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2578 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2497 | !(ifp->flags&IFA_F_TENTATIVE) || | 2579 | !(ifp->flags&IFA_F_TENTATIVE) || |
2498 | ifp->flags & IFA_F_NODAD) { | 2580 | ifp->flags & IFA_F_NODAD) { |
2499 | ifp->flags &= ~IFA_F_TENTATIVE; | 2581 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); |
2500 | spin_unlock_bh(&ifp->lock); | 2582 | spin_unlock_bh(&ifp->lock); |
2501 | read_unlock_bh(&idev->lock); | 2583 | read_unlock_bh(&idev->lock); |
2502 | 2584 | ||
@@ -2516,6 +2598,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2516 | addrconf_dad_stop(ifp); | 2598 | addrconf_dad_stop(ifp); |
2517 | return; | 2599 | return; |
2518 | } | 2600 | } |
2601 | |||
2602 | /* | ||
2603 | * Optimistic nodes can start receiving | ||
2604 | * Frames right away | ||
2605 | */ | ||
2606 | if(ifp->flags & IFA_F_OPTIMISTIC) | ||
2607 | ip6_ins_rt(ifp->rt); | ||
2608 | |||
2519 | addrconf_dad_kick(ifp); | 2609 | addrconf_dad_kick(ifp); |
2520 | spin_unlock_bh(&ifp->lock); | 2610 | spin_unlock_bh(&ifp->lock); |
2521 | out: | 2611 | out: |
@@ -2540,7 +2630,7 @@ static void addrconf_dad_timer(unsigned long data) | |||
2540 | * DAD was successful | 2630 | * DAD was successful |
2541 | */ | 2631 | */ |
2542 | 2632 | ||
2543 | ifp->flags &= ~IFA_F_TENTATIVE; | 2633 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); |
2544 | spin_unlock_bh(&ifp->lock); | 2634 | spin_unlock_bh(&ifp->lock); |
2545 | read_unlock_bh(&idev->lock); | 2635 | read_unlock_bh(&idev->lock); |
2546 | 2636 | ||
@@ -3164,7 +3254,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3164 | 3254 | ||
3165 | s_idx = cb->args[0]; | 3255 | s_idx = cb->args[0]; |
3166 | s_ip_idx = ip_idx = cb->args[1]; | 3256 | s_ip_idx = ip_idx = cb->args[1]; |
3167 | read_lock(&dev_base_lock); | ||
3168 | 3257 | ||
3169 | for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { | 3258 | for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { |
3170 | if (idx < s_idx) | 3259 | if (idx < s_idx) |
@@ -3226,7 +3315,6 @@ done: | |||
3226 | read_unlock_bh(&idev->lock); | 3315 | read_unlock_bh(&idev->lock); |
3227 | in6_dev_put(idev); | 3316 | in6_dev_put(idev); |
3228 | } | 3317 | } |
3229 | read_unlock(&dev_base_lock); | ||
3230 | cb->args[0] = idx; | 3318 | cb->args[0] = idx; |
3231 | cb->args[1] = ip_idx; | 3319 | cb->args[1] = ip_idx; |
3232 | return skb->len; | 3320 | return skb->len; |
@@ -3359,6 +3447,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3359 | #endif | 3447 | #endif |
3360 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | 3448 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; |
3361 | array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; | 3449 | array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; |
3450 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
3451 | array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; | ||
3452 | #endif | ||
3362 | } | 3453 | } |
3363 | 3454 | ||
3364 | static inline size_t inet6_if_nlmsg_size(void) | 3455 | static inline size_t inet6_if_nlmsg_size(void) |
@@ -3372,14 +3463,44 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3372 | nla_total_size(4) /* IFLA_INET6_FLAGS */ | 3463 | nla_total_size(4) /* IFLA_INET6_FLAGS */ |
3373 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | 3464 | + nla_total_size(sizeof(struct ifla_cacheinfo)) |
3374 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | 3465 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ |
3466 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3467 | + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ | ||
3375 | ); | 3468 | ); |
3376 | } | 3469 | } |
3377 | 3470 | ||
3471 | static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | ||
3472 | int bytes) | ||
3473 | { | ||
3474 | int i; | ||
3475 | int pad = bytes - sizeof(u64) * items; | ||
3476 | BUG_ON(pad < 0); | ||
3477 | |||
3478 | /* Use put_unaligned() because stats may not be aligned for u64. */ | ||
3479 | put_unaligned(items, &stats[0]); | ||
3480 | for (i = 1; i < items; i++) | ||
3481 | put_unaligned(snmp_fold_field(mib, i), &stats[i]); | ||
3482 | |||
3483 | memset(&stats[items], 0, pad); | ||
3484 | } | ||
3485 | |||
3486 | static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | ||
3487 | int bytes) | ||
3488 | { | ||
3489 | switch(attrtype) { | ||
3490 | case IFLA_INET6_STATS: | ||
3491 | __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | ||
3492 | break; | ||
3493 | case IFLA_INET6_ICMP6STATS: | ||
3494 | __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | ||
3495 | break; | ||
3496 | } | ||
3497 | } | ||
3498 | |||
3378 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3499 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
3379 | u32 pid, u32 seq, int event, unsigned int flags) | 3500 | u32 pid, u32 seq, int event, unsigned int flags) |
3380 | { | 3501 | { |
3381 | struct net_device *dev = idev->dev; | 3502 | struct net_device *dev = idev->dev; |
3382 | struct nlattr *conf; | 3503 | struct nlattr *nla; |
3383 | struct ifinfomsg *hdr; | 3504 | struct ifinfomsg *hdr; |
3384 | struct nlmsghdr *nlh; | 3505 | struct nlmsghdr *nlh; |
3385 | void *protoinfo; | 3506 | void *protoinfo; |
@@ -3419,12 +3540,22 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
3419 | ci.retrans_time = idev->nd_parms->retrans_time; | 3540 | ci.retrans_time = idev->nd_parms->retrans_time; |
3420 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | 3541 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); |
3421 | 3542 | ||
3422 | conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | 3543 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); |
3423 | if (conf == NULL) | 3544 | if (nla == NULL) |
3424 | goto nla_put_failure; | 3545 | goto nla_put_failure; |
3425 | ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf)); | 3546 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); |
3426 | 3547 | ||
3427 | /* XXX - Statistics/MC not implemented */ | 3548 | /* XXX - MC not implemented */ |
3549 | |||
3550 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3551 | if (nla == NULL) | ||
3552 | goto nla_put_failure; | ||
3553 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3554 | |||
3555 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3556 | if (nla == NULL) | ||
3557 | goto nla_put_failure; | ||
3558 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3428 | 3559 | ||
3429 | nla_nest_end(skb, protoinfo); | 3560 | nla_nest_end(skb, protoinfo); |
3430 | return nlmsg_end(skb, nlh); | 3561 | return nlmsg_end(skb, nlh); |
@@ -3550,30 +3681,20 @@ errout: | |||
3550 | rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err); | 3681 | rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err); |
3551 | } | 3682 | } |
3552 | 3683 | ||
3553 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | ||
3554 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, | ||
3555 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, | ||
3556 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, | ||
3557 | [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr, | ||
3558 | .dumpit = inet6_dump_ifaddr, }, | ||
3559 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, | ||
3560 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, | ||
3561 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, | ||
3562 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, | ||
3563 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, | ||
3564 | .dumpit = inet6_dump_fib, }, | ||
3565 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3566 | [RTM_GETRULE - RTM_BASE] = { .dumpit = fib6_rules_dump, }, | ||
3567 | #endif | ||
3568 | }; | ||
3569 | |||
3570 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3684 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
3571 | { | 3685 | { |
3572 | inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); | 3686 | inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); |
3573 | 3687 | ||
3574 | switch (event) { | 3688 | switch (event) { |
3575 | case RTM_NEWADDR: | 3689 | case RTM_NEWADDR: |
3576 | ip6_ins_rt(ifp->rt); | 3690 | /* |
3691 | * If the address was optimistic | ||
3692 | * we inserted the route at the start of | ||
3693 | * our DAD process, so we don't need | ||
3694 | * to do it again | ||
3695 | */ | ||
3696 | if (!(ifp->rt->rt6i_node)) | ||
3697 | ip6_ins_rt(ifp->rt); | ||
3577 | if (ifp->idev->cnf.forwarding) | 3698 | if (ifp->idev->cnf.forwarding) |
3578 | addrconf_join_anycast(ifp); | 3699 | addrconf_join_anycast(ifp); |
3579 | break; | 3700 | break; |
@@ -3894,6 +4015,17 @@ static struct addrconf_sysctl_table | |||
3894 | .mode = 0644, | 4015 | .mode = 0644, |
3895 | .proc_handler = &proc_dointvec, | 4016 | .proc_handler = &proc_dointvec, |
3896 | }, | 4017 | }, |
4018 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
4019 | { | ||
4020 | .ctl_name = CTL_UNNUMBERED, | ||
4021 | .procname = "optimistic_dad", | ||
4022 | .data = &ipv6_devconf.optimistic_dad, | ||
4023 | .maxlen = sizeof(int), | ||
4024 | .mode = 0644, | ||
4025 | .proc_handler = &proc_dointvec, | ||
4026 | |||
4027 | }, | ||
4028 | #endif | ||
3897 | { | 4029 | { |
3898 | .ctl_name = 0, /* sentinel */ | 4030 | .ctl_name = 0, /* sentinel */ |
3899 | } | 4031 | } |
@@ -4021,11 +4153,15 @@ int register_inet6addr_notifier(struct notifier_block *nb) | |||
4021 | return atomic_notifier_chain_register(&inet6addr_chain, nb); | 4153 | return atomic_notifier_chain_register(&inet6addr_chain, nb); |
4022 | } | 4154 | } |
4023 | 4155 | ||
4156 | EXPORT_SYMBOL(register_inet6addr_notifier); | ||
4157 | |||
4024 | int unregister_inet6addr_notifier(struct notifier_block *nb) | 4158 | int unregister_inet6addr_notifier(struct notifier_block *nb) |
4025 | { | 4159 | { |
4026 | return atomic_notifier_chain_unregister(&inet6addr_chain,nb); | 4160 | return atomic_notifier_chain_unregister(&inet6addr_chain,nb); |
4027 | } | 4161 | } |
4028 | 4162 | ||
4163 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | ||
4164 | |||
4029 | /* | 4165 | /* |
4030 | * Init / cleanup code | 4166 | * Init / cleanup code |
4031 | */ | 4167 | */ |
@@ -4064,7 +4200,18 @@ int __init addrconf_init(void) | |||
4064 | register_netdevice_notifier(&ipv6_dev_notf); | 4200 | register_netdevice_notifier(&ipv6_dev_notf); |
4065 | 4201 | ||
4066 | addrconf_verify(0); | 4202 | addrconf_verify(0); |
4067 | rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; | 4203 | |
4204 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); | ||
4205 | if (err < 0) | ||
4206 | goto errout; | ||
4207 | |||
4208 | /* Only the first call to __rtnl_register can fail */ | ||
4209 | __rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL); | ||
4210 | __rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL); | ||
4211 | __rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr, inet6_dump_ifaddr); | ||
4212 | __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, inet6_dump_ifmcaddr); | ||
4213 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, inet6_dump_ifacaddr); | ||
4214 | |||
4068 | #ifdef CONFIG_SYSCTL | 4215 | #ifdef CONFIG_SYSCTL |
4069 | addrconf_sysctl.sysctl_header = | 4216 | addrconf_sysctl.sysctl_header = |
4070 | register_sysctl_table(addrconf_sysctl.addrconf_root_dir); | 4217 | register_sysctl_table(addrconf_sysctl.addrconf_root_dir); |
@@ -4072,6 +4219,10 @@ int __init addrconf_init(void) | |||
4072 | #endif | 4219 | #endif |
4073 | 4220 | ||
4074 | return 0; | 4221 | return 0; |
4222 | errout: | ||
4223 | unregister_netdevice_notifier(&ipv6_dev_notf); | ||
4224 | |||
4225 | return err; | ||
4075 | } | 4226 | } |
4076 | 4227 | ||
4077 | void __exit addrconf_cleanup(void) | 4228 | void __exit addrconf_cleanup(void) |
@@ -4083,7 +4234,6 @@ void __exit addrconf_cleanup(void) | |||
4083 | 4234 | ||
4084 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4235 | unregister_netdevice_notifier(&ipv6_dev_notf); |
4085 | 4236 | ||
4086 | rtnetlink_links[PF_INET6] = NULL; | ||
4087 | #ifdef CONFIG_SYSCTL | 4237 | #ifdef CONFIG_SYSCTL |
4088 | addrconf_sysctl_unregister(&ipv6_devconf_dflt); | 4238 | addrconf_sysctl_unregister(&ipv6_devconf_dflt); |
4089 | addrconf_sysctl_unregister(&ipv6_devconf); | 4239 | addrconf_sysctl_unregister(&ipv6_devconf); |