diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 177 |
1 files changed, 162 insertions, 15 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0424e4e27414..fab23db8ee73 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <net/pkt_sched.h> | 81 | #include <net/pkt_sched.h> |
82 | #include <linux/if_tunnel.h> | 82 | #include <linux/if_tunnel.h> |
83 | #include <linux/rtnetlink.h> | 83 | #include <linux/rtnetlink.h> |
84 | #include <linux/netconf.h> | ||
84 | 85 | ||
85 | #ifdef CONFIG_IPV6_PRIVACY | 86 | #ifdef CONFIG_IPV6_PRIVACY |
86 | #include <linux/random.h> | 87 | #include <linux/random.h> |
@@ -401,7 +402,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
401 | if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) | 402 | if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) |
402 | ndev->cnf.accept_dad = -1; | 403 | ndev->cnf.accept_dad = -1; |
403 | 404 | ||
404 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 405 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
405 | if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { | 406 | if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { |
406 | pr_info("%s: Disabled Multicast RS\n", dev->name); | 407 | pr_info("%s: Disabled Multicast RS\n", dev->name); |
407 | ndev->cnf.rtr_solicits = 0; | 408 | ndev->cnf.rtr_solicits = 0; |
@@ -460,6 +461,141 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev) | |||
460 | return idev; | 461 | return idev; |
461 | } | 462 | } |
462 | 463 | ||
464 | static int inet6_netconf_msgsize_devconf(int type) | ||
465 | { | ||
466 | int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) | ||
467 | + nla_total_size(4); /* NETCONFA_IFINDEX */ | ||
468 | |||
469 | /* type -1 is used for ALL */ | ||
470 | if (type == -1 || type == NETCONFA_FORWARDING) | ||
471 | size += nla_total_size(4); | ||
472 | |||
473 | return size; | ||
474 | } | ||
475 | |||
476 | static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | ||
477 | struct ipv6_devconf *devconf, u32 portid, | ||
478 | u32 seq, int event, unsigned int flags, | ||
479 | int type) | ||
480 | { | ||
481 | struct nlmsghdr *nlh; | ||
482 | struct netconfmsg *ncm; | ||
483 | |||
484 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), | ||
485 | flags); | ||
486 | if (nlh == NULL) | ||
487 | return -EMSGSIZE; | ||
488 | |||
489 | ncm = nlmsg_data(nlh); | ||
490 | ncm->ncm_family = AF_INET6; | ||
491 | |||
492 | if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) | ||
493 | goto nla_put_failure; | ||
494 | |||
495 | /* type -1 is used for ALL */ | ||
496 | if ((type == -1 || type == NETCONFA_FORWARDING) && | ||
497 | nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) | ||
498 | goto nla_put_failure; | ||
499 | |||
500 | return nlmsg_end(skb, nlh); | ||
501 | |||
502 | nla_put_failure: | ||
503 | nlmsg_cancel(skb, nlh); | ||
504 | return -EMSGSIZE; | ||
505 | } | ||
506 | |||
507 | static void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, | ||
508 | struct ipv6_devconf *devconf) | ||
509 | { | ||
510 | struct sk_buff *skb; | ||
511 | int err = -ENOBUFS; | ||
512 | |||
513 | skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_ATOMIC); | ||
514 | if (skb == NULL) | ||
515 | goto errout; | ||
516 | |||
517 | err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, | ||
518 | RTM_NEWNETCONF, 0, type); | ||
519 | if (err < 0) { | ||
520 | /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ | ||
521 | WARN_ON(err == -EMSGSIZE); | ||
522 | kfree_skb(skb); | ||
523 | goto errout; | ||
524 | } | ||
525 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC); | ||
526 | return; | ||
527 | errout: | ||
528 | if (err < 0) | ||
529 | rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); | ||
530 | } | ||
531 | |||
532 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | ||
533 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | ||
534 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | ||
535 | }; | ||
536 | |||
537 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | ||
538 | struct nlmsghdr *nlh, | ||
539 | void *arg) | ||
540 | { | ||
541 | struct net *net = sock_net(in_skb->sk); | ||
542 | struct nlattr *tb[NETCONFA_MAX+1]; | ||
543 | struct netconfmsg *ncm; | ||
544 | struct sk_buff *skb; | ||
545 | struct ipv6_devconf *devconf; | ||
546 | struct inet6_dev *in6_dev; | ||
547 | struct net_device *dev; | ||
548 | int ifindex; | ||
549 | int err; | ||
550 | |||
551 | err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, | ||
552 | devconf_ipv6_policy); | ||
553 | if (err < 0) | ||
554 | goto errout; | ||
555 | |||
556 | err = EINVAL; | ||
557 | if (!tb[NETCONFA_IFINDEX]) | ||
558 | goto errout; | ||
559 | |||
560 | ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); | ||
561 | switch (ifindex) { | ||
562 | case NETCONFA_IFINDEX_ALL: | ||
563 | devconf = net->ipv6.devconf_all; | ||
564 | break; | ||
565 | case NETCONFA_IFINDEX_DEFAULT: | ||
566 | devconf = net->ipv6.devconf_dflt; | ||
567 | break; | ||
568 | default: | ||
569 | dev = __dev_get_by_index(net, ifindex); | ||
570 | if (dev == NULL) | ||
571 | goto errout; | ||
572 | in6_dev = __in6_dev_get(dev); | ||
573 | if (in6_dev == NULL) | ||
574 | goto errout; | ||
575 | devconf = &in6_dev->cnf; | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | err = -ENOBUFS; | ||
580 | skb = nlmsg_new(inet6_netconf_msgsize_devconf(-1), GFP_ATOMIC); | ||
581 | if (skb == NULL) | ||
582 | goto errout; | ||
583 | |||
584 | err = inet6_netconf_fill_devconf(skb, ifindex, devconf, | ||
585 | NETLINK_CB(in_skb).portid, | ||
586 | nlh->nlmsg_seq, RTM_NEWNETCONF, 0, | ||
587 | -1); | ||
588 | if (err < 0) { | ||
589 | /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ | ||
590 | WARN_ON(err == -EMSGSIZE); | ||
591 | kfree_skb(skb); | ||
592 | goto errout; | ||
593 | } | ||
594 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); | ||
595 | errout: | ||
596 | return err; | ||
597 | } | ||
598 | |||
463 | #ifdef CONFIG_SYSCTL | 599 | #ifdef CONFIG_SYSCTL |
464 | static void dev_forward_change(struct inet6_dev *idev) | 600 | static void dev_forward_change(struct inet6_dev *idev) |
465 | { | 601 | { |
@@ -471,7 +607,7 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
471 | dev = idev->dev; | 607 | dev = idev->dev; |
472 | if (idev->cnf.forwarding) | 608 | if (idev->cnf.forwarding) |
473 | dev_disable_lro(dev); | 609 | dev_disable_lro(dev); |
474 | if (dev && (dev->flags & IFF_MULTICAST)) { | 610 | if (dev->flags & IFF_MULTICAST) { |
475 | if (idev->cnf.forwarding) | 611 | if (idev->cnf.forwarding) |
476 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); | 612 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); |
477 | else | 613 | else |
@@ -486,6 +622,8 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
486 | else | 622 | else |
487 | addrconf_leave_anycast(ifa); | 623 | addrconf_leave_anycast(ifa); |
488 | } | 624 | } |
625 | inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING, | ||
626 | dev->ifindex, &idev->cnf); | ||
489 | } | 627 | } |
490 | 628 | ||
491 | 629 | ||
@@ -518,6 +656,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) | |||
518 | *p = newf; | 656 | *p = newf; |
519 | 657 | ||
520 | if (p == &net->ipv6.devconf_dflt->forwarding) { | 658 | if (p == &net->ipv6.devconf_dflt->forwarding) { |
659 | if ((!newf) ^ (!old)) | ||
660 | inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, | ||
661 | NETCONFA_IFINDEX_DEFAULT, | ||
662 | net->ipv6.devconf_dflt); | ||
521 | rtnl_unlock(); | 663 | rtnl_unlock(); |
522 | return 0; | 664 | return 0; |
523 | } | 665 | } |
@@ -525,6 +667,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) | |||
525 | if (p == &net->ipv6.devconf_all->forwarding) { | 667 | if (p == &net->ipv6.devconf_all->forwarding) { |
526 | net->ipv6.devconf_dflt->forwarding = newf; | 668 | net->ipv6.devconf_dflt->forwarding = newf; |
527 | addrconf_forward_change(net, newf); | 669 | addrconf_forward_change(net, newf); |
670 | if ((!newf) ^ (!old)) | ||
671 | inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, | ||
672 | NETCONFA_IFINDEX_ALL, | ||
673 | net->ipv6.devconf_all); | ||
528 | } else if ((!newf) ^ (!old)) | 674 | } else if ((!newf) ^ (!old)) |
529 | dev_forward_change((struct inet6_dev *)table->extra1); | 675 | dev_forward_change((struct inet6_dev *)table->extra1); |
530 | rtnl_unlock(); | 676 | rtnl_unlock(); |
@@ -553,7 +699,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
553 | pr_warn("Freeing alive inet6 address %p\n", ifp); | 699 | pr_warn("Freeing alive inet6 address %p\n", ifp); |
554 | return; | 700 | return; |
555 | } | 701 | } |
556 | dst_release(&ifp->rt->dst); | 702 | ip6_rt_put(ifp->rt); |
557 | 703 | ||
558 | kfree_rcu(ifp, rcu); | 704 | kfree_rcu(ifp, rcu); |
559 | } | 705 | } |
@@ -805,7 +951,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
805 | rt6_set_expires(rt, expires); | 951 | rt6_set_expires(rt, expires); |
806 | } | 952 | } |
807 | } | 953 | } |
808 | dst_release(&rt->dst); | 954 | ip6_rt_put(rt); |
809 | } | 955 | } |
810 | 956 | ||
811 | /* clean up prefsrc entries */ | 957 | /* clean up prefsrc entries */ |
@@ -1692,7 +1838,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, | |||
1692 | This thing is done here expecting that the whole | 1838 | This thing is done here expecting that the whole |
1693 | class of non-broadcast devices need not cloning. | 1839 | class of non-broadcast devices need not cloning. |
1694 | */ | 1840 | */ |
1695 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 1841 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
1696 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) | 1842 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
1697 | cfg.fc_flags |= RTF_NONEXTHOP; | 1843 | cfg.fc_flags |= RTF_NONEXTHOP; |
1698 | #endif | 1844 | #endif |
@@ -1752,7 +1898,7 @@ static void addrconf_add_mroute(struct net_device *dev) | |||
1752 | ip6_route_add(&cfg); | 1898 | ip6_route_add(&cfg); |
1753 | } | 1899 | } |
1754 | 1900 | ||
1755 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 1901 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
1756 | static void sit_route_add(struct net_device *dev) | 1902 | static void sit_route_add(struct net_device *dev) |
1757 | { | 1903 | { |
1758 | struct fib6_config cfg = { | 1904 | struct fib6_config cfg = { |
@@ -1881,8 +2027,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | |||
1881 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, | 2027 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, |
1882 | dev, expires, flags); | 2028 | dev, expires, flags); |
1883 | } | 2029 | } |
1884 | if (rt) | 2030 | ip6_rt_put(rt); |
1885 | dst_release(&rt->dst); | ||
1886 | } | 2031 | } |
1887 | 2032 | ||
1888 | /* Try to figure out our local address for this prefix */ | 2033 | /* Try to figure out our local address for this prefix */ |
@@ -2104,7 +2249,7 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg) | |||
2104 | if (dev == NULL) | 2249 | if (dev == NULL) |
2105 | goto err_exit; | 2250 | goto err_exit; |
2106 | 2251 | ||
2107 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2252 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
2108 | if (dev->type == ARPHRD_SIT) { | 2253 | if (dev->type == ARPHRD_SIT) { |
2109 | const struct net_device_ops *ops = dev->netdev_ops; | 2254 | const struct net_device_ops *ops = dev->netdev_ops; |
2110 | struct ifreq ifr; | 2255 | struct ifreq ifr; |
@@ -2315,7 +2460,7 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
2315 | } | 2460 | } |
2316 | } | 2461 | } |
2317 | 2462 | ||
2318 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2463 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
2319 | static void sit_add_v4_addrs(struct inet6_dev *idev) | 2464 | static void sit_add_v4_addrs(struct inet6_dev *idev) |
2320 | { | 2465 | { |
2321 | struct in6_addr addr; | 2466 | struct in6_addr addr; |
@@ -2434,7 +2579,7 @@ static void addrconf_dev_config(struct net_device *dev) | |||
2434 | addrconf_add_linklocal(idev, &addr); | 2579 | addrconf_add_linklocal(idev, &addr); |
2435 | } | 2580 | } |
2436 | 2581 | ||
2437 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2582 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
2438 | static void addrconf_sit_config(struct net_device *dev) | 2583 | static void addrconf_sit_config(struct net_device *dev) |
2439 | { | 2584 | { |
2440 | struct inet6_dev *idev; | 2585 | struct inet6_dev *idev; |
@@ -2471,7 +2616,7 @@ static void addrconf_sit_config(struct net_device *dev) | |||
2471 | } | 2616 | } |
2472 | #endif | 2617 | #endif |
2473 | 2618 | ||
2474 | #if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE) | 2619 | #if IS_ENABLED(CONFIG_NET_IPGRE) |
2475 | static void addrconf_gre_config(struct net_device *dev) | 2620 | static void addrconf_gre_config(struct net_device *dev) |
2476 | { | 2621 | { |
2477 | struct inet6_dev *idev; | 2622 | struct inet6_dev *idev; |
@@ -2601,12 +2746,12 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2601 | } | 2746 | } |
2602 | 2747 | ||
2603 | switch (dev->type) { | 2748 | switch (dev->type) { |
2604 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2749 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
2605 | case ARPHRD_SIT: | 2750 | case ARPHRD_SIT: |
2606 | addrconf_sit_config(dev); | 2751 | addrconf_sit_config(dev); |
2607 | break; | 2752 | break; |
2608 | #endif | 2753 | #endif |
2609 | #if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE) | 2754 | #if IS_ENABLED(CONFIG_NET_IPGRE) |
2610 | case ARPHRD_IPGRE: | 2755 | case ARPHRD_IPGRE: |
2611 | addrconf_gre_config(dev); | 2756 | addrconf_gre_config(dev); |
2612 | break; | 2757 | break; |
@@ -3194,7 +3339,7 @@ void if6_proc_exit(void) | |||
3194 | } | 3339 | } |
3195 | #endif /* CONFIG_PROC_FS */ | 3340 | #endif /* CONFIG_PROC_FS */ |
3196 | 3341 | ||
3197 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 3342 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
3198 | /* Check if address is a home address configured on any interface. */ | 3343 | /* Check if address is a home address configured on any interface. */ |
3199 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) | 3344 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) |
3200 | { | 3345 | { |
@@ -4784,6 +4929,8 @@ int __init addrconf_init(void) | |||
4784 | inet6_dump_ifmcaddr, NULL); | 4929 | inet6_dump_ifmcaddr, NULL); |
4785 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, | 4930 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, |
4786 | inet6_dump_ifacaddr, NULL); | 4931 | inet6_dump_ifacaddr, NULL); |
4932 | __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, | ||
4933 | NULL, NULL); | ||
4787 | 4934 | ||
4788 | ipv6_addr_label_rtnl_register(); | 4935 | ipv6_addr_label_rtnl_register(); |
4789 | 4936 | ||