diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 312 |
1 files changed, 166 insertions, 146 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 324fac3b6c16..498b927f68be 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -98,7 +98,11 @@ | |||
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | #define INFINITY_LIFE_TIME 0xFFFFFFFF | 100 | #define INFINITY_LIFE_TIME 0xFFFFFFFF |
101 | #define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) | 101 | |
102 | static inline u32 cstamp_delta(unsigned long cstamp) | ||
103 | { | ||
104 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | ||
105 | } | ||
102 | 106 | ||
103 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | 107 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) |
104 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | 108 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) |
@@ -243,7 +247,7 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
243 | /* Check if a route is valid prefix route */ | 247 | /* Check if a route is valid prefix route */ |
244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | 248 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) |
245 | { | 249 | { |
246 | return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0); | 250 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; |
247 | } | 251 | } |
248 | 252 | ||
249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 253 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -285,19 +289,19 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) | |||
285 | sizeof(struct ipstats_mib), | 289 | sizeof(struct ipstats_mib), |
286 | __alignof__(struct ipstats_mib)) < 0) | 290 | __alignof__(struct ipstats_mib)) < 0) |
287 | goto err_ip; | 291 | goto err_ip; |
288 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, | 292 | idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), |
289 | sizeof(struct icmpv6_mib), | 293 | GFP_KERNEL); |
290 | __alignof__(struct icmpv6_mib)) < 0) | 294 | if (!idev->stats.icmpv6dev) |
291 | goto err_icmp; | 295 | goto err_icmp; |
292 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, | 296 | idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), |
293 | sizeof(struct icmpv6msg_mib), | 297 | GFP_KERNEL); |
294 | __alignof__(struct icmpv6msg_mib)) < 0) | 298 | if (!idev->stats.icmpv6msgdev) |
295 | goto err_icmpmsg; | 299 | goto err_icmpmsg; |
296 | 300 | ||
297 | return 0; | 301 | return 0; |
298 | 302 | ||
299 | err_icmpmsg: | 303 | err_icmpmsg: |
300 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 304 | kfree(idev->stats.icmpv6dev); |
301 | err_icmp: | 305 | err_icmp: |
302 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 306 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
303 | err_ip: | 307 | err_ip: |
@@ -306,19 +310,13 @@ err_ip: | |||
306 | 310 | ||
307 | static void snmp6_free_dev(struct inet6_dev *idev) | 311 | static void snmp6_free_dev(struct inet6_dev *idev) |
308 | { | 312 | { |
309 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); | 313 | kfree(idev->stats.icmpv6msgdev); |
310 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 314 | kfree(idev->stats.icmpv6dev); |
311 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 315 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
312 | } | 316 | } |
313 | 317 | ||
314 | /* Nobody refers to this device, we may destroy it. */ | 318 | /* Nobody refers to this device, we may destroy it. */ |
315 | 319 | ||
316 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | ||
317 | { | ||
318 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); | ||
319 | kfree(idev); | ||
320 | } | ||
321 | |||
322 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 320 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
323 | { | 321 | { |
324 | struct net_device *dev = idev->dev; | 322 | struct net_device *dev = idev->dev; |
@@ -335,7 +333,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
335 | return; | 333 | return; |
336 | } | 334 | } |
337 | snmp6_free_dev(idev); | 335 | snmp6_free_dev(idev); |
338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); | 336 | kfree_rcu(idev, rcu); |
339 | } | 337 | } |
340 | 338 | ||
341 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 339 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
@@ -416,9 +414,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
416 | dev->type == ARPHRD_TUNNEL6 || | 414 | dev->type == ARPHRD_TUNNEL6 || |
417 | dev->type == ARPHRD_SIT || | 415 | dev->type == ARPHRD_SIT || |
418 | dev->type == ARPHRD_NONE) { | 416 | dev->type == ARPHRD_NONE) { |
419 | printk(KERN_INFO | ||
420 | "%s: Disabled Privacy Extensions\n", | ||
421 | dev->name); | ||
422 | ndev->cnf.use_tempaddr = -1; | 417 | ndev->cnf.use_tempaddr = -1; |
423 | } else { | 418 | } else { |
424 | in6_dev_hold(ndev); | 419 | in6_dev_hold(ndev); |
@@ -534,12 +529,6 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
534 | } | 529 | } |
535 | #endif | 530 | #endif |
536 | 531 | ||
537 | static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) | ||
538 | { | ||
539 | struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); | ||
540 | kfree(ifp); | ||
541 | } | ||
542 | |||
543 | /* Nobody refers to this ifaddr, destroy it */ | 532 | /* Nobody refers to this ifaddr, destroy it */ |
544 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | 533 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) |
545 | { | 534 | { |
@@ -560,7 +549,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
560 | } | 549 | } |
561 | dst_release(&ifp->rt->dst); | 550 | dst_release(&ifp->rt->dst); |
562 | 551 | ||
563 | call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu); | 552 | kfree_rcu(ifp, rcu); |
564 | } | 553 | } |
565 | 554 | ||
566 | static void | 555 | static void |
@@ -717,12 +706,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
717 | struct inet6_ifaddr *ifa, *ifn; | 706 | struct inet6_ifaddr *ifa, *ifn; |
718 | struct inet6_dev *idev = ifp->idev; | 707 | struct inet6_dev *idev = ifp->idev; |
719 | int state; | 708 | int state; |
720 | int hash; | ||
721 | int deleted = 0, onlink = 0; | 709 | int deleted = 0, onlink = 0; |
722 | unsigned long expires = jiffies; | 710 | unsigned long expires = jiffies; |
723 | 711 | ||
724 | hash = ipv6_addr_hash(&ifp->addr); | ||
725 | |||
726 | spin_lock_bh(&ifp->state_lock); | 712 | spin_lock_bh(&ifp->state_lock); |
727 | state = ifp->state; | 713 | state = ifp->state; |
728 | ifp->state = INET6_IFADDR_STATE_DEAD; | 714 | ifp->state = INET6_IFADDR_STATE_DEAD; |
@@ -827,6 +813,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
827 | dst_release(&rt->dst); | 813 | dst_release(&rt->dst); |
828 | } | 814 | } |
829 | 815 | ||
816 | /* clean up prefsrc entries */ | ||
817 | rt6_remove_prefsrc(ifp); | ||
830 | out: | 818 | out: |
831 | in6_ifa_put(ifp); | 819 | in6_ifa_put(ifp); |
832 | } | 820 | } |
@@ -836,7 +824,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
836 | { | 824 | { |
837 | struct inet6_dev *idev = ifp->idev; | 825 | struct inet6_dev *idev = ifp->idev; |
838 | struct in6_addr addr, *tmpaddr; | 826 | struct in6_addr addr, *tmpaddr; |
839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp; | 827 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age; |
840 | unsigned long regen_advance; | 828 | unsigned long regen_advance; |
841 | int tmp_plen; | 829 | int tmp_plen; |
842 | int ret = 0; | 830 | int ret = 0; |
@@ -886,12 +874,13 @@ retry: | |||
886 | goto out; | 874 | goto out; |
887 | } | 875 | } |
888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); | 876 | memcpy(&addr.s6_addr[8], idev->rndid, 8); |
877 | age = (jiffies - ifp->tstamp) / HZ; | ||
889 | tmp_valid_lft = min_t(__u32, | 878 | tmp_valid_lft = min_t(__u32, |
890 | ifp->valid_lft, | 879 | ifp->valid_lft, |
891 | idev->cnf.temp_valid_lft); | 880 | idev->cnf.temp_valid_lft + age); |
892 | tmp_prefered_lft = min_t(__u32, | 881 | tmp_prefered_lft = min_t(__u32, |
893 | ifp->prefered_lft, | 882 | ifp->prefered_lft, |
894 | idev->cnf.temp_prefered_lft - | 883 | idev->cnf.temp_prefered_lft + age - |
895 | idev->cnf.max_desync_factor); | 884 | idev->cnf.max_desync_factor); |
896 | tmp_plen = ifp->prefix_len; | 885 | tmp_plen = ifp->prefix_len; |
897 | max_addresses = idev->cnf.max_addresses; | 886 | max_addresses = idev->cnf.max_addresses; |
@@ -1085,7 +1074,7 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
1085 | case IPV6_SADDR_RULE_PRIVACY: | 1074 | case IPV6_SADDR_RULE_PRIVACY: |
1086 | { | 1075 | { |
1087 | /* Rule 7: Prefer public address | 1076 | /* Rule 7: Prefer public address |
1088 | * Note: prefer temprary address if use_tempaddr >= 2 | 1077 | * Note: prefer temporary address if use_tempaddr >= 2 |
1089 | */ | 1078 | */ |
1090 | int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? | 1079 | int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? |
1091 | !!(dst->prefs & IPV6_PREFER_SRC_TMP) : | 1080 | !!(dst->prefs & IPV6_PREFER_SRC_TMP) : |
@@ -1282,7 +1271,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
1282 | return cnt; | 1271 | return cnt; |
1283 | } | 1272 | } |
1284 | 1273 | ||
1285 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, | 1274 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, |
1286 | struct net_device *dev, int strict) | 1275 | struct net_device *dev, int strict) |
1287 | { | 1276 | { |
1288 | struct inet6_ifaddr *ifp; | 1277 | struct inet6_ifaddr *ifp; |
@@ -1325,7 +1314,7 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | |||
1325 | return false; | 1314 | return false; |
1326 | } | 1315 | } |
1327 | 1316 | ||
1328 | int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) | 1317 | int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) |
1329 | { | 1318 | { |
1330 | struct inet6_dev *idev; | 1319 | struct inet6_dev *idev; |
1331 | struct inet6_ifaddr *ifa; | 1320 | struct inet6_ifaddr *ifa; |
@@ -1426,8 +1415,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1426 | { | 1415 | { |
1427 | struct inet6_dev *idev = ifp->idev; | 1416 | struct inet6_dev *idev = ifp->idev; |
1428 | 1417 | ||
1429 | if (addrconf_dad_end(ifp)) | 1418 | if (addrconf_dad_end(ifp)) { |
1419 | in6_ifa_put(ifp); | ||
1430 | return; | 1420 | return; |
1421 | } | ||
1431 | 1422 | ||
1432 | if (net_ratelimit()) | 1423 | if (net_ratelimit()) |
1433 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", | 1424 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", |
@@ -1454,7 +1445,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1454 | 1445 | ||
1455 | /* Join to solicited addr multicast group. */ | 1446 | /* Join to solicited addr multicast group. */ |
1456 | 1447 | ||
1457 | void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) | 1448 | void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) |
1458 | { | 1449 | { |
1459 | struct in6_addr maddr; | 1450 | struct in6_addr maddr; |
1460 | 1451 | ||
@@ -1465,7 +1456,7 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) | |||
1465 | ipv6_dev_mc_inc(dev, &maddr); | 1456 | ipv6_dev_mc_inc(dev, &maddr); |
1466 | } | 1457 | } |
1467 | 1458 | ||
1468 | void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr) | 1459 | void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) |
1469 | { | 1460 | { |
1470 | struct in6_addr maddr; | 1461 | struct in6_addr maddr; |
1471 | 1462 | ||
@@ -1544,7 +1535,7 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) | |||
1544 | return 0; | 1535 | return 0; |
1545 | } | 1536 | } |
1546 | 1537 | ||
1547 | int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | 1538 | static int __ipv6_isatap_ifid(u8 *eui, __be32 addr) |
1548 | { | 1539 | { |
1549 | if (addr == 0) | 1540 | if (addr == 0) |
1550 | return -1; | 1541 | return -1; |
@@ -1560,7 +1551,6 @@ int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | |||
1560 | memcpy(eui + 4, &addr, 4); | 1551 | memcpy(eui + 4, &addr, 4); |
1561 | return 0; | 1552 | return 0; |
1562 | } | 1553 | } |
1563 | EXPORT_SYMBOL(__ipv6_isatap_ifid); | ||
1564 | 1554 | ||
1565 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) | 1555 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) |
1566 | { | 1556 | { |
@@ -1968,7 +1958,7 @@ ok: | |||
1968 | * to the stored lifetime since we'll | 1958 | * to the stored lifetime since we'll |
1969 | * be updating the timestamp below, | 1959 | * be updating the timestamp below, |
1970 | * else we'll set it back to the | 1960 | * else we'll set it back to the |
1971 | * minumum. | 1961 | * minimum. |
1972 | */ | 1962 | */ |
1973 | if (prefered_lft != ifp->prefered_lft) { | 1963 | if (prefered_lft != ifp->prefered_lft) { |
1974 | valid_lft = stored_lft; | 1964 | valid_lft = stored_lft; |
@@ -2022,10 +2012,11 @@ ok: | |||
2022 | ipv6_ifa_notify(0, ift); | 2012 | ipv6_ifa_notify(0, ift); |
2023 | } | 2013 | } |
2024 | 2014 | ||
2025 | if (create && in6_dev->cnf.use_tempaddr > 0) { | 2015 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { |
2026 | /* | 2016 | /* |
2027 | * When a new public address is created as described in [ADDRCONF], | 2017 | * When a new public address is created as described in [ADDRCONF], |
2028 | * also create a new temporary address. | 2018 | * also create a new temporary address. Also create a temporary |
2019 | * address if it's enabled but no temporary address currently exists. | ||
2029 | */ | 2020 | */ |
2030 | read_unlock_bh(&in6_dev->lock); | 2021 | read_unlock_bh(&in6_dev->lock); |
2031 | ipv6_create_tempaddr(ifp, NULL); | 2022 | ipv6_create_tempaddr(ifp, NULL); |
@@ -2110,7 +2101,7 @@ err_exit: | |||
2110 | /* | 2101 | /* |
2111 | * Manual configuration of address on an interface | 2102 | * Manual configuration of address on an interface |
2112 | */ | 2103 | */ |
2113 | static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | 2104 | static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, |
2114 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, | 2105 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, |
2115 | __u32 valid_lft) | 2106 | __u32 valid_lft) |
2116 | { | 2107 | { |
@@ -2184,7 +2175,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2184 | return PTR_ERR(ifp); | 2175 | return PTR_ERR(ifp); |
2185 | } | 2176 | } |
2186 | 2177 | ||
2187 | static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, | 2178 | static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx, |
2188 | unsigned int plen) | 2179 | unsigned int plen) |
2189 | { | 2180 | { |
2190 | struct inet6_ifaddr *ifp; | 2181 | struct inet6_ifaddr *ifp; |
@@ -2347,7 +2338,7 @@ static void init_loopback(struct net_device *dev) | |||
2347 | add_addr(idev, &in6addr_loopback, 128, IFA_HOST); | 2338 | add_addr(idev, &in6addr_loopback, 128, IFA_HOST); |
2348 | } | 2339 | } |
2349 | 2340 | ||
2350 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) | 2341 | static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) |
2351 | { | 2342 | { |
2352 | struct inet6_ifaddr * ifp; | 2343 | struct inet6_ifaddr * ifp; |
2353 | u32 addr_flags = IFA_F_PERMANENT; | 2344 | u32 addr_flags = IFA_F_PERMANENT; |
@@ -2657,8 +2648,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2657 | struct net *net = dev_net(dev); | 2648 | struct net *net = dev_net(dev); |
2658 | struct inet6_dev *idev; | 2649 | struct inet6_dev *idev; |
2659 | struct inet6_ifaddr *ifa; | 2650 | struct inet6_ifaddr *ifa; |
2660 | LIST_HEAD(keep_list); | 2651 | int state, i; |
2661 | int state; | ||
2662 | 2652 | ||
2663 | ASSERT_RTNL(); | 2653 | ASSERT_RTNL(); |
2664 | 2654 | ||
@@ -2684,6 +2674,23 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2684 | 2674 | ||
2685 | } | 2675 | } |
2686 | 2676 | ||
2677 | /* Step 2: clear hash table */ | ||
2678 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | ||
2679 | struct hlist_head *h = &inet6_addr_lst[i]; | ||
2680 | struct hlist_node *n; | ||
2681 | |||
2682 | spin_lock_bh(&addrconf_hash_lock); | ||
2683 | restart: | ||
2684 | hlist_for_each_entry_rcu(ifa, n, h, addr_lst) { | ||
2685 | if (ifa->idev == idev) { | ||
2686 | hlist_del_init_rcu(&ifa->addr_lst); | ||
2687 | addrconf_del_timer(ifa); | ||
2688 | goto restart; | ||
2689 | } | ||
2690 | } | ||
2691 | spin_unlock_bh(&addrconf_hash_lock); | ||
2692 | } | ||
2693 | |||
2687 | write_lock_bh(&idev->lock); | 2694 | write_lock_bh(&idev->lock); |
2688 | 2695 | ||
2689 | /* Step 2: clear flags for stateless addrconf */ | 2696 | /* Step 2: clear flags for stateless addrconf */ |
@@ -2717,61 +2724,24 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2717 | struct inet6_ifaddr, if_list); | 2724 | struct inet6_ifaddr, if_list); |
2718 | addrconf_del_timer(ifa); | 2725 | addrconf_del_timer(ifa); |
2719 | 2726 | ||
2720 | /* If just doing link down, and address is permanent | 2727 | list_del(&ifa->if_list); |
2721 | and not link-local, then retain it. */ | ||
2722 | if (!how && | ||
2723 | (ifa->flags&IFA_F_PERMANENT) && | ||
2724 | !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
2725 | list_move_tail(&ifa->if_list, &keep_list); | ||
2726 | |||
2727 | /* If not doing DAD on this address, just keep it. */ | ||
2728 | if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2729 | idev->cnf.accept_dad <= 0 || | ||
2730 | (ifa->flags & IFA_F_NODAD)) | ||
2731 | continue; | ||
2732 | |||
2733 | /* If it was tentative already, no need to notify */ | ||
2734 | if (ifa->flags & IFA_F_TENTATIVE) | ||
2735 | continue; | ||
2736 | 2728 | ||
2737 | /* Flag it for later restoration when link comes up */ | 2729 | write_unlock_bh(&idev->lock); |
2738 | ifa->flags |= IFA_F_TENTATIVE; | ||
2739 | ifa->state = INET6_IFADDR_STATE_DAD; | ||
2740 | |||
2741 | write_unlock_bh(&idev->lock); | ||
2742 | |||
2743 | in6_ifa_hold(ifa); | ||
2744 | } else { | ||
2745 | list_del(&ifa->if_list); | ||
2746 | |||
2747 | /* clear hash table */ | ||
2748 | spin_lock_bh(&addrconf_hash_lock); | ||
2749 | hlist_del_init_rcu(&ifa->addr_lst); | ||
2750 | spin_unlock_bh(&addrconf_hash_lock); | ||
2751 | 2730 | ||
2752 | write_unlock_bh(&idev->lock); | 2731 | spin_lock_bh(&ifa->state_lock); |
2753 | spin_lock_bh(&ifa->state_lock); | 2732 | state = ifa->state; |
2754 | state = ifa->state; | 2733 | ifa->state = INET6_IFADDR_STATE_DEAD; |
2755 | ifa->state = INET6_IFADDR_STATE_DEAD; | 2734 | spin_unlock_bh(&ifa->state_lock); |
2756 | spin_unlock_bh(&ifa->state_lock); | ||
2757 | 2735 | ||
2758 | if (state == INET6_IFADDR_STATE_DEAD) | 2736 | if (state != INET6_IFADDR_STATE_DEAD) { |
2759 | goto put_ifa; | 2737 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2738 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | ||
2760 | } | 2739 | } |
2761 | |||
2762 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | ||
2763 | if (ifa->state == INET6_IFADDR_STATE_DEAD) | ||
2764 | atomic_notifier_call_chain(&inet6addr_chain, | ||
2765 | NETDEV_DOWN, ifa); | ||
2766 | |||
2767 | put_ifa: | ||
2768 | in6_ifa_put(ifa); | 2740 | in6_ifa_put(ifa); |
2769 | 2741 | ||
2770 | write_lock_bh(&idev->lock); | 2742 | write_lock_bh(&idev->lock); |
2771 | } | 2743 | } |
2772 | 2744 | ||
2773 | list_splice(&keep_list, &idev->addr_list); | ||
2774 | |||
2775 | write_unlock_bh(&idev->lock); | 2745 | write_unlock_bh(&idev->lock); |
2776 | 2746 | ||
2777 | /* Step 5: Discard multicast list */ | 2747 | /* Step 5: Discard multicast list */ |
@@ -2964,7 +2934,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2964 | start sending router solicitations. | 2934 | start sending router solicitations. |
2965 | */ | 2935 | */ |
2966 | 2936 | ||
2967 | if (ifp->idev->cnf.forwarding == 0 && | 2937 | if ((ifp->idev->cnf.forwarding == 0 || |
2938 | ifp->idev->cnf.forwarding == 2) && | ||
2968 | ifp->idev->cnf.rtr_solicits > 0 && | 2939 | ifp->idev->cnf.rtr_solicits > 0 && |
2969 | (dev->flags&IFF_LOOPBACK) == 0 && | 2940 | (dev->flags&IFF_LOOPBACK) == 0 && |
2970 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 2941 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
@@ -3138,7 +3109,7 @@ void if6_proc_exit(void) | |||
3138 | 3109 | ||
3139 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 3110 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
3140 | /* Check if address is a home address configured on any interface. */ | 3111 | /* Check if address is a home address configured on any interface. */ |
3141 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | 3112 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) |
3142 | { | 3113 | { |
3143 | int ret = 0; | 3114 | int ret = 0; |
3144 | struct inet6_ifaddr *ifp = NULL; | 3115 | struct inet6_ifaddr *ifp = NULL; |
@@ -3448,10 +3419,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, | |||
3448 | { | 3419 | { |
3449 | struct ifa_cacheinfo ci; | 3420 | struct ifa_cacheinfo ci; |
3450 | 3421 | ||
3451 | ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 | 3422 | ci.cstamp = cstamp_delta(cstamp); |
3452 | + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | 3423 | ci.tstamp = cstamp_delta(tstamp); |
3453 | ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3454 | + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3455 | ci.ifa_prefered = preferred; | 3424 | ci.ifa_prefered = preferred; |
3456 | ci.ifa_valid = valid; | 3425 | ci.ifa_valid = valid; |
3457 | 3426 | ||
@@ -3802,8 +3771,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3802 | array[DEVCONF_AUTOCONF] = cnf->autoconf; | 3771 | array[DEVCONF_AUTOCONF] = cnf->autoconf; |
3803 | array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; | 3772 | array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; |
3804 | array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; | 3773 | array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; |
3805 | array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval; | 3774 | array[DEVCONF_RTR_SOLICIT_INTERVAL] = |
3806 | array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay; | 3775 | jiffies_to_msecs(cnf->rtr_solicit_interval); |
3776 | array[DEVCONF_RTR_SOLICIT_DELAY] = | ||
3777 | jiffies_to_msecs(cnf->rtr_solicit_delay); | ||
3807 | array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; | 3778 | array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; |
3808 | #ifdef CONFIG_IPV6_PRIVACY | 3779 | #ifdef CONFIG_IPV6_PRIVACY |
3809 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; | 3780 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; |
@@ -3817,7 +3788,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3817 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; | 3788 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; |
3818 | #ifdef CONFIG_IPV6_ROUTER_PREF | 3789 | #ifdef CONFIG_IPV6_ROUTER_PREF |
3819 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; | 3790 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; |
3820 | array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; | 3791 | array[DEVCONF_RTR_PROBE_INTERVAL] = |
3792 | jiffies_to_msecs(cnf->rtr_probe_interval); | ||
3821 | #ifdef CONFIG_IPV6_ROUTE_INFO | 3793 | #ifdef CONFIG_IPV6_ROUTE_INFO |
3822 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | 3794 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; |
3823 | #endif | 3795 | #endif |
@@ -3835,6 +3807,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3835 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 3807 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
3836 | } | 3808 | } |
3837 | 3809 | ||
3810 | static inline size_t inet6_ifla6_size(void) | ||
3811 | { | ||
3812 | return nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3813 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3814 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3815 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3816 | + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ | ||
3817 | } | ||
3818 | |||
3838 | static inline size_t inet6_if_nlmsg_size(void) | 3819 | static inline size_t inet6_if_nlmsg_size(void) |
3839 | { | 3820 | { |
3840 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 3821 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -3842,16 +3823,10 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3842 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ | 3823 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ |
3843 | + nla_total_size(4) /* IFLA_MTU */ | 3824 | + nla_total_size(4) /* IFLA_MTU */ |
3844 | + nla_total_size(4) /* IFLA_LINK */ | 3825 | + nla_total_size(4) /* IFLA_LINK */ |
3845 | + nla_total_size( /* IFLA_PROTINFO */ | 3826 | + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ |
3846 | nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3847 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3848 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3849 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3850 | + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ | ||
3851 | ); | ||
3852 | } | 3827 | } |
3853 | 3828 | ||
3854 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | 3829 | static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, |
3855 | int items, int bytes) | 3830 | int items, int bytes) |
3856 | { | 3831 | { |
3857 | int i; | 3832 | int i; |
@@ -3861,7 +3836,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | |||
3861 | /* Use put_unaligned() because stats may not be aligned for u64. */ | 3836 | /* Use put_unaligned() because stats may not be aligned for u64. */ |
3862 | put_unaligned(items, &stats[0]); | 3837 | put_unaligned(items, &stats[0]); |
3863 | for (i = 1; i < items; i++) | 3838 | for (i = 1; i < items; i++) |
3864 | put_unaligned(snmp_fold_field(mib, i), &stats[i]); | 3839 | put_unaligned(atomic_long_read(&mib[i]), &stats[i]); |
3865 | 3840 | ||
3866 | memset(&stats[items], 0, pad); | 3841 | memset(&stats[items], 0, pad); |
3867 | } | 3842 | } |
@@ -3890,20 +3865,75 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3890 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); | 3865 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); |
3891 | break; | 3866 | break; |
3892 | case IFLA_INET6_ICMP6STATS: | 3867 | case IFLA_INET6_ICMP6STATS: |
3893 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3868 | __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); |
3894 | break; | 3869 | break; |
3895 | } | 3870 | } |
3896 | } | 3871 | } |
3897 | 3872 | ||
3873 | static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | ||
3874 | { | ||
3875 | struct nlattr *nla; | ||
3876 | struct ifla_cacheinfo ci; | ||
3877 | |||
3878 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | ||
3879 | |||
3880 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3881 | ci.tstamp = cstamp_delta(idev->tstamp); | ||
3882 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | ||
3883 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | ||
3884 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3885 | |||
3886 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3887 | if (nla == NULL) | ||
3888 | goto nla_put_failure; | ||
3889 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3890 | |||
3891 | /* XXX - MC not implemented */ | ||
3892 | |||
3893 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3894 | if (nla == NULL) | ||
3895 | goto nla_put_failure; | ||
3896 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3897 | |||
3898 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3899 | if (nla == NULL) | ||
3900 | goto nla_put_failure; | ||
3901 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3902 | |||
3903 | return 0; | ||
3904 | |||
3905 | nla_put_failure: | ||
3906 | return -EMSGSIZE; | ||
3907 | } | ||
3908 | |||
3909 | static size_t inet6_get_link_af_size(const struct net_device *dev) | ||
3910 | { | ||
3911 | if (!__in6_dev_get(dev)) | ||
3912 | return 0; | ||
3913 | |||
3914 | return inet6_ifla6_size(); | ||
3915 | } | ||
3916 | |||
3917 | static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
3918 | { | ||
3919 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
3920 | |||
3921 | if (!idev) | ||
3922 | return -ENODATA; | ||
3923 | |||
3924 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) | ||
3925 | return -EMSGSIZE; | ||
3926 | |||
3927 | return 0; | ||
3928 | } | ||
3929 | |||
3898 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3930 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
3899 | u32 pid, u32 seq, int event, unsigned int flags) | 3931 | u32 pid, u32 seq, int event, unsigned int flags) |
3900 | { | 3932 | { |
3901 | struct net_device *dev = idev->dev; | 3933 | struct net_device *dev = idev->dev; |
3902 | struct nlattr *nla; | ||
3903 | struct ifinfomsg *hdr; | 3934 | struct ifinfomsg *hdr; |
3904 | struct nlmsghdr *nlh; | 3935 | struct nlmsghdr *nlh; |
3905 | void *protoinfo; | 3936 | void *protoinfo; |
3906 | struct ifla_cacheinfo ci; | ||
3907 | 3937 | ||
3908 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); | 3938 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
3909 | if (nlh == NULL) | 3939 | if (nlh == NULL) |
@@ -3930,31 +3960,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
3930 | if (protoinfo == NULL) | 3960 | if (protoinfo == NULL) |
3931 | goto nla_put_failure; | 3961 | goto nla_put_failure; |
3932 | 3962 | ||
3933 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | 3963 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) |
3934 | |||
3935 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3936 | ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3937 | + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3938 | ci.reachable_time = idev->nd_parms->reachable_time; | ||
3939 | ci.retrans_time = idev->nd_parms->retrans_time; | ||
3940 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3941 | |||
3942 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3943 | if (nla == NULL) | ||
3944 | goto nla_put_failure; | ||
3945 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3946 | |||
3947 | /* XXX - MC not implemented */ | ||
3948 | |||
3949 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3950 | if (nla == NULL) | ||
3951 | goto nla_put_failure; | ||
3952 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3953 | |||
3954 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3955 | if (nla == NULL) | ||
3956 | goto nla_put_failure; | 3964 | goto nla_put_failure; |
3957 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3958 | 3965 | ||
3959 | nla_nest_end(skb, protoinfo); | 3966 | nla_nest_end(skb, protoinfo); |
3960 | return nlmsg_end(skb, nlh); | 3967 | return nlmsg_end(skb, nlh); |
@@ -4021,11 +4028,11 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | |||
4021 | kfree_skb(skb); | 4028 | kfree_skb(skb); |
4022 | goto errout; | 4029 | goto errout; |
4023 | } | 4030 | } |
4024 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 4031 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC); |
4025 | return; | 4032 | return; |
4026 | errout: | 4033 | errout: |
4027 | if (err < 0) | 4034 | if (err < 0) |
4028 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); | 4035 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err); |
4029 | } | 4036 | } |
4030 | 4037 | ||
4031 | static inline size_t inet6_prefix_nlmsg_size(void) | 4038 | static inline size_t inet6_prefix_nlmsg_size(void) |
@@ -4122,8 +4129,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4122 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 4129 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
4123 | dst_hold(&ifp->rt->dst); | 4130 | dst_hold(&ifp->rt->dst); |
4124 | 4131 | ||
4125 | if (ifp->state == INET6_IFADDR_STATE_DEAD && | 4132 | if (ip6_del_rt(ifp->rt)) |
4126 | ip6_del_rt(ifp->rt)) | ||
4127 | dst_free(&ifp->rt->dst); | 4133 | dst_free(&ifp->rt->dst); |
4128 | break; | 4134 | break; |
4129 | } | 4135 | } |
@@ -4521,7 +4527,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4521 | 4527 | ||
4522 | t = p->sysctl; | 4528 | t = p->sysctl; |
4523 | p->sysctl = NULL; | 4529 | p->sysctl = NULL; |
4524 | unregister_sysctl_table(t->sysctl_header); | 4530 | unregister_net_sysctl_table(t->sysctl_header); |
4525 | kfree(t->dev_name); | 4531 | kfree(t->dev_name); |
4526 | kfree(t); | 4532 | kfree(t); |
4527 | } | 4533 | } |
@@ -4625,6 +4631,12 @@ int unregister_inet6addr_notifier(struct notifier_block *nb) | |||
4625 | } | 4631 | } |
4626 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4632 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
4627 | 4633 | ||
4634 | static struct rtnl_af_ops inet6_ops = { | ||
4635 | .family = AF_INET6, | ||
4636 | .fill_link_af = inet6_fill_link_af, | ||
4637 | .get_link_af_size = inet6_get_link_af_size, | ||
4638 | }; | ||
4639 | |||
4628 | /* | 4640 | /* |
4629 | * Init / cleanup code | 4641 | * Init / cleanup code |
4630 | */ | 4642 | */ |
@@ -4676,6 +4688,10 @@ int __init addrconf_init(void) | |||
4676 | 4688 | ||
4677 | addrconf_verify(0); | 4689 | addrconf_verify(0); |
4678 | 4690 | ||
4691 | err = rtnl_af_register(&inet6_ops); | ||
4692 | if (err < 0) | ||
4693 | goto errout_af; | ||
4694 | |||
4679 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); | 4695 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); |
4680 | if (err < 0) | 4696 | if (err < 0) |
4681 | goto errout; | 4697 | goto errout; |
@@ -4691,6 +4707,8 @@ int __init addrconf_init(void) | |||
4691 | 4707 | ||
4692 | return 0; | 4708 | return 0; |
4693 | errout: | 4709 | errout: |
4710 | rtnl_af_unregister(&inet6_ops); | ||
4711 | errout_af: | ||
4694 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4712 | unregister_netdevice_notifier(&ipv6_dev_notf); |
4695 | errlo: | 4713 | errlo: |
4696 | unregister_pernet_subsys(&addrconf_ops); | 4714 | unregister_pernet_subsys(&addrconf_ops); |
@@ -4711,6 +4729,8 @@ void addrconf_cleanup(void) | |||
4711 | 4729 | ||
4712 | rtnl_lock(); | 4730 | rtnl_lock(); |
4713 | 4731 | ||
4732 | __rtnl_af_unregister(&inet6_ops); | ||
4733 | |||
4714 | /* clean dev list */ | 4734 | /* clean dev list */ |
4715 | for_each_netdev(&init_net, dev) { | 4735 | for_each_netdev(&init_net, dev) { |
4716 | if (__in6_dev_get(dev) == NULL) | 4736 | if (__in6_dev_get(dev) == NULL) |