diff options
Diffstat (limited to 'net/ipv6')
44 files changed, 2186 insertions, 1041 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index b6d3f79151e2..2068ac4fbdad 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -7,9 +7,11 @@ obj-$(CONFIG_IPV6) += ipv6.o | |||
| 7 | ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ | 7 | ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ |
| 8 | addrlabel.o \ | 8 | addrlabel.o \ |
| 9 | route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ | 9 | route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ |
| 10 | raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ | 10 | raw.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ |
| 11 | exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o | 11 | exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o |
| 12 | 12 | ||
| 13 | ipv6-offload := ip6_offload.o tcpv6_offload.o udp_offload.o exthdrs_offload.o | ||
| 14 | |||
| 13 | ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o | 15 | ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o |
| 14 | ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o | 16 | ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o |
| 15 | 17 | ||
| @@ -39,5 +41,6 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | |||
| 39 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
| 40 | 42 | ||
| 41 | obj-y += addrconf_core.o exthdrs_core.o | 43 | obj-y += addrconf_core.o exthdrs_core.o |
| 44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6_offload) | ||
| 42 | 45 | ||
| 43 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0424e4e27414..6fca01f136ad 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,150 @@ 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 | #ifdef CONFIG_IPV6_MROUTE | ||
| 473 | if (type == -1 || type == NETCONFA_MC_FORWARDING) | ||
| 474 | size += nla_total_size(4); | ||
| 475 | #endif | ||
| 476 | |||
| 477 | return size; | ||
| 478 | } | ||
| 479 | |||
| 480 | static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | ||
| 481 | struct ipv6_devconf *devconf, u32 portid, | ||
| 482 | u32 seq, int event, unsigned int flags, | ||
| 483 | int type) | ||
| 484 | { | ||
| 485 | struct nlmsghdr *nlh; | ||
| 486 | struct netconfmsg *ncm; | ||
| 487 | |||
| 488 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), | ||
| 489 | flags); | ||
| 490 | if (nlh == NULL) | ||
| 491 | return -EMSGSIZE; | ||
| 492 | |||
| 493 | ncm = nlmsg_data(nlh); | ||
| 494 | ncm->ncm_family = AF_INET6; | ||
| 495 | |||
| 496 | if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) | ||
| 497 | goto nla_put_failure; | ||
| 498 | |||
| 499 | /* type -1 is used for ALL */ | ||
| 500 | if ((type == -1 || type == NETCONFA_FORWARDING) && | ||
| 501 | nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) | ||
| 502 | goto nla_put_failure; | ||
| 503 | #ifdef CONFIG_IPV6_MROUTE | ||
| 504 | if ((type == -1 || type == NETCONFA_MC_FORWARDING) && | ||
| 505 | nla_put_s32(skb, NETCONFA_MC_FORWARDING, | ||
| 506 | devconf->mc_forwarding) < 0) | ||
| 507 | goto nla_put_failure; | ||
| 508 | #endif | ||
| 509 | return nlmsg_end(skb, nlh); | ||
| 510 | |||
| 511 | nla_put_failure: | ||
| 512 | nlmsg_cancel(skb, nlh); | ||
| 513 | return -EMSGSIZE; | ||
| 514 | } | ||
| 515 | |||
| 516 | void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, | ||
| 517 | struct ipv6_devconf *devconf) | ||
| 518 | { | ||
| 519 | struct sk_buff *skb; | ||
| 520 | int err = -ENOBUFS; | ||
| 521 | |||
| 522 | skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_ATOMIC); | ||
| 523 | if (skb == NULL) | ||
| 524 | goto errout; | ||
| 525 | |||
| 526 | err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, | ||
| 527 | RTM_NEWNETCONF, 0, type); | ||
| 528 | if (err < 0) { | ||
| 529 | /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ | ||
| 530 | WARN_ON(err == -EMSGSIZE); | ||
| 531 | kfree_skb(skb); | ||
| 532 | goto errout; | ||
| 533 | } | ||
| 534 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC); | ||
| 535 | return; | ||
| 536 | errout: | ||
| 537 | if (err < 0) | ||
| 538 | rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); | ||
| 539 | } | ||
| 540 | |||
| 541 | static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { | ||
| 542 | [NETCONFA_IFINDEX] = { .len = sizeof(int) }, | ||
| 543 | [NETCONFA_FORWARDING] = { .len = sizeof(int) }, | ||
| 544 | }; | ||
| 545 | |||
| 546 | static int inet6_netconf_get_devconf(struct sk_buff *in_skb, | ||
| 547 | struct nlmsghdr *nlh, | ||
| 548 | void *arg) | ||
| 549 | { | ||
| 550 | struct net *net = sock_net(in_skb->sk); | ||
| 551 | struct nlattr *tb[NETCONFA_MAX+1]; | ||
| 552 | struct netconfmsg *ncm; | ||
| 553 | struct sk_buff *skb; | ||
| 554 | struct ipv6_devconf *devconf; | ||
| 555 | struct inet6_dev *in6_dev; | ||
| 556 | struct net_device *dev; | ||
| 557 | int ifindex; | ||
| 558 | int err; | ||
| 559 | |||
| 560 | err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, | ||
| 561 | devconf_ipv6_policy); | ||
| 562 | if (err < 0) | ||
| 563 | goto errout; | ||
| 564 | |||
| 565 | err = EINVAL; | ||
| 566 | if (!tb[NETCONFA_IFINDEX]) | ||
| 567 | goto errout; | ||
| 568 | |||
| 569 | ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); | ||
| 570 | switch (ifindex) { | ||
| 571 | case NETCONFA_IFINDEX_ALL: | ||
| 572 | devconf = net->ipv6.devconf_all; | ||
| 573 | break; | ||
| 574 | case NETCONFA_IFINDEX_DEFAULT: | ||
| 575 | devconf = net->ipv6.devconf_dflt; | ||
| 576 | break; | ||
| 577 | default: | ||
| 578 | dev = __dev_get_by_index(net, ifindex); | ||
| 579 | if (dev == NULL) | ||
| 580 | goto errout; | ||
| 581 | in6_dev = __in6_dev_get(dev); | ||
| 582 | if (in6_dev == NULL) | ||
| 583 | goto errout; | ||
| 584 | devconf = &in6_dev->cnf; | ||
| 585 | break; | ||
| 586 | } | ||
| 587 | |||
| 588 | err = -ENOBUFS; | ||
| 589 | skb = nlmsg_new(inet6_netconf_msgsize_devconf(-1), GFP_ATOMIC); | ||
| 590 | if (skb == NULL) | ||
| 591 | goto errout; | ||
| 592 | |||
| 593 | err = inet6_netconf_fill_devconf(skb, ifindex, devconf, | ||
| 594 | NETLINK_CB(in_skb).portid, | ||
| 595 | nlh->nlmsg_seq, RTM_NEWNETCONF, 0, | ||
| 596 | -1); | ||
| 597 | if (err < 0) { | ||
| 598 | /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ | ||
| 599 | WARN_ON(err == -EMSGSIZE); | ||
| 600 | kfree_skb(skb); | ||
| 601 | goto errout; | ||
| 602 | } | ||
| 603 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); | ||
| 604 | errout: | ||
| 605 | return err; | ||
| 606 | } | ||
| 607 | |||
| 463 | #ifdef CONFIG_SYSCTL | 608 | #ifdef CONFIG_SYSCTL |
| 464 | static void dev_forward_change(struct inet6_dev *idev) | 609 | static void dev_forward_change(struct inet6_dev *idev) |
| 465 | { | 610 | { |
| @@ -471,7 +616,7 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
| 471 | dev = idev->dev; | 616 | dev = idev->dev; |
| 472 | if (idev->cnf.forwarding) | 617 | if (idev->cnf.forwarding) |
| 473 | dev_disable_lro(dev); | 618 | dev_disable_lro(dev); |
| 474 | if (dev && (dev->flags & IFF_MULTICAST)) { | 619 | if (dev->flags & IFF_MULTICAST) { |
| 475 | if (idev->cnf.forwarding) | 620 | if (idev->cnf.forwarding) |
| 476 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); | 621 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); |
| 477 | else | 622 | else |
| @@ -486,6 +631,8 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
| 486 | else | 631 | else |
| 487 | addrconf_leave_anycast(ifa); | 632 | addrconf_leave_anycast(ifa); |
| 488 | } | 633 | } |
| 634 | inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING, | ||
| 635 | dev->ifindex, &idev->cnf); | ||
| 489 | } | 636 | } |
| 490 | 637 | ||
| 491 | 638 | ||
| @@ -518,6 +665,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) | |||
| 518 | *p = newf; | 665 | *p = newf; |
| 519 | 666 | ||
| 520 | if (p == &net->ipv6.devconf_dflt->forwarding) { | 667 | if (p == &net->ipv6.devconf_dflt->forwarding) { |
| 668 | if ((!newf) ^ (!old)) | ||
| 669 | inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, | ||
| 670 | NETCONFA_IFINDEX_DEFAULT, | ||
| 671 | net->ipv6.devconf_dflt); | ||
| 521 | rtnl_unlock(); | 672 | rtnl_unlock(); |
| 522 | return 0; | 673 | return 0; |
| 523 | } | 674 | } |
| @@ -525,6 +676,10 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) | |||
| 525 | if (p == &net->ipv6.devconf_all->forwarding) { | 676 | if (p == &net->ipv6.devconf_all->forwarding) { |
| 526 | net->ipv6.devconf_dflt->forwarding = newf; | 677 | net->ipv6.devconf_dflt->forwarding = newf; |
| 527 | addrconf_forward_change(net, newf); | 678 | addrconf_forward_change(net, newf); |
| 679 | if ((!newf) ^ (!old)) | ||
| 680 | inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, | ||
| 681 | NETCONFA_IFINDEX_ALL, | ||
| 682 | net->ipv6.devconf_all); | ||
| 528 | } else if ((!newf) ^ (!old)) | 683 | } else if ((!newf) ^ (!old)) |
| 529 | dev_forward_change((struct inet6_dev *)table->extra1); | 684 | dev_forward_change((struct inet6_dev *)table->extra1); |
| 530 | rtnl_unlock(); | 685 | rtnl_unlock(); |
| @@ -553,7 +708,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
| 553 | pr_warn("Freeing alive inet6 address %p\n", ifp); | 708 | pr_warn("Freeing alive inet6 address %p\n", ifp); |
| 554 | return; | 709 | return; |
| 555 | } | 710 | } |
| 556 | dst_release(&ifp->rt->dst); | 711 | ip6_rt_put(ifp->rt); |
| 557 | 712 | ||
| 558 | kfree_rcu(ifp, rcu); | 713 | kfree_rcu(ifp, rcu); |
| 559 | } | 714 | } |
| @@ -805,7 +960,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 805 | rt6_set_expires(rt, expires); | 960 | rt6_set_expires(rt, expires); |
| 806 | } | 961 | } |
| 807 | } | 962 | } |
| 808 | dst_release(&rt->dst); | 963 | ip6_rt_put(rt); |
| 809 | } | 964 | } |
| 810 | 965 | ||
| 811 | /* clean up prefsrc entries */ | 966 | /* clean up prefsrc entries */ |
| @@ -1692,7 +1847,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, | |||
| 1692 | This thing is done here expecting that the whole | 1847 | This thing is done here expecting that the whole |
| 1693 | class of non-broadcast devices need not cloning. | 1848 | class of non-broadcast devices need not cloning. |
| 1694 | */ | 1849 | */ |
| 1695 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 1850 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 1696 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) | 1851 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
| 1697 | cfg.fc_flags |= RTF_NONEXTHOP; | 1852 | cfg.fc_flags |= RTF_NONEXTHOP; |
| 1698 | #endif | 1853 | #endif |
| @@ -1752,7 +1907,7 @@ static void addrconf_add_mroute(struct net_device *dev) | |||
| 1752 | ip6_route_add(&cfg); | 1907 | ip6_route_add(&cfg); |
| 1753 | } | 1908 | } |
| 1754 | 1909 | ||
| 1755 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 1910 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 1756 | static void sit_route_add(struct net_device *dev) | 1911 | static void sit_route_add(struct net_device *dev) |
| 1757 | { | 1912 | { |
| 1758 | struct fib6_config cfg = { | 1913 | struct fib6_config cfg = { |
| @@ -1881,8 +2036,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | |||
| 1881 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, | 2036 | addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, |
| 1882 | dev, expires, flags); | 2037 | dev, expires, flags); |
| 1883 | } | 2038 | } |
| 1884 | if (rt) | 2039 | ip6_rt_put(rt); |
| 1885 | dst_release(&rt->dst); | ||
| 1886 | } | 2040 | } |
| 1887 | 2041 | ||
| 1888 | /* Try to figure out our local address for this prefix */ | 2042 | /* Try to figure out our local address for this prefix */ |
| @@ -2104,7 +2258,7 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg) | |||
| 2104 | if (dev == NULL) | 2258 | if (dev == NULL) |
| 2105 | goto err_exit; | 2259 | goto err_exit; |
| 2106 | 2260 | ||
| 2107 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2261 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 2108 | if (dev->type == ARPHRD_SIT) { | 2262 | if (dev->type == ARPHRD_SIT) { |
| 2109 | const struct net_device_ops *ops = dev->netdev_ops; | 2263 | const struct net_device_ops *ops = dev->netdev_ops; |
| 2110 | struct ifreq ifr; | 2264 | struct ifreq ifr; |
| @@ -2268,7 +2422,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg) | |||
| 2268 | struct in6_ifreq ireq; | 2422 | struct in6_ifreq ireq; |
| 2269 | int err; | 2423 | int err; |
| 2270 | 2424 | ||
| 2271 | if (!capable(CAP_NET_ADMIN)) | 2425 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 2272 | return -EPERM; | 2426 | return -EPERM; |
| 2273 | 2427 | ||
| 2274 | if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) | 2428 | if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) |
| @@ -2287,7 +2441,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg) | |||
| 2287 | struct in6_ifreq ireq; | 2441 | struct in6_ifreq ireq; |
| 2288 | int err; | 2442 | int err; |
| 2289 | 2443 | ||
| 2290 | if (!capable(CAP_NET_ADMIN)) | 2444 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 2291 | return -EPERM; | 2445 | return -EPERM; |
| 2292 | 2446 | ||
| 2293 | if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) | 2447 | if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) |
| @@ -2315,7 +2469,7 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
| 2315 | } | 2469 | } |
| 2316 | } | 2470 | } |
| 2317 | 2471 | ||
| 2318 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2472 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 2319 | static void sit_add_v4_addrs(struct inet6_dev *idev) | 2473 | static void sit_add_v4_addrs(struct inet6_dev *idev) |
| 2320 | { | 2474 | { |
| 2321 | struct in6_addr addr; | 2475 | struct in6_addr addr; |
| @@ -2434,7 +2588,7 @@ static void addrconf_dev_config(struct net_device *dev) | |||
| 2434 | addrconf_add_linklocal(idev, &addr); | 2588 | addrconf_add_linklocal(idev, &addr); |
| 2435 | } | 2589 | } |
| 2436 | 2590 | ||
| 2437 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2591 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 2438 | static void addrconf_sit_config(struct net_device *dev) | 2592 | static void addrconf_sit_config(struct net_device *dev) |
| 2439 | { | 2593 | { |
| 2440 | struct inet6_dev *idev; | 2594 | struct inet6_dev *idev; |
| @@ -2471,7 +2625,7 @@ static void addrconf_sit_config(struct net_device *dev) | |||
| 2471 | } | 2625 | } |
| 2472 | #endif | 2626 | #endif |
| 2473 | 2627 | ||
| 2474 | #if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE) | 2628 | #if IS_ENABLED(CONFIG_NET_IPGRE) |
| 2475 | static void addrconf_gre_config(struct net_device *dev) | 2629 | static void addrconf_gre_config(struct net_device *dev) |
| 2476 | { | 2630 | { |
| 2477 | struct inet6_dev *idev; | 2631 | struct inet6_dev *idev; |
| @@ -2601,12 +2755,12 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2601 | } | 2755 | } |
| 2602 | 2756 | ||
| 2603 | switch (dev->type) { | 2757 | switch (dev->type) { |
| 2604 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2758 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| 2605 | case ARPHRD_SIT: | 2759 | case ARPHRD_SIT: |
| 2606 | addrconf_sit_config(dev); | 2760 | addrconf_sit_config(dev); |
| 2607 | break; | 2761 | break; |
| 2608 | #endif | 2762 | #endif |
| 2609 | #if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE) | 2763 | #if IS_ENABLED(CONFIG_NET_IPGRE) |
| 2610 | case ARPHRD_IPGRE: | 2764 | case ARPHRD_IPGRE: |
| 2611 | addrconf_gre_config(dev); | 2765 | addrconf_gre_config(dev); |
| 2612 | break; | 2766 | break; |
| @@ -2843,7 +2997,7 @@ static void addrconf_rs_timer(unsigned long data) | |||
| 2843 | if (idev->dead || !(idev->if_flags & IF_READY)) | 2997 | if (idev->dead || !(idev->if_flags & IF_READY)) |
| 2844 | goto out; | 2998 | goto out; |
| 2845 | 2999 | ||
| 2846 | if (idev->cnf.forwarding) | 3000 | if (!ipv6_accept_ra(idev)) |
| 2847 | goto out; | 3001 | goto out; |
| 2848 | 3002 | ||
| 2849 | /* Announcement received after solicitation was sent */ | 3003 | /* Announcement received after solicitation was sent */ |
| @@ -3005,8 +3159,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
| 3005 | router advertisements, start sending router solicitations. | 3159 | router advertisements, start sending router solicitations. |
| 3006 | */ | 3160 | */ |
| 3007 | 3161 | ||
| 3008 | if (((ifp->idev->cnf.accept_ra == 1 && !ifp->idev->cnf.forwarding) || | 3162 | if (ipv6_accept_ra(ifp->idev) && |
| 3009 | ifp->idev->cnf.accept_ra == 2) && | ||
| 3010 | ifp->idev->cnf.rtr_solicits > 0 && | 3163 | ifp->idev->cnf.rtr_solicits > 0 && |
| 3011 | (dev->flags&IFF_LOOPBACK) == 0 && | 3164 | (dev->flags&IFF_LOOPBACK) == 0 && |
| 3012 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 3165 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
| @@ -3194,7 +3347,7 @@ void if6_proc_exit(void) | |||
| 3194 | } | 3347 | } |
| 3195 | #endif /* CONFIG_PROC_FS */ | 3348 | #endif /* CONFIG_PROC_FS */ |
| 3196 | 3349 | ||
| 3197 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 3350 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 3198 | /* Check if address is a home address configured on any interface. */ | 3351 | /* 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) | 3352 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) |
| 3200 | { | 3353 | { |
| @@ -3892,6 +4045,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
| 3892 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; | 4045 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; |
| 3893 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; | 4046 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; |
| 3894 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 4047 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
| 4048 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; | ||
| 3895 | } | 4049 | } |
| 3896 | 4050 | ||
| 3897 | static inline size_t inet6_ifla6_size(void) | 4051 | static inline size_t inet6_ifla6_size(void) |
| @@ -4560,6 +4714,13 @@ static struct addrconf_sysctl_table | |||
| 4560 | .proc_handler = proc_dointvec | 4714 | .proc_handler = proc_dointvec |
| 4561 | }, | 4715 | }, |
| 4562 | { | 4716 | { |
| 4717 | .procname = "ndisc_notify", | ||
| 4718 | .data = &ipv6_devconf.ndisc_notify, | ||
| 4719 | .maxlen = sizeof(int), | ||
| 4720 | .mode = 0644, | ||
| 4721 | .proc_handler = proc_dointvec | ||
| 4722 | }, | ||
| 4723 | { | ||
| 4563 | /* sentinel */ | 4724 | /* sentinel */ |
| 4564 | } | 4725 | } |
| 4565 | }, | 4726 | }, |
| @@ -4784,6 +4945,8 @@ int __init addrconf_init(void) | |||
| 4784 | inet6_dump_ifmcaddr, NULL); | 4945 | inet6_dump_ifmcaddr, NULL); |
| 4785 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, | 4946 | __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, |
| 4786 | inet6_dump_ifacaddr, NULL); | 4947 | inet6_dump_ifacaddr, NULL); |
| 4948 | __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, | ||
| 4949 | NULL, NULL); | ||
| 4787 | 4950 | ||
| 4788 | ipv6_addr_label_rtnl_register(); | 4951 | ipv6_addr_label_rtnl_register(); |
| 4789 | 4952 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a974247a9ae4..b043c60429bd 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -160,7 +160,8 @@ lookup_protocol: | |||
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | err = -EPERM; | 162 | err = -EPERM; |
| 163 | if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) | 163 | if (sock->type == SOCK_RAW && !kern && |
| 164 | !ns_capable(net->user_ns, CAP_NET_RAW)) | ||
| 164 | goto out_rcu_unlock; | 165 | goto out_rcu_unlock; |
| 165 | 166 | ||
| 166 | sock->ops = answer->ops; | 167 | sock->ops = answer->ops; |
| @@ -282,7 +283,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 282 | return -EINVAL; | 283 | return -EINVAL; |
| 283 | 284 | ||
| 284 | snum = ntohs(addr->sin6_port); | 285 | snum = ntohs(addr->sin6_port); |
| 285 | if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) | 286 | if (snum && snum < PROT_SOCK && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) |
| 286 | return -EACCES; | 287 | return -EACCES; |
| 287 | 288 | ||
| 288 | lock_sock(sk); | 289 | lock_sock(sk); |
| @@ -699,249 +700,9 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb) | |||
| 699 | } | 700 | } |
| 700 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); | 701 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); |
| 701 | 702 | ||
| 702 | static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) | ||
| 703 | { | ||
| 704 | const struct inet6_protocol *ops = NULL; | ||
| 705 | |||
| 706 | for (;;) { | ||
| 707 | struct ipv6_opt_hdr *opth; | ||
| 708 | int len; | ||
| 709 | |||
| 710 | if (proto != NEXTHDR_HOP) { | ||
| 711 | ops = rcu_dereference(inet6_protos[proto]); | ||
| 712 | |||
| 713 | if (unlikely(!ops)) | ||
| 714 | break; | ||
| 715 | |||
| 716 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
| 717 | break; | ||
| 718 | } | ||
| 719 | |||
| 720 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
| 721 | break; | ||
| 722 | |||
| 723 | opth = (void *)skb->data; | ||
| 724 | len = ipv6_optlen(opth); | ||
| 725 | |||
| 726 | if (unlikely(!pskb_may_pull(skb, len))) | ||
| 727 | break; | ||
| 728 | |||
| 729 | proto = opth->nexthdr; | ||
| 730 | __skb_pull(skb, len); | ||
| 731 | } | ||
| 732 | |||
| 733 | return proto; | ||
| 734 | } | ||
| 735 | |||
| 736 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
| 737 | { | ||
| 738 | const struct ipv6hdr *ipv6h; | ||
| 739 | const struct inet6_protocol *ops; | ||
| 740 | int err = -EINVAL; | ||
| 741 | |||
| 742 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 743 | goto out; | ||
| 744 | |||
| 745 | ipv6h = ipv6_hdr(skb); | ||
| 746 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 747 | err = -EPROTONOSUPPORT; | ||
| 748 | |||
| 749 | rcu_read_lock(); | ||
| 750 | ops = rcu_dereference(inet6_protos[ | ||
| 751 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
| 752 | |||
| 753 | if (likely(ops && ops->gso_send_check)) { | ||
| 754 | skb_reset_transport_header(skb); | ||
| 755 | err = ops->gso_send_check(skb); | ||
| 756 | } | ||
| 757 | rcu_read_unlock(); | ||
| 758 | |||
| 759 | out: | ||
| 760 | return err; | ||
| 761 | } | ||
| 762 | |||
| 763 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | ||
| 764 | netdev_features_t features) | ||
| 765 | { | ||
| 766 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 767 | struct ipv6hdr *ipv6h; | ||
| 768 | const struct inet6_protocol *ops; | ||
| 769 | int proto; | ||
| 770 | struct frag_hdr *fptr; | ||
| 771 | unsigned int unfrag_ip6hlen; | ||
| 772 | u8 *prevhdr; | ||
| 773 | int offset = 0; | ||
| 774 | |||
| 775 | if (!(features & NETIF_F_V6_CSUM)) | ||
| 776 | features &= ~NETIF_F_SG; | ||
| 777 | |||
| 778 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 779 | ~(SKB_GSO_UDP | | ||
| 780 | SKB_GSO_DODGY | | ||
| 781 | SKB_GSO_TCP_ECN | | ||
| 782 | SKB_GSO_TCPV6 | | ||
| 783 | 0))) | ||
| 784 | goto out; | ||
| 785 | |||
| 786 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 787 | goto out; | ||
| 788 | |||
| 789 | ipv6h = ipv6_hdr(skb); | ||
| 790 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 791 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
| 792 | |||
| 793 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
| 794 | rcu_read_lock(); | ||
| 795 | ops = rcu_dereference(inet6_protos[proto]); | ||
| 796 | if (likely(ops && ops->gso_segment)) { | ||
| 797 | skb_reset_transport_header(skb); | ||
| 798 | segs = ops->gso_segment(skb, features); | ||
| 799 | } | ||
| 800 | rcu_read_unlock(); | ||
| 801 | |||
| 802 | if (IS_ERR(segs)) | ||
| 803 | goto out; | ||
| 804 | |||
| 805 | for (skb = segs; skb; skb = skb->next) { | ||
| 806 | ipv6h = ipv6_hdr(skb); | ||
| 807 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
| 808 | sizeof(*ipv6h)); | ||
| 809 | if (proto == IPPROTO_UDP) { | ||
| 810 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 811 | fptr = (struct frag_hdr *)(skb_network_header(skb) + | ||
| 812 | unfrag_ip6hlen); | ||
| 813 | fptr->frag_off = htons(offset); | ||
| 814 | if (skb->next != NULL) | ||
| 815 | fptr->frag_off |= htons(IP6_MF); | ||
| 816 | offset += (ntohs(ipv6h->payload_len) - | ||
| 817 | sizeof(struct frag_hdr)); | ||
| 818 | } | ||
| 819 | } | ||
| 820 | |||
| 821 | out: | ||
| 822 | return segs; | ||
| 823 | } | ||
| 824 | |||
| 825 | static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | ||
| 826 | struct sk_buff *skb) | ||
| 827 | { | ||
| 828 | const struct inet6_protocol *ops; | ||
| 829 | struct sk_buff **pp = NULL; | ||
| 830 | struct sk_buff *p; | ||
| 831 | struct ipv6hdr *iph; | ||
| 832 | unsigned int nlen; | ||
| 833 | unsigned int hlen; | ||
| 834 | unsigned int off; | ||
| 835 | int flush = 1; | ||
| 836 | int proto; | ||
| 837 | __wsum csum; | ||
| 838 | |||
| 839 | off = skb_gro_offset(skb); | ||
| 840 | hlen = off + sizeof(*iph); | ||
| 841 | iph = skb_gro_header_fast(skb, off); | ||
| 842 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 843 | iph = skb_gro_header_slow(skb, hlen, off); | ||
| 844 | if (unlikely(!iph)) | ||
| 845 | goto out; | ||
| 846 | } | ||
| 847 | |||
| 848 | skb_gro_pull(skb, sizeof(*iph)); | ||
| 849 | skb_set_transport_header(skb, skb_gro_offset(skb)); | ||
| 850 | |||
| 851 | flush += ntohs(iph->payload_len) != skb_gro_len(skb); | ||
| 852 | |||
| 853 | rcu_read_lock(); | ||
| 854 | proto = iph->nexthdr; | ||
| 855 | ops = rcu_dereference(inet6_protos[proto]); | ||
| 856 | if (!ops || !ops->gro_receive) { | ||
| 857 | __pskb_pull(skb, skb_gro_offset(skb)); | ||
| 858 | proto = ipv6_gso_pull_exthdrs(skb, proto); | ||
| 859 | skb_gro_pull(skb, -skb_transport_offset(skb)); | ||
| 860 | skb_reset_transport_header(skb); | ||
| 861 | __skb_push(skb, skb_gro_offset(skb)); | ||
| 862 | |||
| 863 | ops = rcu_dereference(inet6_protos[proto]); | ||
| 864 | if (!ops || !ops->gro_receive) | ||
| 865 | goto out_unlock; | ||
| 866 | |||
| 867 | iph = ipv6_hdr(skb); | ||
| 868 | } | ||
| 869 | |||
| 870 | NAPI_GRO_CB(skb)->proto = proto; | ||
| 871 | |||
| 872 | flush--; | ||
| 873 | nlen = skb_network_header_len(skb); | ||
| 874 | |||
| 875 | for (p = *head; p; p = p->next) { | ||
| 876 | const struct ipv6hdr *iph2; | ||
| 877 | __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */ | ||
| 878 | |||
| 879 | if (!NAPI_GRO_CB(p)->same_flow) | ||
| 880 | continue; | ||
| 881 | |||
| 882 | iph2 = ipv6_hdr(p); | ||
| 883 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; | ||
| 884 | |||
| 885 | /* All fields must match except length and Traffic Class. */ | ||
| 886 | if (nlen != skb_network_header_len(p) || | ||
| 887 | (first_word & htonl(0xF00FFFFF)) || | ||
| 888 | memcmp(&iph->nexthdr, &iph2->nexthdr, | ||
| 889 | nlen - offsetof(struct ipv6hdr, nexthdr))) { | ||
| 890 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 891 | continue; | ||
| 892 | } | ||
| 893 | /* flush if Traffic Class fields are different */ | ||
| 894 | NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); | ||
| 895 | NAPI_GRO_CB(p)->flush |= flush; | ||
| 896 | } | ||
| 897 | |||
| 898 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 899 | |||
| 900 | csum = skb->csum; | ||
| 901 | skb_postpull_rcsum(skb, iph, skb_network_header_len(skb)); | ||
| 902 | |||
| 903 | pp = ops->gro_receive(head, skb); | ||
| 904 | |||
| 905 | skb->csum = csum; | ||
| 906 | |||
| 907 | out_unlock: | ||
| 908 | rcu_read_unlock(); | ||
| 909 | |||
| 910 | out: | ||
| 911 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 912 | |||
| 913 | return pp; | ||
| 914 | } | ||
| 915 | |||
| 916 | static int ipv6_gro_complete(struct sk_buff *skb) | ||
| 917 | { | ||
| 918 | const struct inet6_protocol *ops; | ||
| 919 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 920 | int err = -ENOSYS; | ||
| 921 | |||
| 922 | iph->payload_len = htons(skb->len - skb_network_offset(skb) - | ||
| 923 | sizeof(*iph)); | ||
| 924 | |||
| 925 | rcu_read_lock(); | ||
| 926 | ops = rcu_dereference(inet6_protos[NAPI_GRO_CB(skb)->proto]); | ||
| 927 | if (WARN_ON(!ops || !ops->gro_complete)) | ||
| 928 | goto out_unlock; | ||
| 929 | |||
| 930 | err = ops->gro_complete(skb); | ||
| 931 | |||
| 932 | out_unlock: | ||
| 933 | rcu_read_unlock(); | ||
| 934 | |||
| 935 | return err; | ||
| 936 | } | ||
| 937 | |||
| 938 | static struct packet_type ipv6_packet_type __read_mostly = { | 703 | static struct packet_type ipv6_packet_type __read_mostly = { |
| 939 | .type = cpu_to_be16(ETH_P_IPV6), | 704 | .type = cpu_to_be16(ETH_P_IPV6), |
| 940 | .func = ipv6_rcv, | 705 | .func = ipv6_rcv, |
| 941 | .gso_send_check = ipv6_gso_send_check, | ||
| 942 | .gso_segment = ipv6_gso_segment, | ||
| 943 | .gro_receive = ipv6_gro_receive, | ||
| 944 | .gro_complete = ipv6_gro_complete, | ||
| 945 | }; | 706 | }; |
| 946 | 707 | ||
| 947 | static int __init ipv6_packet_init(void) | 708 | static int __init ipv6_packet_init(void) |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 7e6139508ee7..ecc35b93314b 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
| @@ -44,7 +44,7 @@ | |||
| 44 | #define IPV6HDR_BASELEN 8 | 44 | #define IPV6HDR_BASELEN 8 |
| 45 | 45 | ||
| 46 | struct tmp_ext { | 46 | struct tmp_ext { |
| 47 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 47 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 48 | struct in6_addr saddr; | 48 | struct in6_addr saddr; |
| 49 | #endif | 49 | #endif |
| 50 | struct in6_addr daddr; | 50 | struct in6_addr daddr; |
| @@ -152,7 +152,7 @@ bad: | |||
| 152 | return false; | 152 | return false; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 155 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 156 | /** | 156 | /** |
| 157 | * ipv6_rearrange_destopt - rearrange IPv6 destination options header | 157 | * ipv6_rearrange_destopt - rearrange IPv6 destination options header |
| 158 | * @iph: IPv6 header | 158 | * @iph: IPv6 header |
| @@ -320,7 +320,7 @@ static void ah6_output_done(struct crypto_async_request *base, int err) | |||
| 320 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); | 320 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); |
| 321 | 321 | ||
| 322 | if (extlen) { | 322 | if (extlen) { |
| 323 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 323 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 324 | memcpy(&top_iph->saddr, iph_ext, extlen); | 324 | memcpy(&top_iph->saddr, iph_ext, extlen); |
| 325 | #else | 325 | #else |
| 326 | memcpy(&top_iph->daddr, iph_ext, extlen); | 326 | memcpy(&top_iph->daddr, iph_ext, extlen); |
| @@ -385,7 +385,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 385 | memcpy(iph_base, top_iph, IPV6HDR_BASELEN); | 385 | memcpy(iph_base, top_iph, IPV6HDR_BASELEN); |
| 386 | 386 | ||
| 387 | if (extlen) { | 387 | if (extlen) { |
| 388 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 388 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 389 | memcpy(iph_ext, &top_iph->saddr, extlen); | 389 | memcpy(iph_ext, &top_iph->saddr, extlen); |
| 390 | #else | 390 | #else |
| 391 | memcpy(iph_ext, &top_iph->daddr, extlen); | 391 | memcpy(iph_ext, &top_iph->daddr, extlen); |
| @@ -434,7 +434,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 434 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); | 434 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); |
| 435 | 435 | ||
| 436 | if (extlen) { | 436 | if (extlen) { |
| 437 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 437 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 438 | memcpy(&top_iph->saddr, iph_ext, extlen); | 438 | memcpy(&top_iph->saddr, iph_ext, extlen); |
| 439 | #else | 439 | #else |
| 440 | memcpy(&top_iph->daddr, iph_ext, extlen); | 440 | memcpy(&top_iph->daddr, iph_ext, extlen); |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index cdf02be5f191..757a810d8f15 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
| @@ -64,7 +64,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 64 | int ishost = !net->ipv6.devconf_all->forwarding; | 64 | int ishost = !net->ipv6.devconf_all->forwarding; |
| 65 | int err = 0; | 65 | int err = 0; |
| 66 | 66 | ||
| 67 | if (!capable(CAP_NET_ADMIN)) | 67 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 68 | return -EPERM; | 68 | return -EPERM; |
| 69 | if (ipv6_addr_is_multicast(addr)) | 69 | if (ipv6_addr_is_multicast(addr)) |
| 70 | return -EINVAL; | 70 | return -EINVAL; |
| @@ -84,7 +84,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 84 | rt = rt6_lookup(net, addr, NULL, 0, 0); | 84 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
| 85 | if (rt) { | 85 | if (rt) { |
| 86 | dev = rt->dst.dev; | 86 | dev = rt->dst.dev; |
| 87 | dst_release(&rt->dst); | 87 | ip6_rt_put(rt); |
| 88 | } else if (ishost) { | 88 | } else if (ishost) { |
| 89 | err = -EADDRNOTAVAIL; | 89 | err = -EADDRNOTAVAIL; |
| 90 | goto error; | 90 | goto error; |
| @@ -189,6 +189,9 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
| 189 | struct net *net = sock_net(sk); | 189 | struct net *net = sock_net(sk); |
| 190 | int prev_index; | 190 | int prev_index; |
| 191 | 191 | ||
| 192 | if (!np->ipv6_ac_list) | ||
| 193 | return; | ||
| 194 | |||
| 192 | write_lock_bh(&ipv6_sk_ac_lock); | 195 | write_lock_bh(&ipv6_sk_ac_lock); |
| 193 | pac = np->ipv6_ac_list; | 196 | pac = np->ipv6_ac_list; |
| 194 | np->ipv6_ac_list = NULL; | 197 | np->ipv6_ac_list = NULL; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index be2b67d631e5..8edf2601065a 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -701,7 +701,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk, | |||
| 701 | err = -EINVAL; | 701 | err = -EINVAL; |
| 702 | goto exit_f; | 702 | goto exit_f; |
| 703 | } | 703 | } |
| 704 | if (!capable(CAP_NET_RAW)) { | 704 | if (!ns_capable(net->user_ns, CAP_NET_RAW)) { |
| 705 | err = -EPERM; | 705 | err = -EPERM; |
| 706 | goto exit_f; | 706 | goto exit_f; |
| 707 | } | 707 | } |
| @@ -721,7 +721,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk, | |||
| 721 | err = -EINVAL; | 721 | err = -EINVAL; |
| 722 | goto exit_f; | 722 | goto exit_f; |
| 723 | } | 723 | } |
| 724 | if (!capable(CAP_NET_RAW)) { | 724 | if (!ns_capable(net->user_ns, CAP_NET_RAW)) { |
| 725 | err = -EPERM; | 725 | err = -EPERM; |
| 726 | goto exit_f; | 726 | goto exit_f; |
| 727 | } | 727 | } |
| @@ -746,7 +746,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk, | |||
| 746 | err = -EINVAL; | 746 | err = -EINVAL; |
| 747 | goto exit_f; | 747 | goto exit_f; |
| 748 | } | 748 | } |
| 749 | if (!capable(CAP_NET_RAW)) { | 749 | if (!ns_capable(net->user_ns, CAP_NET_RAW)) { |
| 750 | err = -EPERM; | 750 | err = -EPERM; |
| 751 | goto exit_f; | 751 | goto exit_f; |
| 752 | } | 752 | } |
| @@ -769,7 +769,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk, | |||
| 769 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); | 769 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); |
| 770 | 770 | ||
| 771 | switch (rthdr->type) { | 771 | switch (rthdr->type) { |
| 772 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 772 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 773 | case IPV6_SRCRT_TYPE_2: | 773 | case IPV6_SRCRT_TYPE_2: |
| 774 | if (rthdr->hdrlen != 2 || | 774 | if (rthdr->hdrlen != 2 || |
| 775 | rthdr->segments_left != 1) { | 775 | rthdr->segments_left != 1) { |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index fa3d9c328092..473f628f9f20 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
| @@ -43,56 +43,12 @@ | |||
| 43 | #include <net/ndisc.h> | 43 | #include <net/ndisc.h> |
| 44 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
| 45 | #include <net/addrconf.h> | 45 | #include <net/addrconf.h> |
| 46 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 46 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 47 | #include <net/xfrm.h> | 47 | #include <net/xfrm.h> |
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
| 51 | 51 | ||
| 52 | int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | ||
| 53 | { | ||
| 54 | const unsigned char *nh = skb_network_header(skb); | ||
| 55 | int packet_len = skb->tail - skb->network_header; | ||
| 56 | struct ipv6_opt_hdr *hdr; | ||
| 57 | int len; | ||
| 58 | |||
| 59 | if (offset + 2 > packet_len) | ||
| 60 | goto bad; | ||
| 61 | hdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 62 | len = ((hdr->hdrlen + 1) << 3); | ||
| 63 | |||
| 64 | if (offset + len > packet_len) | ||
| 65 | goto bad; | ||
| 66 | |||
| 67 | offset += 2; | ||
| 68 | len -= 2; | ||
| 69 | |||
| 70 | while (len > 0) { | ||
| 71 | int opttype = nh[offset]; | ||
| 72 | int optlen; | ||
| 73 | |||
| 74 | if (opttype == type) | ||
| 75 | return offset; | ||
| 76 | |||
| 77 | switch (opttype) { | ||
| 78 | case IPV6_TLV_PAD1: | ||
| 79 | optlen = 1; | ||
| 80 | break; | ||
| 81 | default: | ||
| 82 | optlen = nh[offset + 1] + 2; | ||
| 83 | if (optlen > len) | ||
| 84 | goto bad; | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | offset += optlen; | ||
| 88 | len -= optlen; | ||
| 89 | } | ||
| 90 | /* not_found */ | ||
| 91 | bad: | ||
| 92 | return -1; | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); | ||
| 95 | |||
| 96 | /* | 52 | /* |
| 97 | * Parsing tlv encoded headers. | 53 | * Parsing tlv encoded headers. |
| 98 | * | 54 | * |
| @@ -224,7 +180,7 @@ bad: | |||
| 224 | Destination options header. | 180 | Destination options header. |
| 225 | *****************************/ | 181 | *****************************/ |
| 226 | 182 | ||
| 227 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 183 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 228 | static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) | 184 | static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) |
| 229 | { | 185 | { |
| 230 | struct ipv6_destopt_hao *hao; | 186 | struct ipv6_destopt_hao *hao; |
| @@ -288,7 +244,7 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) | |||
| 288 | #endif | 244 | #endif |
| 289 | 245 | ||
| 290 | static const struct tlvtype_proc tlvprocdestopt_lst[] = { | 246 | static const struct tlvtype_proc tlvprocdestopt_lst[] = { |
| 291 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 247 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 292 | { | 248 | { |
| 293 | .type = IPV6_TLV_HAO, | 249 | .type = IPV6_TLV_HAO, |
| 294 | .func = ipv6_dest_hao, | 250 | .func = ipv6_dest_hao, |
| @@ -300,7 +256,7 @@ static const struct tlvtype_proc tlvprocdestopt_lst[] = { | |||
| 300 | static int ipv6_destopt_rcv(struct sk_buff *skb) | 256 | static int ipv6_destopt_rcv(struct sk_buff *skb) |
| 301 | { | 257 | { |
| 302 | struct inet6_skb_parm *opt = IP6CB(skb); | 258 | struct inet6_skb_parm *opt = IP6CB(skb); |
| 303 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 259 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 304 | __u16 dstbuf; | 260 | __u16 dstbuf; |
| 305 | #endif | 261 | #endif |
| 306 | struct dst_entry *dst = skb_dst(skb); | 262 | struct dst_entry *dst = skb_dst(skb); |
| @@ -315,14 +271,14 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) | |||
| 315 | } | 271 | } |
| 316 | 272 | ||
| 317 | opt->lastopt = opt->dst1 = skb_network_header_len(skb); | 273 | opt->lastopt = opt->dst1 = skb_network_header_len(skb); |
| 318 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 274 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 319 | dstbuf = opt->dst1; | 275 | dstbuf = opt->dst1; |
| 320 | #endif | 276 | #endif |
| 321 | 277 | ||
| 322 | if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { | 278 | if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { |
| 323 | skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; | 279 | skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; |
| 324 | opt = IP6CB(skb); | 280 | opt = IP6CB(skb); |
| 325 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 281 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 326 | opt->nhoff = dstbuf; | 282 | opt->nhoff = dstbuf; |
| 327 | #else | 283 | #else |
| 328 | opt->nhoff = opt->dst1; | 284 | opt->nhoff = opt->dst1; |
| @@ -378,7 +334,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) | |||
| 378 | looped_back: | 334 | looped_back: |
| 379 | if (hdr->segments_left == 0) { | 335 | if (hdr->segments_left == 0) { |
| 380 | switch (hdr->type) { | 336 | switch (hdr->type) { |
| 381 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 337 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 382 | case IPV6_SRCRT_TYPE_2: | 338 | case IPV6_SRCRT_TYPE_2: |
| 383 | /* Silently discard type 2 header unless it was | 339 | /* Silently discard type 2 header unless it was |
| 384 | * processed by own | 340 | * processed by own |
| @@ -404,7 +360,7 @@ looped_back: | |||
| 404 | } | 360 | } |
| 405 | 361 | ||
| 406 | switch (hdr->type) { | 362 | switch (hdr->type) { |
| 407 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 363 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 408 | case IPV6_SRCRT_TYPE_2: | 364 | case IPV6_SRCRT_TYPE_2: |
| 409 | if (accept_source_route < 0) | 365 | if (accept_source_route < 0) |
| 410 | goto unknown_rh; | 366 | goto unknown_rh; |
| @@ -461,7 +417,7 @@ looped_back: | |||
| 461 | addr += i - 1; | 417 | addr += i - 1; |
| 462 | 418 | ||
| 463 | switch (hdr->type) { | 419 | switch (hdr->type) { |
| 464 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 420 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 465 | case IPV6_SRCRT_TYPE_2: | 421 | case IPV6_SRCRT_TYPE_2: |
| 466 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | 422 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, |
| 467 | (xfrm_address_t *)&ipv6_hdr(skb)->saddr, | 423 | (xfrm_address_t *)&ipv6_hdr(skb)->saddr, |
| @@ -528,12 +484,12 @@ unknown_rh: | |||
| 528 | 484 | ||
| 529 | static const struct inet6_protocol rthdr_protocol = { | 485 | static const struct inet6_protocol rthdr_protocol = { |
| 530 | .handler = ipv6_rthdr_rcv, | 486 | .handler = ipv6_rthdr_rcv, |
| 531 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, | 487 | .flags = INET6_PROTO_NOPOLICY, |
| 532 | }; | 488 | }; |
| 533 | 489 | ||
| 534 | static const struct inet6_protocol destopt_protocol = { | 490 | static const struct inet6_protocol destopt_protocol = { |
| 535 | .handler = ipv6_destopt_rcv, | 491 | .handler = ipv6_destopt_rcv, |
| 536 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, | 492 | .flags = INET6_PROTO_NOPOLICY, |
| 537 | }; | 493 | }; |
| 538 | 494 | ||
| 539 | static const struct inet6_protocol nodata_protocol = { | 495 | static const struct inet6_protocol nodata_protocol = { |
| @@ -559,10 +515,10 @@ int __init ipv6_exthdrs_init(void) | |||
| 559 | 515 | ||
| 560 | out: | 516 | out: |
| 561 | return ret; | 517 | return ret; |
| 562 | out_rthdr: | ||
| 563 | inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING); | ||
| 564 | out_destopt: | 518 | out_destopt: |
| 565 | inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); | 519 | inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); |
| 520 | out_rthdr: | ||
| 521 | inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING); | ||
| 566 | goto out; | 522 | goto out; |
| 567 | }; | 523 | }; |
| 568 | 524 | ||
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index f73d59a14131..c5e83fae4df4 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
| @@ -111,3 +111,171 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, | |||
| 111 | return start; | 111 | return start; |
| 112 | } | 112 | } |
| 113 | EXPORT_SYMBOL(ipv6_skip_exthdr); | 113 | EXPORT_SYMBOL(ipv6_skip_exthdr); |
| 114 | |||
| 115 | int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | ||
| 116 | { | ||
| 117 | const unsigned char *nh = skb_network_header(skb); | ||
| 118 | int packet_len = skb->tail - skb->network_header; | ||
| 119 | struct ipv6_opt_hdr *hdr; | ||
| 120 | int len; | ||
| 121 | |||
| 122 | if (offset + 2 > packet_len) | ||
| 123 | goto bad; | ||
| 124 | hdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
| 125 | len = ((hdr->hdrlen + 1) << 3); | ||
| 126 | |||
| 127 | if (offset + len > packet_len) | ||
| 128 | goto bad; | ||
| 129 | |||
| 130 | offset += 2; | ||
| 131 | len -= 2; | ||
| 132 | |||
| 133 | while (len > 0) { | ||
| 134 | int opttype = nh[offset]; | ||
| 135 | int optlen; | ||
| 136 | |||
| 137 | if (opttype == type) | ||
| 138 | return offset; | ||
| 139 | |||
| 140 | switch (opttype) { | ||
| 141 | case IPV6_TLV_PAD1: | ||
| 142 | optlen = 1; | ||
| 143 | break; | ||
| 144 | default: | ||
| 145 | optlen = nh[offset + 1] + 2; | ||
| 146 | if (optlen > len) | ||
| 147 | goto bad; | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | offset += optlen; | ||
| 151 | len -= optlen; | ||
| 152 | } | ||
| 153 | /* not_found */ | ||
| 154 | bad: | ||
| 155 | return -1; | ||
| 156 | } | ||
| 157 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); | ||
| 158 | |||
| 159 | /* | ||
| 160 | * find the offset to specified header or the protocol number of last header | ||
| 161 | * if target < 0. "last header" is transport protocol header, ESP, or | ||
| 162 | * "No next header". | ||
| 163 | * | ||
| 164 | * Note that *offset is used as input/output parameter. an if it is not zero, | ||
| 165 | * then it must be a valid offset to an inner IPv6 header. This can be used | ||
| 166 | * to explore inner IPv6 header, eg. ICMPv6 error messages. | ||
| 167 | * | ||
| 168 | * If target header is found, its offset is set in *offset and return protocol | ||
| 169 | * number. Otherwise, return -1. | ||
| 170 | * | ||
| 171 | * If the first fragment doesn't contain the final protocol header or | ||
| 172 | * NEXTHDR_NONE it is considered invalid. | ||
| 173 | * | ||
| 174 | * Note that non-1st fragment is special case that "the protocol number | ||
| 175 | * of last header" is "next header" field in Fragment header. In this case, | ||
| 176 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
| 177 | * isn't NULL. | ||
| 178 | * | ||
| 179 | * if flags is not NULL and it's a fragment, then the frag flag | ||
| 180 | * IP6_FH_F_FRAG will be set. If it's an AH header, the | ||
| 181 | * IP6_FH_F_AUTH flag is set and target < 0, then this function will | ||
| 182 | * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this | ||
| 183 | * function will skip all those routing headers, where segements_left was 0. | ||
| 184 | */ | ||
| 185 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | ||
| 186 | int target, unsigned short *fragoff, int *flags) | ||
| 187 | { | ||
| 188 | unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); | ||
| 189 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 190 | unsigned int len; | ||
| 191 | bool found; | ||
| 192 | |||
| 193 | if (fragoff) | ||
| 194 | *fragoff = 0; | ||
| 195 | |||
| 196 | if (*offset) { | ||
| 197 | struct ipv6hdr _ip6, *ip6; | ||
| 198 | |||
| 199 | ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); | ||
| 200 | if (!ip6 || (ip6->version != 6)) { | ||
| 201 | printk(KERN_ERR "IPv6 header not found\n"); | ||
| 202 | return -EBADMSG; | ||
| 203 | } | ||
| 204 | start = *offset + sizeof(struct ipv6hdr); | ||
| 205 | nexthdr = ip6->nexthdr; | ||
| 206 | } | ||
| 207 | len = skb->len - start; | ||
| 208 | |||
| 209 | do { | ||
| 210 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 211 | unsigned int hdrlen; | ||
| 212 | found = (nexthdr == target); | ||
| 213 | |||
| 214 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { | ||
| 215 | if (target < 0) | ||
| 216 | break; | ||
| 217 | return -ENOENT; | ||
| 218 | } | ||
| 219 | |||
| 220 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | ||
| 221 | if (hp == NULL) | ||
| 222 | return -EBADMSG; | ||
| 223 | |||
| 224 | if (nexthdr == NEXTHDR_ROUTING) { | ||
| 225 | struct ipv6_rt_hdr _rh, *rh; | ||
| 226 | |||
| 227 | rh = skb_header_pointer(skb, start, sizeof(_rh), | ||
| 228 | &_rh); | ||
| 229 | if (rh == NULL) | ||
| 230 | return -EBADMSG; | ||
| 231 | |||
| 232 | if (flags && (*flags & IP6_FH_F_SKIP_RH) && | ||
| 233 | rh->segments_left == 0) | ||
| 234 | found = false; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 238 | unsigned short _frag_off; | ||
| 239 | __be16 *fp; | ||
| 240 | |||
| 241 | if (flags) /* Indicate that this is a fragment */ | ||
| 242 | *flags |= IP6_FH_F_FRAG; | ||
| 243 | fp = skb_header_pointer(skb, | ||
| 244 | start+offsetof(struct frag_hdr, | ||
| 245 | frag_off), | ||
| 246 | sizeof(_frag_off), | ||
| 247 | &_frag_off); | ||
| 248 | if (fp == NULL) | ||
| 249 | return -EBADMSG; | ||
| 250 | |||
| 251 | _frag_off = ntohs(*fp) & ~0x7; | ||
| 252 | if (_frag_off) { | ||
| 253 | if (target < 0 && | ||
| 254 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
| 255 | hp->nexthdr == NEXTHDR_NONE)) { | ||
| 256 | if (fragoff) | ||
| 257 | *fragoff = _frag_off; | ||
| 258 | return hp->nexthdr; | ||
| 259 | } | ||
| 260 | return -ENOENT; | ||
| 261 | } | ||
| 262 | hdrlen = 8; | ||
| 263 | } else if (nexthdr == NEXTHDR_AUTH) { | ||
| 264 | if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0)) | ||
| 265 | break; | ||
| 266 | hdrlen = (hp->hdrlen + 2) << 2; | ||
| 267 | } else | ||
| 268 | hdrlen = ipv6_optlen(hp); | ||
| 269 | |||
| 270 | if (!found) { | ||
| 271 | nexthdr = hp->nexthdr; | ||
| 272 | len -= hdrlen; | ||
| 273 | start += hdrlen; | ||
| 274 | } | ||
| 275 | } while (!found); | ||
| 276 | |||
| 277 | *offset = start; | ||
| 278 | return nexthdr; | ||
| 279 | } | ||
| 280 | EXPORT_SYMBOL(ipv6_find_hdr); | ||
| 281 | |||
diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c new file mode 100644 index 000000000000..cf77f3abfd06 --- /dev/null +++ b/net/ipv6/exthdrs_offload.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * IPV6 GSO/GRO offload support | ||
| 3 | * Linux INET6 implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * IPV6 Extension Header GSO/GRO support | ||
| 11 | */ | ||
| 12 | #include <net/protocol.h> | ||
| 13 | #include "ip6_offload.h" | ||
| 14 | |||
| 15 | static const struct net_offload rthdr_offload = { | ||
| 16 | .flags = INET6_PROTO_GSO_EXTHDR, | ||
| 17 | }; | ||
| 18 | |||
| 19 | static const struct net_offload dstopt_offload = { | ||
| 20 | .flags = INET6_PROTO_GSO_EXTHDR, | ||
| 21 | }; | ||
| 22 | |||
| 23 | int __init ipv6_exthdrs_offload_init(void) | ||
| 24 | { | ||
| 25 | int ret; | ||
| 26 | |||
| 27 | ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING); | ||
| 28 | if (!ret) | ||
| 29 | goto out; | ||
| 30 | |||
| 31 | ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS); | ||
| 32 | if (!ret) | ||
| 33 | goto out_rt; | ||
| 34 | |||
| 35 | out: | ||
| 36 | return ret; | ||
| 37 | |||
| 38 | out_rt: | ||
| 39 | inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); | ||
| 40 | goto out; | ||
| 41 | } | ||
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index d9fb9110f607..2e1a432867c0 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
| @@ -100,7 +100,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
| 100 | goto out; | 100 | goto out; |
| 101 | } | 101 | } |
| 102 | again: | 102 | again: |
| 103 | dst_release(&rt->dst); | 103 | ip6_rt_put(rt); |
| 104 | rt = NULL; | 104 | rt = NULL; |
| 105 | goto out; | 105 | goto out; |
| 106 | 106 | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 24d69dbca4d6..b4a9fd51dae7 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -280,7 +280,7 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st | |||
| 280 | return 0; | 280 | return 0; |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 283 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 284 | static void mip6_addr_swap(struct sk_buff *skb) | 284 | static void mip6_addr_swap(struct sk_buff *skb) |
| 285 | { | 285 | { |
| 286 | struct ipv6hdr *iph = ipv6_hdr(skb); | 286 | struct ipv6hdr *iph = ipv6_hdr(skb); |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index c4f934176cab..30647857a375 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
| @@ -252,6 +252,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu) | |||
| 252 | return NULL; | 252 | return NULL; |
| 253 | dst->ops->update_pmtu(dst, sk, NULL, mtu); | 253 | dst->ops->update_pmtu(dst, sk, NULL, mtu); |
| 254 | 254 | ||
| 255 | return inet6_csk_route_socket(sk, &fl6); | 255 | dst = inet6_csk_route_socket(sk, &fl6); |
| 256 | return IS_ERR(dst) ? NULL : dst; | ||
| 256 | } | 257 | } |
| 257 | EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); | 258 | EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 73f1a00a96af..dea17fd28e50 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
| @@ -87,11 +87,13 @@ struct sock *__inet6_lookup_established(struct net *net, | |||
| 87 | rcu_read_lock(); | 87 | rcu_read_lock(); |
| 88 | begin: | 88 | begin: |
| 89 | sk_nulls_for_each_rcu(sk, node, &head->chain) { | 89 | sk_nulls_for_each_rcu(sk, node, &head->chain) { |
| 90 | /* For IPV6 do the cheaper port and family tests first. */ | 90 | if (sk->sk_hash != hash) |
| 91 | if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 91 | continue; |
| 92 | if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { | ||
| 92 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) | 93 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) |
| 93 | goto begintw; | 94 | goto begintw; |
| 94 | if (!INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 95 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, |
| 96 | ports, dif))) { | ||
| 95 | sock_put(sk); | 97 | sock_put(sk); |
| 96 | goto begin; | 98 | goto begin; |
| 97 | } | 99 | } |
| @@ -104,12 +106,16 @@ begin: | |||
| 104 | begintw: | 106 | begintw: |
| 105 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 107 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
| 106 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { | 108 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { |
| 107 | if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 109 | if (sk->sk_hash != hash) |
| 110 | continue; | ||
| 111 | if (likely(INET6_TW_MATCH(sk, net, saddr, daddr, | ||
| 112 | ports, dif))) { | ||
| 108 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { | 113 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { |
| 109 | sk = NULL; | 114 | sk = NULL; |
| 110 | goto out; | 115 | goto out; |
| 111 | } | 116 | } |
| 112 | if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { | 117 | if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr, |
| 118 | ports, dif))) { | ||
| 113 | sock_put(sk); | 119 | sock_put(sk); |
| 114 | goto begintw; | 120 | goto begintw; |
| 115 | } | 121 | } |
| @@ -236,9 +242,12 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 236 | 242 | ||
| 237 | /* Check TIME-WAIT sockets first. */ | 243 | /* Check TIME-WAIT sockets first. */ |
| 238 | sk_nulls_for_each(sk2, node, &head->twchain) { | 244 | sk_nulls_for_each(sk2, node, &head->twchain) { |
| 239 | tw = inet_twsk(sk2); | 245 | if (sk2->sk_hash != hash) |
| 246 | continue; | ||
| 240 | 247 | ||
| 241 | if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) { | 248 | if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr, |
| 249 | ports, dif))) { | ||
| 250 | tw = inet_twsk(sk2); | ||
| 242 | if (twsk_unique(sk, sk2, twp)) | 251 | if (twsk_unique(sk, sk2, twp)) |
| 243 | goto unique; | 252 | goto unique; |
| 244 | else | 253 | else |
| @@ -249,7 +258,9 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 249 | 258 | ||
| 250 | /* And established part... */ | 259 | /* And established part... */ |
| 251 | sk_nulls_for_each(sk2, node, &head->chain) { | 260 | sk_nulls_for_each(sk2, node, &head->chain) { |
| 252 | if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) | 261 | if (sk2->sk_hash != hash) |
| 262 | continue; | ||
| 263 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) | ||
| 253 | goto not_unique; | 264 | goto not_unique; |
| 254 | } | 265 | } |
| 255 | 266 | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 24995a93ef8c..710cafd2e1a9 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -672,6 +672,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 672 | iter->rt6i_idev == rt->rt6i_idev && | 672 | iter->rt6i_idev == rt->rt6i_idev && |
| 673 | ipv6_addr_equal(&iter->rt6i_gateway, | 673 | ipv6_addr_equal(&iter->rt6i_gateway, |
| 674 | &rt->rt6i_gateway)) { | 674 | &rt->rt6i_gateway)) { |
| 675 | if (rt->rt6i_nsiblings) | ||
| 676 | rt->rt6i_nsiblings = 0; | ||
| 675 | if (!(iter->rt6i_flags & RTF_EXPIRES)) | 677 | if (!(iter->rt6i_flags & RTF_EXPIRES)) |
| 676 | return -EEXIST; | 678 | return -EEXIST; |
| 677 | if (!(rt->rt6i_flags & RTF_EXPIRES)) | 679 | if (!(rt->rt6i_flags & RTF_EXPIRES)) |
| @@ -680,6 +682,21 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 680 | rt6_set_expires(iter, rt->dst.expires); | 682 | rt6_set_expires(iter, rt->dst.expires); |
| 681 | return -EEXIST; | 683 | return -EEXIST; |
| 682 | } | 684 | } |
| 685 | /* If we have the same destination and the same metric, | ||
| 686 | * but not the same gateway, then the route we try to | ||
| 687 | * add is sibling to this route, increment our counter | ||
| 688 | * of siblings, and later we will add our route to the | ||
| 689 | * list. | ||
| 690 | * Only static routes (which don't have flag | ||
| 691 | * RTF_EXPIRES) are used for ECMPv6. | ||
| 692 | * | ||
| 693 | * To avoid long list, we only had siblings if the | ||
| 694 | * route have a gateway. | ||
| 695 | */ | ||
| 696 | if (rt->rt6i_flags & RTF_GATEWAY && | ||
| 697 | !(rt->rt6i_flags & RTF_EXPIRES) && | ||
| 698 | !(iter->rt6i_flags & RTF_EXPIRES)) | ||
| 699 | rt->rt6i_nsiblings++; | ||
| 683 | } | 700 | } |
| 684 | 701 | ||
| 685 | if (iter->rt6i_metric > rt->rt6i_metric) | 702 | if (iter->rt6i_metric > rt->rt6i_metric) |
| @@ -692,6 +709,35 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 692 | if (ins == &fn->leaf) | 709 | if (ins == &fn->leaf) |
| 693 | fn->rr_ptr = NULL; | 710 | fn->rr_ptr = NULL; |
| 694 | 711 | ||
| 712 | /* Link this route to others same route. */ | ||
| 713 | if (rt->rt6i_nsiblings) { | ||
| 714 | unsigned int rt6i_nsiblings; | ||
| 715 | struct rt6_info *sibling, *temp_sibling; | ||
| 716 | |||
| 717 | /* Find the first route that have the same metric */ | ||
| 718 | sibling = fn->leaf; | ||
| 719 | while (sibling) { | ||
| 720 | if (sibling->rt6i_metric == rt->rt6i_metric) { | ||
| 721 | list_add_tail(&rt->rt6i_siblings, | ||
| 722 | &sibling->rt6i_siblings); | ||
| 723 | break; | ||
| 724 | } | ||
| 725 | sibling = sibling->dst.rt6_next; | ||
| 726 | } | ||
| 727 | /* For each sibling in the list, increment the counter of | ||
| 728 | * siblings. BUG() if counters does not match, list of siblings | ||
| 729 | * is broken! | ||
| 730 | */ | ||
| 731 | rt6i_nsiblings = 0; | ||
| 732 | list_for_each_entry_safe(sibling, temp_sibling, | ||
| 733 | &rt->rt6i_siblings, rt6i_siblings) { | ||
| 734 | sibling->rt6i_nsiblings++; | ||
| 735 | BUG_ON(sibling->rt6i_nsiblings != rt->rt6i_nsiblings); | ||
| 736 | rt6i_nsiblings++; | ||
| 737 | } | ||
| 738 | BUG_ON(rt6i_nsiblings != rt->rt6i_nsiblings); | ||
| 739 | } | ||
| 740 | |||
| 695 | /* | 741 | /* |
| 696 | * insert node | 742 | * insert node |
| 697 | */ | 743 | */ |
| @@ -1193,6 +1239,17 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 1193 | if (fn->rr_ptr == rt) | 1239 | if (fn->rr_ptr == rt) |
| 1194 | fn->rr_ptr = NULL; | 1240 | fn->rr_ptr = NULL; |
| 1195 | 1241 | ||
| 1242 | /* Remove this entry from other siblings */ | ||
| 1243 | if (rt->rt6i_nsiblings) { | ||
| 1244 | struct rt6_info *sibling, *next_sibling; | ||
| 1245 | |||
| 1246 | list_for_each_entry_safe(sibling, next_sibling, | ||
| 1247 | &rt->rt6i_siblings, rt6i_siblings) | ||
| 1248 | sibling->rt6i_nsiblings--; | ||
| 1249 | rt->rt6i_nsiblings = 0; | ||
| 1250 | list_del_init(&rt->rt6i_siblings); | ||
| 1251 | } | ||
| 1252 | |||
| 1196 | /* Adjust walkers */ | 1253 | /* Adjust walkers */ |
| 1197 | read_lock(&fib6_walker_lock); | 1254 | read_lock(&fib6_walker_lock); |
| 1198 | FOR_WALKERS(w) { | 1255 | FOR_WALKERS(w) { |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 90bbefb57943..29124b7a04c8 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -519,7 +519,8 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
| 519 | } | 519 | } |
| 520 | read_unlock_bh(&ip6_sk_fl_lock); | 520 | read_unlock_bh(&ip6_sk_fl_lock); |
| 521 | 521 | ||
| 522 | if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) { | 522 | if (freq.flr_share == IPV6_FL_S_NONE && |
| 523 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { | ||
| 523 | fl = fl_lookup(net, freq.flr_label); | 524 | fl = fl_lookup(net, freq.flr_label); |
| 524 | if (fl) { | 525 | if (fl) { |
| 525 | err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); | 526 | err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index d5cb3c4e66f8..867466c96aac 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
| @@ -109,21 +109,6 @@ static u32 HASH_ADDR(const struct in6_addr *addr) | |||
| 109 | #define tunnels_r tunnels[2] | 109 | #define tunnels_r tunnels[2] |
| 110 | #define tunnels_l tunnels[1] | 110 | #define tunnels_l tunnels[1] |
| 111 | #define tunnels_wc tunnels[0] | 111 | #define tunnels_wc tunnels[0] |
| 112 | /* | ||
| 113 | * Locking : hash tables are protected by RCU and RTNL | ||
| 114 | */ | ||
| 115 | |||
| 116 | #define for_each_ip_tunnel_rcu(start) \ | ||
| 117 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
| 118 | |||
| 119 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
| 120 | struct pcpu_tstats { | ||
| 121 | u64 rx_packets; | ||
| 122 | u64 rx_bytes; | ||
| 123 | u64 tx_packets; | ||
| 124 | u64 tx_bytes; | ||
| 125 | struct u64_stats_sync syncp; | ||
| 126 | }; | ||
| 127 | 112 | ||
| 128 | static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev, | 113 | static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev, |
| 129 | struct rtnl_link_stats64 *tot) | 114 | struct rtnl_link_stats64 *tot) |
| @@ -181,7 +166,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, | |||
| 181 | ARPHRD_ETHER : ARPHRD_IP6GRE; | 166 | ARPHRD_ETHER : ARPHRD_IP6GRE; |
| 182 | int score, cand_score = 4; | 167 | int score, cand_score = 4; |
| 183 | 168 | ||
| 184 | for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { | 169 | for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) { |
| 185 | if (!ipv6_addr_equal(local, &t->parms.laddr) || | 170 | if (!ipv6_addr_equal(local, &t->parms.laddr) || |
| 186 | !ipv6_addr_equal(remote, &t->parms.raddr) || | 171 | !ipv6_addr_equal(remote, &t->parms.raddr) || |
| 187 | key != t->parms.i_key || | 172 | key != t->parms.i_key || |
| @@ -206,7 +191,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, | |||
| 206 | } | 191 | } |
| 207 | } | 192 | } |
| 208 | 193 | ||
| 209 | for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { | 194 | for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) { |
| 210 | if (!ipv6_addr_equal(remote, &t->parms.raddr) || | 195 | if (!ipv6_addr_equal(remote, &t->parms.raddr) || |
| 211 | key != t->parms.i_key || | 196 | key != t->parms.i_key || |
| 212 | !(t->dev->flags & IFF_UP)) | 197 | !(t->dev->flags & IFF_UP)) |
| @@ -230,7 +215,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, | |||
| 230 | } | 215 | } |
| 231 | } | 216 | } |
| 232 | 217 | ||
| 233 | for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) { | 218 | for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) { |
| 234 | if ((!ipv6_addr_equal(local, &t->parms.laddr) && | 219 | if ((!ipv6_addr_equal(local, &t->parms.laddr) && |
| 235 | (!ipv6_addr_equal(local, &t->parms.raddr) || | 220 | (!ipv6_addr_equal(local, &t->parms.raddr) || |
| 236 | !ipv6_addr_is_multicast(local))) || | 221 | !ipv6_addr_is_multicast(local))) || |
| @@ -256,7 +241,7 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, | |||
| 256 | } | 241 | } |
| 257 | } | 242 | } |
| 258 | 243 | ||
| 259 | for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) { | 244 | for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) { |
| 260 | if (t->parms.i_key != key || | 245 | if (t->parms.i_key != key || |
| 261 | !(t->dev->flags & IFF_UP)) | 246 | !(t->dev->flags & IFF_UP)) |
| 262 | continue; | 247 | continue; |
| @@ -1069,7 +1054,7 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) | |||
| 1069 | dev->mtu = IPV6_MIN_MTU; | 1054 | dev->mtu = IPV6_MIN_MTU; |
| 1070 | } | 1055 | } |
| 1071 | } | 1056 | } |
| 1072 | dst_release(&rt->dst); | 1057 | ip6_rt_put(rt); |
| 1073 | } | 1058 | } |
| 1074 | 1059 | ||
| 1075 | t->hlen = addend; | 1060 | t->hlen = addend; |
| @@ -1161,7 +1146,7 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev, | |||
| 1161 | case SIOCADDTUNNEL: | 1146 | case SIOCADDTUNNEL: |
| 1162 | case SIOCCHGTUNNEL: | 1147 | case SIOCCHGTUNNEL: |
| 1163 | err = -EPERM; | 1148 | err = -EPERM; |
| 1164 | if (!capable(CAP_NET_ADMIN)) | 1149 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1165 | goto done; | 1150 | goto done; |
| 1166 | 1151 | ||
| 1167 | err = -EFAULT; | 1152 | err = -EFAULT; |
| @@ -1209,7 +1194,7 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev, | |||
| 1209 | 1194 | ||
| 1210 | case SIOCDELTUNNEL: | 1195 | case SIOCDELTUNNEL: |
| 1211 | err = -EPERM; | 1196 | err = -EPERM; |
| 1212 | if (!capable(CAP_NET_ADMIN)) | 1197 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1213 | goto done; | 1198 | goto done; |
| 1214 | 1199 | ||
| 1215 | if (dev == ign->fb_tunnel_dev) { | 1200 | if (dev == ign->fb_tunnel_dev) { |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c new file mode 100644 index 000000000000..f26f0da7f095 --- /dev/null +++ b/net/ipv6/ip6_offload.c | |||
| @@ -0,0 +1,282 @@ | |||
| 1 | /* | ||
| 2 | * IPV6 GSO/GRO offload support | ||
| 3 | * Linux INET6 implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/socket.h> | ||
| 13 | #include <linux/netdevice.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/printk.h> | ||
| 16 | |||
| 17 | #include <net/protocol.h> | ||
| 18 | #include <net/ipv6.h> | ||
| 19 | |||
| 20 | #include "ip6_offload.h" | ||
| 21 | |||
| 22 | static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) | ||
| 23 | { | ||
| 24 | const struct net_offload *ops = NULL; | ||
| 25 | |||
| 26 | for (;;) { | ||
| 27 | struct ipv6_opt_hdr *opth; | ||
| 28 | int len; | ||
| 29 | |||
| 30 | if (proto != NEXTHDR_HOP) { | ||
| 31 | ops = rcu_dereference(inet6_offloads[proto]); | ||
| 32 | |||
| 33 | if (unlikely(!ops)) | ||
| 34 | break; | ||
| 35 | |||
| 36 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
| 37 | break; | ||
| 38 | } | ||
| 39 | |||
| 40 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
| 41 | break; | ||
| 42 | |||
| 43 | opth = (void *)skb->data; | ||
| 44 | len = ipv6_optlen(opth); | ||
| 45 | |||
| 46 | if (unlikely(!pskb_may_pull(skb, len))) | ||
| 47 | break; | ||
| 48 | |||
| 49 | proto = opth->nexthdr; | ||
| 50 | __skb_pull(skb, len); | ||
| 51 | } | ||
| 52 | |||
| 53 | return proto; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
| 57 | { | ||
| 58 | const struct ipv6hdr *ipv6h; | ||
| 59 | const struct net_offload *ops; | ||
| 60 | int err = -EINVAL; | ||
| 61 | |||
| 62 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 63 | goto out; | ||
| 64 | |||
| 65 | ipv6h = ipv6_hdr(skb); | ||
| 66 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 67 | err = -EPROTONOSUPPORT; | ||
| 68 | |||
| 69 | rcu_read_lock(); | ||
| 70 | ops = rcu_dereference(inet6_offloads[ | ||
| 71 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
| 72 | |||
| 73 | if (likely(ops && ops->callbacks.gso_send_check)) { | ||
| 74 | skb_reset_transport_header(skb); | ||
| 75 | err = ops->callbacks.gso_send_check(skb); | ||
| 76 | } | ||
| 77 | rcu_read_unlock(); | ||
| 78 | |||
| 79 | out: | ||
| 80 | return err; | ||
| 81 | } | ||
| 82 | |||
| 83 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | ||
| 84 | netdev_features_t features) | ||
| 85 | { | ||
| 86 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 87 | struct ipv6hdr *ipv6h; | ||
| 88 | const struct net_offload *ops; | ||
| 89 | int proto; | ||
| 90 | struct frag_hdr *fptr; | ||
| 91 | unsigned int unfrag_ip6hlen; | ||
| 92 | u8 *prevhdr; | ||
| 93 | int offset = 0; | ||
| 94 | |||
| 95 | if (!(features & NETIF_F_V6_CSUM)) | ||
| 96 | features &= ~NETIF_F_SG; | ||
| 97 | |||
| 98 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 99 | ~(SKB_GSO_UDP | | ||
| 100 | SKB_GSO_DODGY | | ||
| 101 | SKB_GSO_TCP_ECN | | ||
| 102 | SKB_GSO_TCPV6 | | ||
| 103 | 0))) | ||
| 104 | goto out; | ||
| 105 | |||
| 106 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 107 | goto out; | ||
| 108 | |||
| 109 | ipv6h = ipv6_hdr(skb); | ||
| 110 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 111 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
| 112 | |||
| 113 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
| 114 | rcu_read_lock(); | ||
| 115 | ops = rcu_dereference(inet6_offloads[proto]); | ||
| 116 | if (likely(ops && ops->callbacks.gso_segment)) { | ||
| 117 | skb_reset_transport_header(skb); | ||
| 118 | segs = ops->callbacks.gso_segment(skb, features); | ||
| 119 | } | ||
| 120 | rcu_read_unlock(); | ||
| 121 | |||
| 122 | if (IS_ERR(segs)) | ||
| 123 | goto out; | ||
| 124 | |||
| 125 | for (skb = segs; skb; skb = skb->next) { | ||
| 126 | ipv6h = ipv6_hdr(skb); | ||
| 127 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
| 128 | sizeof(*ipv6h)); | ||
| 129 | if (proto == IPPROTO_UDP) { | ||
| 130 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 131 | fptr = (struct frag_hdr *)(skb_network_header(skb) + | ||
| 132 | unfrag_ip6hlen); | ||
| 133 | fptr->frag_off = htons(offset); | ||
| 134 | if (skb->next != NULL) | ||
| 135 | fptr->frag_off |= htons(IP6_MF); | ||
| 136 | offset += (ntohs(ipv6h->payload_len) - | ||
| 137 | sizeof(struct frag_hdr)); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | out: | ||
| 142 | return segs; | ||
| 143 | } | ||
| 144 | |||
| 145 | static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | ||
| 146 | struct sk_buff *skb) | ||
| 147 | { | ||
| 148 | const struct net_offload *ops; | ||
| 149 | struct sk_buff **pp = NULL; | ||
| 150 | struct sk_buff *p; | ||
| 151 | struct ipv6hdr *iph; | ||
| 152 | unsigned int nlen; | ||
| 153 | unsigned int hlen; | ||
| 154 | unsigned int off; | ||
| 155 | int flush = 1; | ||
| 156 | int proto; | ||
| 157 | __wsum csum; | ||
| 158 | |||
| 159 | off = skb_gro_offset(skb); | ||
| 160 | hlen = off + sizeof(*iph); | ||
| 161 | iph = skb_gro_header_fast(skb, off); | ||
| 162 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 163 | iph = skb_gro_header_slow(skb, hlen, off); | ||
| 164 | if (unlikely(!iph)) | ||
| 165 | goto out; | ||
| 166 | } | ||
| 167 | |||
| 168 | skb_gro_pull(skb, sizeof(*iph)); | ||
| 169 | skb_set_transport_header(skb, skb_gro_offset(skb)); | ||
| 170 | |||
| 171 | flush += ntohs(iph->payload_len) != skb_gro_len(skb); | ||
| 172 | |||
| 173 | rcu_read_lock(); | ||
| 174 | proto = iph->nexthdr; | ||
| 175 | ops = rcu_dereference(inet6_offloads[proto]); | ||
| 176 | if (!ops || !ops->callbacks.gro_receive) { | ||
| 177 | __pskb_pull(skb, skb_gro_offset(skb)); | ||
| 178 | proto = ipv6_gso_pull_exthdrs(skb, proto); | ||
| 179 | skb_gro_pull(skb, -skb_transport_offset(skb)); | ||
| 180 | skb_reset_transport_header(skb); | ||
| 181 | __skb_push(skb, skb_gro_offset(skb)); | ||
| 182 | |||
| 183 | ops = rcu_dereference(inet6_offloads[proto]); | ||
| 184 | if (!ops || !ops->callbacks.gro_receive) | ||
| 185 | goto out_unlock; | ||
| 186 | |||
| 187 | iph = ipv6_hdr(skb); | ||
| 188 | } | ||
| 189 | |||
| 190 | NAPI_GRO_CB(skb)->proto = proto; | ||
| 191 | |||
| 192 | flush--; | ||
| 193 | nlen = skb_network_header_len(skb); | ||
| 194 | |||
| 195 | for (p = *head; p; p = p->next) { | ||
| 196 | const struct ipv6hdr *iph2; | ||
| 197 | __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */ | ||
| 198 | |||
| 199 | if (!NAPI_GRO_CB(p)->same_flow) | ||
| 200 | continue; | ||
| 201 | |||
| 202 | iph2 = ipv6_hdr(p); | ||
| 203 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; | ||
| 204 | |||
| 205 | /* All fields must match except length and Traffic Class. */ | ||
| 206 | if (nlen != skb_network_header_len(p) || | ||
| 207 | (first_word & htonl(0xF00FFFFF)) || | ||
| 208 | memcmp(&iph->nexthdr, &iph2->nexthdr, | ||
| 209 | nlen - offsetof(struct ipv6hdr, nexthdr))) { | ||
| 210 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 211 | continue; | ||
| 212 | } | ||
| 213 | /* flush if Traffic Class fields are different */ | ||
| 214 | NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); | ||
| 215 | NAPI_GRO_CB(p)->flush |= flush; | ||
| 216 | } | ||
| 217 | |||
| 218 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 219 | |||
| 220 | csum = skb->csum; | ||
| 221 | skb_postpull_rcsum(skb, iph, skb_network_header_len(skb)); | ||
| 222 | |||
| 223 | pp = ops->callbacks.gro_receive(head, skb); | ||
| 224 | |||
| 225 | skb->csum = csum; | ||
| 226 | |||
| 227 | out_unlock: | ||
| 228 | rcu_read_unlock(); | ||
| 229 | |||
| 230 | out: | ||
| 231 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 232 | |||
| 233 | return pp; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int ipv6_gro_complete(struct sk_buff *skb) | ||
| 237 | { | ||
| 238 | const struct net_offload *ops; | ||
| 239 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 240 | int err = -ENOSYS; | ||
| 241 | |||
| 242 | iph->payload_len = htons(skb->len - skb_network_offset(skb) - | ||
| 243 | sizeof(*iph)); | ||
| 244 | |||
| 245 | rcu_read_lock(); | ||
| 246 | ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]); | ||
| 247 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) | ||
| 248 | goto out_unlock; | ||
| 249 | |||
| 250 | err = ops->callbacks.gro_complete(skb); | ||
| 251 | |||
| 252 | out_unlock: | ||
| 253 | rcu_read_unlock(); | ||
| 254 | |||
| 255 | return err; | ||
| 256 | } | ||
| 257 | |||
| 258 | static struct packet_offload ipv6_packet_offload __read_mostly = { | ||
| 259 | .type = cpu_to_be16(ETH_P_IPV6), | ||
| 260 | .callbacks = { | ||
| 261 | .gso_send_check = ipv6_gso_send_check, | ||
| 262 | .gso_segment = ipv6_gso_segment, | ||
| 263 | .gro_receive = ipv6_gro_receive, | ||
| 264 | .gro_complete = ipv6_gro_complete, | ||
| 265 | }, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static int __init ipv6_offload_init(void) | ||
| 269 | { | ||
| 270 | |||
| 271 | if (tcpv6_offload_init() < 0) | ||
| 272 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); | ||
| 273 | if (udp_offload_init() < 0) | ||
| 274 | pr_crit("%s: Cannot add UDP protocol offload\n", __func__); | ||
| 275 | if (ipv6_exthdrs_offload_init() < 0) | ||
| 276 | pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__); | ||
| 277 | |||
| 278 | dev_add_offload(&ipv6_packet_offload); | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | fs_initcall(ipv6_offload_init); | ||
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h new file mode 100644 index 000000000000..2e155c651b35 --- /dev/null +++ b/net/ipv6/ip6_offload.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* | ||
| 2 | * IPV6 GSO/GRO offload support | ||
| 3 | * Linux INET6 implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef __ip6_offload_h | ||
| 12 | #define __ip6_offload_h | ||
| 13 | |||
| 14 | int ipv6_exthdrs_offload_init(void); | ||
| 15 | int udp_offload_init(void); | ||
| 16 | int tcpv6_offload_init(void); | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index aece3e792f84..5552d13ae92f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -538,78 +538,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
| 538 | to->tc_index = from->tc_index; | 538 | to->tc_index = from->tc_index; |
| 539 | #endif | 539 | #endif |
| 540 | nf_copy(to, from); | 540 | nf_copy(to, from); |
| 541 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 541 | #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) |
| 542 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
| 543 | to->nf_trace = from->nf_trace; | 542 | to->nf_trace = from->nf_trace; |
| 544 | #endif | 543 | #endif |
| 545 | skb_copy_secmark(to, from); | 544 | skb_copy_secmark(to, from); |
| 546 | } | 545 | } |
| 547 | 546 | ||
| 548 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | ||
| 549 | { | ||
| 550 | u16 offset = sizeof(struct ipv6hdr); | ||
| 551 | struct ipv6_opt_hdr *exthdr = | ||
| 552 | (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); | ||
| 553 | unsigned int packet_len = skb->tail - skb->network_header; | ||
| 554 | int found_rhdr = 0; | ||
| 555 | *nexthdr = &ipv6_hdr(skb)->nexthdr; | ||
| 556 | |||
| 557 | while (offset + 1 <= packet_len) { | ||
| 558 | |||
| 559 | switch (**nexthdr) { | ||
| 560 | |||
| 561 | case NEXTHDR_HOP: | ||
| 562 | break; | ||
| 563 | case NEXTHDR_ROUTING: | ||
| 564 | found_rhdr = 1; | ||
| 565 | break; | ||
| 566 | case NEXTHDR_DEST: | ||
| 567 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | ||
| 568 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) | ||
| 569 | break; | ||
| 570 | #endif | ||
| 571 | if (found_rhdr) | ||
| 572 | return offset; | ||
| 573 | break; | ||
| 574 | default : | ||
| 575 | return offset; | ||
| 576 | } | ||
| 577 | |||
| 578 | offset += ipv6_optlen(exthdr); | ||
| 579 | *nexthdr = &exthdr->nexthdr; | ||
| 580 | exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + | ||
| 581 | offset); | ||
| 582 | } | ||
| 583 | |||
| 584 | return offset; | ||
| 585 | } | ||
| 586 | |||
| 587 | void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
| 588 | { | ||
| 589 | static atomic_t ipv6_fragmentation_id; | ||
| 590 | int old, new; | ||
| 591 | |||
| 592 | if (rt && !(rt->dst.flags & DST_NOPEER)) { | ||
| 593 | struct inet_peer *peer; | ||
| 594 | struct net *net; | ||
| 595 | |||
| 596 | net = dev_net(rt->dst.dev); | ||
| 597 | peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); | ||
| 598 | if (peer) { | ||
| 599 | fhdr->identification = htonl(inet_getid(peer, 0)); | ||
| 600 | inet_putpeer(peer); | ||
| 601 | return; | ||
| 602 | } | ||
| 603 | } | ||
| 604 | do { | ||
| 605 | old = atomic_read(&ipv6_fragmentation_id); | ||
| 606 | new = old + 1; | ||
| 607 | if (!new) | ||
| 608 | new = 1; | ||
| 609 | } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); | ||
| 610 | fhdr->identification = htonl(new); | ||
| 611 | } | ||
| 612 | |||
| 613 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 547 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
| 614 | { | 548 | { |
| 615 | struct sk_buff *frag; | 549 | struct sk_buff *frag; |
| @@ -756,7 +690,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 756 | if (err == 0) { | 690 | if (err == 0) { |
| 757 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), | 691 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
| 758 | IPSTATS_MIB_FRAGOKS); | 692 | IPSTATS_MIB_FRAGOKS); |
| 759 | dst_release(&rt->dst); | 693 | ip6_rt_put(rt); |
| 760 | return 0; | 694 | return 0; |
| 761 | } | 695 | } |
| 762 | 696 | ||
| @@ -768,7 +702,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 768 | 702 | ||
| 769 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), | 703 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
| 770 | IPSTATS_MIB_FRAGFAILS); | 704 | IPSTATS_MIB_FRAGFAILS); |
| 771 | dst_release(&rt->dst); | 705 | ip6_rt_put(rt); |
| 772 | return err; | 706 | return err; |
| 773 | 707 | ||
| 774 | slow_path_clean: | 708 | slow_path_clean: |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index cb7e2ded6f08..a14f28b280f5 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -74,6 +74,10 @@ MODULE_ALIAS_NETDEV("ip6tnl0"); | |||
| 74 | #define HASH_SIZE_SHIFT 5 | 74 | #define HASH_SIZE_SHIFT 5 |
| 75 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | 75 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) |
| 76 | 76 | ||
| 77 | static bool log_ecn_error = true; | ||
| 78 | module_param(log_ecn_error, bool, 0644); | ||
| 79 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | ||
| 80 | |||
| 77 | static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) | 81 | static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) |
| 78 | { | 82 | { |
| 79 | u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); | 83 | u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); |
| @@ -83,6 +87,7 @@ static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) | |||
| 83 | 87 | ||
| 84 | static int ip6_tnl_dev_init(struct net_device *dev); | 88 | static int ip6_tnl_dev_init(struct net_device *dev); |
| 85 | static void ip6_tnl_dev_setup(struct net_device *dev); | 89 | static void ip6_tnl_dev_setup(struct net_device *dev); |
| 90 | static struct rtnl_link_ops ip6_link_ops __read_mostly; | ||
| 86 | 91 | ||
| 87 | static int ip6_tnl_net_id __read_mostly; | 92 | static int ip6_tnl_net_id __read_mostly; |
| 88 | struct ip6_tnl_net { | 93 | struct ip6_tnl_net { |
| @@ -94,14 +99,6 @@ struct ip6_tnl_net { | |||
| 94 | struct ip6_tnl __rcu **tnls[2]; | 99 | struct ip6_tnl __rcu **tnls[2]; |
| 95 | }; | 100 | }; |
| 96 | 101 | ||
| 97 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
| 98 | struct pcpu_tstats { | ||
| 99 | unsigned long rx_packets; | ||
| 100 | unsigned long rx_bytes; | ||
| 101 | unsigned long tx_packets; | ||
| 102 | unsigned long tx_bytes; | ||
| 103 | } __attribute__((aligned(4*sizeof(unsigned long)))); | ||
| 104 | |||
| 105 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) | 102 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) |
| 106 | { | 103 | { |
| 107 | struct pcpu_tstats sum = { 0 }; | 104 | struct pcpu_tstats sum = { 0 }; |
| @@ -258,6 +255,33 @@ static void ip6_dev_free(struct net_device *dev) | |||
| 258 | free_netdev(dev); | 255 | free_netdev(dev); |
| 259 | } | 256 | } |
| 260 | 257 | ||
| 258 | static int ip6_tnl_create2(struct net_device *dev) | ||
| 259 | { | ||
| 260 | struct ip6_tnl *t = netdev_priv(dev); | ||
| 261 | struct net *net = dev_net(dev); | ||
| 262 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 263 | int err; | ||
| 264 | |||
| 265 | t = netdev_priv(dev); | ||
| 266 | err = ip6_tnl_dev_init(dev); | ||
| 267 | if (err < 0) | ||
| 268 | goto out; | ||
| 269 | |||
| 270 | err = register_netdevice(dev); | ||
| 271 | if (err < 0) | ||
| 272 | goto out; | ||
| 273 | |||
| 274 | strcpy(t->parms.name, dev->name); | ||
| 275 | dev->rtnl_link_ops = &ip6_link_ops; | ||
| 276 | |||
| 277 | dev_hold(dev); | ||
| 278 | ip6_tnl_link(ip6n, t); | ||
| 279 | return 0; | ||
| 280 | |||
| 281 | out: | ||
| 282 | return err; | ||
| 283 | } | ||
| 284 | |||
| 261 | /** | 285 | /** |
| 262 | * ip6_tnl_create - create a new tunnel | 286 | * ip6_tnl_create - create a new tunnel |
| 263 | * @p: tunnel parameters | 287 | * @p: tunnel parameters |
| @@ -276,7 +300,6 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) | |||
| 276 | struct ip6_tnl *t; | 300 | struct ip6_tnl *t; |
| 277 | char name[IFNAMSIZ]; | 301 | char name[IFNAMSIZ]; |
| 278 | int err; | 302 | int err; |
| 279 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 280 | 303 | ||
| 281 | if (p->name[0]) | 304 | if (p->name[0]) |
| 282 | strlcpy(name, p->name, IFNAMSIZ); | 305 | strlcpy(name, p->name, IFNAMSIZ); |
| @@ -291,17 +314,10 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) | |||
| 291 | 314 | ||
| 292 | t = netdev_priv(dev); | 315 | t = netdev_priv(dev); |
| 293 | t->parms = *p; | 316 | t->parms = *p; |
| 294 | err = ip6_tnl_dev_init(dev); | 317 | err = ip6_tnl_create2(dev); |
| 295 | if (err < 0) | 318 | if (err < 0) |
| 296 | goto failed_free; | 319 | goto failed_free; |
| 297 | 320 | ||
| 298 | if ((err = register_netdevice(dev)) < 0) | ||
| 299 | goto failed_free; | ||
| 300 | |||
| 301 | strcpy(t->parms.name, dev->name); | ||
| 302 | |||
| 303 | dev_hold(dev); | ||
| 304 | ip6_tnl_link(ip6n, t); | ||
| 305 | return t; | 321 | return t; |
| 306 | 322 | ||
| 307 | failed_free: | 323 | failed_free: |
| @@ -663,8 +679,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 663 | 679 | ||
| 664 | icmpv6_send(skb2, rel_type, rel_code, rel_info); | 680 | icmpv6_send(skb2, rel_type, rel_code, rel_info); |
| 665 | 681 | ||
| 666 | if (rt) | 682 | ip6_rt_put(rt); |
| 667 | dst_release(&rt->dst); | ||
| 668 | 683 | ||
| 669 | kfree_skb(skb2); | 684 | kfree_skb(skb2); |
| 670 | } | 685 | } |
| @@ -672,28 +687,26 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 672 | return 0; | 687 | return 0; |
| 673 | } | 688 | } |
| 674 | 689 | ||
| 675 | static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | 690 | static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
| 676 | const struct ipv6hdr *ipv6h, | 691 | const struct ipv6hdr *ipv6h, |
| 677 | struct sk_buff *skb) | 692 | struct sk_buff *skb) |
| 678 | { | 693 | { |
| 679 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; | 694 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; |
| 680 | 695 | ||
| 681 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | 696 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) |
| 682 | ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); | 697 | ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); |
| 683 | 698 | ||
| 684 | if (INET_ECN_is_ce(dsfield)) | 699 | return IP6_ECN_decapsulate(ipv6h, skb); |
| 685 | IP_ECN_set_ce(ip_hdr(skb)); | ||
| 686 | } | 700 | } |
| 687 | 701 | ||
| 688 | static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | 702 | static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
| 689 | const struct ipv6hdr *ipv6h, | 703 | const struct ipv6hdr *ipv6h, |
| 690 | struct sk_buff *skb) | 704 | struct sk_buff *skb) |
| 691 | { | 705 | { |
| 692 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | 706 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) |
| 693 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); | 707 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); |
| 694 | 708 | ||
| 695 | if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h))) | 709 | return IP6_ECN_decapsulate(ipv6h, skb); |
| 696 | IP6_ECN_set_ce(ipv6_hdr(skb)); | ||
| 697 | } | 710 | } |
| 698 | 711 | ||
| 699 | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | 712 | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, |
| @@ -757,12 +770,13 @@ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); | |||
| 757 | 770 | ||
| 758 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | 771 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, |
| 759 | __u8 ipproto, | 772 | __u8 ipproto, |
| 760 | void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, | 773 | int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, |
| 761 | const struct ipv6hdr *ipv6h, | 774 | const struct ipv6hdr *ipv6h, |
| 762 | struct sk_buff *skb)) | 775 | struct sk_buff *skb)) |
| 763 | { | 776 | { |
| 764 | struct ip6_tnl *t; | 777 | struct ip6_tnl *t; |
| 765 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 778 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
| 779 | int err; | ||
| 766 | 780 | ||
| 767 | rcu_read_lock(); | 781 | rcu_read_lock(); |
| 768 | 782 | ||
| @@ -792,14 +806,26 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
| 792 | skb->pkt_type = PACKET_HOST; | 806 | skb->pkt_type = PACKET_HOST; |
| 793 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); | 807 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
| 794 | 808 | ||
| 809 | __skb_tunnel_rx(skb, t->dev); | ||
| 810 | |||
| 811 | err = dscp_ecn_decapsulate(t, ipv6h, skb); | ||
| 812 | if (unlikely(err)) { | ||
| 813 | if (log_ecn_error) | ||
| 814 | net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n", | ||
| 815 | &ipv6h->saddr, | ||
| 816 | ipv6_get_dsfield(ipv6h)); | ||
| 817 | if (err > 1) { | ||
| 818 | ++t->dev->stats.rx_frame_errors; | ||
| 819 | ++t->dev->stats.rx_errors; | ||
| 820 | rcu_read_unlock(); | ||
| 821 | goto discard; | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 795 | tstats = this_cpu_ptr(t->dev->tstats); | 825 | tstats = this_cpu_ptr(t->dev->tstats); |
| 796 | tstats->rx_packets++; | 826 | tstats->rx_packets++; |
| 797 | tstats->rx_bytes += skb->len; | 827 | tstats->rx_bytes += skb->len; |
| 798 | 828 | ||
| 799 | __skb_tunnel_rx(skb, t->dev); | ||
| 800 | |||
| 801 | dscp_ecn_decapsulate(t, ipv6h, skb); | ||
| 802 | |||
| 803 | netif_rx(skb); | 829 | netif_rx(skb); |
| 804 | 830 | ||
| 805 | rcu_read_unlock(); | 831 | rcu_read_unlock(); |
| @@ -1208,7 +1234,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
| 1208 | if (dev->mtu < IPV6_MIN_MTU) | 1234 | if (dev->mtu < IPV6_MIN_MTU) |
| 1209 | dev->mtu = IPV6_MIN_MTU; | 1235 | dev->mtu = IPV6_MIN_MTU; |
| 1210 | } | 1236 | } |
| 1211 | dst_release(&rt->dst); | 1237 | ip6_rt_put(rt); |
| 1212 | } | 1238 | } |
| 1213 | } | 1239 | } |
| 1214 | 1240 | ||
| @@ -1237,6 +1263,20 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) | |||
| 1237 | return 0; | 1263 | return 0; |
| 1238 | } | 1264 | } |
| 1239 | 1265 | ||
| 1266 | static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) | ||
| 1267 | { | ||
| 1268 | struct net *net = dev_net(t->dev); | ||
| 1269 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 1270 | int err; | ||
| 1271 | |||
| 1272 | ip6_tnl_unlink(ip6n, t); | ||
| 1273 | synchronize_net(); | ||
| 1274 | err = ip6_tnl_change(t, p); | ||
| 1275 | ip6_tnl_link(ip6n, t); | ||
| 1276 | netdev_state_change(t->dev); | ||
| 1277 | return err; | ||
| 1278 | } | ||
| 1279 | |||
| 1240 | static void | 1280 | static void |
| 1241 | ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) | 1281 | ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) |
| 1242 | { | 1282 | { |
| @@ -1325,7 +1365,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1325 | case SIOCADDTUNNEL: | 1365 | case SIOCADDTUNNEL: |
| 1326 | case SIOCCHGTUNNEL: | 1366 | case SIOCCHGTUNNEL: |
| 1327 | err = -EPERM; | 1367 | err = -EPERM; |
| 1328 | if (!capable(CAP_NET_ADMIN)) | 1368 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1329 | break; | 1369 | break; |
| 1330 | err = -EFAULT; | 1370 | err = -EFAULT; |
| 1331 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | 1371 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) |
| @@ -1345,11 +1385,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1345 | } else | 1385 | } else |
| 1346 | t = netdev_priv(dev); | 1386 | t = netdev_priv(dev); |
| 1347 | 1387 | ||
| 1348 | ip6_tnl_unlink(ip6n, t); | 1388 | err = ip6_tnl_update(t, &p1); |
| 1349 | synchronize_net(); | ||
| 1350 | err = ip6_tnl_change(t, &p1); | ||
| 1351 | ip6_tnl_link(ip6n, t); | ||
| 1352 | netdev_state_change(dev); | ||
| 1353 | } | 1389 | } |
| 1354 | if (t) { | 1390 | if (t) { |
| 1355 | err = 0; | 1391 | err = 0; |
| @@ -1362,7 +1398,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1362 | break; | 1398 | break; |
| 1363 | case SIOCDELTUNNEL: | 1399 | case SIOCDELTUNNEL: |
| 1364 | err = -EPERM; | 1400 | err = -EPERM; |
| 1365 | if (!capable(CAP_NET_ADMIN)) | 1401 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1366 | break; | 1402 | break; |
| 1367 | 1403 | ||
| 1368 | if (dev == ip6n->fb_tnl_dev) { | 1404 | if (dev == ip6n->fb_tnl_dev) { |
| @@ -1505,6 +1541,164 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev) | |||
| 1505 | return 0; | 1541 | return 0; |
| 1506 | } | 1542 | } |
| 1507 | 1543 | ||
| 1544 | static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
| 1545 | { | ||
| 1546 | u8 proto; | ||
| 1547 | |||
| 1548 | if (!data) | ||
| 1549 | return 0; | ||
| 1550 | |||
| 1551 | proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); | ||
| 1552 | if (proto != IPPROTO_IPV6 && | ||
| 1553 | proto != IPPROTO_IPIP && | ||
| 1554 | proto != 0) | ||
| 1555 | return -EINVAL; | ||
| 1556 | |||
| 1557 | return 0; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | static void ip6_tnl_netlink_parms(struct nlattr *data[], | ||
| 1561 | struct __ip6_tnl_parm *parms) | ||
| 1562 | { | ||
| 1563 | memset(parms, 0, sizeof(*parms)); | ||
| 1564 | |||
| 1565 | if (!data) | ||
| 1566 | return; | ||
| 1567 | |||
| 1568 | if (data[IFLA_IPTUN_LINK]) | ||
| 1569 | parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); | ||
| 1570 | |||
| 1571 | if (data[IFLA_IPTUN_LOCAL]) | ||
| 1572 | nla_memcpy(&parms->laddr, data[IFLA_IPTUN_LOCAL], | ||
| 1573 | sizeof(struct in6_addr)); | ||
| 1574 | |||
| 1575 | if (data[IFLA_IPTUN_REMOTE]) | ||
| 1576 | nla_memcpy(&parms->raddr, data[IFLA_IPTUN_REMOTE], | ||
| 1577 | sizeof(struct in6_addr)); | ||
| 1578 | |||
| 1579 | if (data[IFLA_IPTUN_TTL]) | ||
| 1580 | parms->hop_limit = nla_get_u8(data[IFLA_IPTUN_TTL]); | ||
| 1581 | |||
| 1582 | if (data[IFLA_IPTUN_ENCAP_LIMIT]) | ||
| 1583 | parms->encap_limit = nla_get_u8(data[IFLA_IPTUN_ENCAP_LIMIT]); | ||
| 1584 | |||
| 1585 | if (data[IFLA_IPTUN_FLOWINFO]) | ||
| 1586 | parms->flowinfo = nla_get_be32(data[IFLA_IPTUN_FLOWINFO]); | ||
| 1587 | |||
| 1588 | if (data[IFLA_IPTUN_FLAGS]) | ||
| 1589 | parms->flags = nla_get_u32(data[IFLA_IPTUN_FLAGS]); | ||
| 1590 | |||
| 1591 | if (data[IFLA_IPTUN_PROTO]) | ||
| 1592 | parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, | ||
| 1596 | struct nlattr *tb[], struct nlattr *data[]) | ||
| 1597 | { | ||
| 1598 | struct net *net = dev_net(dev); | ||
| 1599 | struct ip6_tnl *nt; | ||
| 1600 | |||
| 1601 | nt = netdev_priv(dev); | ||
| 1602 | ip6_tnl_netlink_parms(data, &nt->parms); | ||
| 1603 | |||
| 1604 | if (ip6_tnl_locate(net, &nt->parms, 0)) | ||
| 1605 | return -EEXIST; | ||
| 1606 | |||
| 1607 | return ip6_tnl_create2(dev); | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], | ||
| 1611 | struct nlattr *data[]) | ||
| 1612 | { | ||
| 1613 | struct ip6_tnl *t; | ||
| 1614 | struct __ip6_tnl_parm p; | ||
| 1615 | struct net *net = dev_net(dev); | ||
| 1616 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
| 1617 | |||
| 1618 | if (dev == ip6n->fb_tnl_dev) | ||
| 1619 | return -EINVAL; | ||
| 1620 | |||
| 1621 | ip6_tnl_netlink_parms(data, &p); | ||
| 1622 | |||
| 1623 | t = ip6_tnl_locate(net, &p, 0); | ||
| 1624 | |||
| 1625 | if (t) { | ||
| 1626 | if (t->dev != dev) | ||
| 1627 | return -EEXIST; | ||
| 1628 | } else | ||
| 1629 | t = netdev_priv(dev); | ||
| 1630 | |||
| 1631 | return ip6_tnl_update(t, &p); | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | static size_t ip6_tnl_get_size(const struct net_device *dev) | ||
| 1635 | { | ||
| 1636 | return | ||
| 1637 | /* IFLA_IPTUN_LINK */ | ||
| 1638 | nla_total_size(4) + | ||
| 1639 | /* IFLA_IPTUN_LOCAL */ | ||
| 1640 | nla_total_size(sizeof(struct in6_addr)) + | ||
| 1641 | /* IFLA_IPTUN_REMOTE */ | ||
| 1642 | nla_total_size(sizeof(struct in6_addr)) + | ||
| 1643 | /* IFLA_IPTUN_TTL */ | ||
| 1644 | nla_total_size(1) + | ||
| 1645 | /* IFLA_IPTUN_ENCAP_LIMIT */ | ||
| 1646 | nla_total_size(1) + | ||
| 1647 | /* IFLA_IPTUN_FLOWINFO */ | ||
| 1648 | nla_total_size(4) + | ||
| 1649 | /* IFLA_IPTUN_FLAGS */ | ||
| 1650 | nla_total_size(4) + | ||
| 1651 | /* IFLA_IPTUN_PROTO */ | ||
| 1652 | nla_total_size(1) + | ||
| 1653 | 0; | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) | ||
| 1657 | { | ||
| 1658 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
| 1659 | struct __ip6_tnl_parm *parm = &tunnel->parms; | ||
| 1660 | |||
| 1661 | if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || | ||
| 1662 | nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr), | ||
| 1663 | &parm->raddr) || | ||
| 1664 | nla_put(skb, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr), | ||
| 1665 | &parm->laddr) || | ||
| 1666 | nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) || | ||
| 1667 | nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || | ||
| 1668 | nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || | ||
| 1669 | nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || | ||
| 1670 | nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto)) | ||
| 1671 | goto nla_put_failure; | ||
| 1672 | return 0; | ||
| 1673 | |||
| 1674 | nla_put_failure: | ||
| 1675 | return -EMSGSIZE; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { | ||
| 1679 | [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, | ||
| 1680 | [IFLA_IPTUN_LOCAL] = { .len = sizeof(struct in6_addr) }, | ||
| 1681 | [IFLA_IPTUN_REMOTE] = { .len = sizeof(struct in6_addr) }, | ||
| 1682 | [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, | ||
| 1683 | [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, | ||
| 1684 | [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, | ||
| 1685 | [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, | ||
| 1686 | [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, | ||
| 1687 | }; | ||
| 1688 | |||
| 1689 | static struct rtnl_link_ops ip6_link_ops __read_mostly = { | ||
| 1690 | .kind = "ip6tnl", | ||
| 1691 | .maxtype = IFLA_IPTUN_MAX, | ||
| 1692 | .policy = ip6_tnl_policy, | ||
| 1693 | .priv_size = sizeof(struct ip6_tnl), | ||
| 1694 | .setup = ip6_tnl_dev_setup, | ||
| 1695 | .validate = ip6_tnl_validate, | ||
| 1696 | .newlink = ip6_tnl_newlink, | ||
| 1697 | .changelink = ip6_tnl_changelink, | ||
| 1698 | .get_size = ip6_tnl_get_size, | ||
| 1699 | .fill_info = ip6_tnl_fill_info, | ||
| 1700 | }; | ||
| 1701 | |||
| 1508 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { | 1702 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { |
| 1509 | .handler = ip4ip6_rcv, | 1703 | .handler = ip4ip6_rcv, |
| 1510 | .err_handler = ip4ip6_err, | 1704 | .err_handler = ip4ip6_err, |
| @@ -1613,9 +1807,14 @@ static int __init ip6_tunnel_init(void) | |||
| 1613 | pr_err("%s: can't register ip6ip6\n", __func__); | 1807 | pr_err("%s: can't register ip6ip6\n", __func__); |
| 1614 | goto out_ip6ip6; | 1808 | goto out_ip6ip6; |
| 1615 | } | 1809 | } |
| 1810 | err = rtnl_link_register(&ip6_link_ops); | ||
| 1811 | if (err < 0) | ||
| 1812 | goto rtnl_link_failed; | ||
| 1616 | 1813 | ||
| 1617 | return 0; | 1814 | return 0; |
| 1618 | 1815 | ||
| 1816 | rtnl_link_failed: | ||
| 1817 | xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); | ||
| 1619 | out_ip6ip6: | 1818 | out_ip6ip6: |
| 1620 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); | 1819 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); |
| 1621 | out_ip4ip6: | 1820 | out_ip4ip6: |
| @@ -1630,6 +1829,7 @@ out_pernet: | |||
| 1630 | 1829 | ||
| 1631 | static void __exit ip6_tunnel_cleanup(void) | 1830 | static void __exit ip6_tunnel_cleanup(void) |
| 1632 | { | 1831 | { |
| 1832 | rtnl_link_unregister(&ip6_link_ops); | ||
| 1633 | if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET)) | 1833 | if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET)) |
| 1634 | pr_info("%s: can't deregister ip4ip6\n", __func__); | 1834 | pr_info("%s: can't deregister ip4ip6\n", __func__); |
| 1635 | 1835 | ||
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index f7c7c6319720..26dcdec9e3a5 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include <linux/netfilter_ipv6.h> | 52 | #include <linux/netfilter_ipv6.h> |
| 53 | #include <linux/export.h> | 53 | #include <linux/export.h> |
| 54 | #include <net/ip6_checksum.h> | 54 | #include <net/ip6_checksum.h> |
| 55 | #include <linux/netconf.h> | ||
| 55 | 56 | ||
| 56 | struct mr6_table { | 57 | struct mr6_table { |
| 57 | struct list_head list; | 58 | struct list_head list; |
| @@ -66,8 +67,8 @@ struct mr6_table { | |||
| 66 | struct mif_device vif6_table[MAXMIFS]; | 67 | struct mif_device vif6_table[MAXMIFS]; |
| 67 | int maxvif; | 68 | int maxvif; |
| 68 | atomic_t cache_resolve_queue_len; | 69 | atomic_t cache_resolve_queue_len; |
| 69 | int mroute_do_assert; | 70 | bool mroute_do_assert; |
| 70 | int mroute_do_pim; | 71 | bool mroute_do_pim; |
| 71 | #ifdef CONFIG_IPV6_PIMSM_V2 | 72 | #ifdef CONFIG_IPV6_PIMSM_V2 |
| 72 | int mroute_reg_vif_num; | 73 | int mroute_reg_vif_num; |
| 73 | #endif | 74 | #endif |
| @@ -115,6 +116,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, | |||
| 115 | mifi_t mifi, int assert); | 116 | mifi_t mifi, int assert); |
| 116 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 117 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
| 117 | struct mfc6_cache *c, struct rtmsg *rtm); | 118 | struct mfc6_cache *c, struct rtmsg *rtm); |
| 119 | static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, | ||
| 120 | int cmd); | ||
| 118 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, | 121 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, |
| 119 | struct netlink_callback *cb); | 122 | struct netlink_callback *cb); |
| 120 | static void mroute_clean_tables(struct mr6_table *mrt); | 123 | static void mroute_clean_tables(struct mr6_table *mrt); |
| @@ -805,8 +808,12 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) | |||
| 805 | dev_set_allmulti(dev, -1); | 808 | dev_set_allmulti(dev, -1); |
| 806 | 809 | ||
| 807 | in6_dev = __in6_dev_get(dev); | 810 | in6_dev = __in6_dev_get(dev); |
| 808 | if (in6_dev) | 811 | if (in6_dev) { |
| 809 | in6_dev->cnf.mc_forwarding--; | 812 | in6_dev->cnf.mc_forwarding--; |
| 813 | inet6_netconf_notify_devconf(dev_net(dev), | ||
| 814 | NETCONFA_MC_FORWARDING, | ||
| 815 | dev->ifindex, &in6_dev->cnf); | ||
| 816 | } | ||
| 810 | 817 | ||
| 811 | if (v->flags & MIFF_REGISTER) | 818 | if (v->flags & MIFF_REGISTER) |
| 812 | unregister_netdevice_queue(dev, head); | 819 | unregister_netdevice_queue(dev, head); |
| @@ -865,6 +872,7 @@ static void ipmr_do_expire_process(struct mr6_table *mrt) | |||
| 865 | } | 872 | } |
| 866 | 873 | ||
| 867 | list_del(&c->list); | 874 | list_del(&c->list); |
| 875 | mr6_netlink_event(mrt, c, RTM_DELROUTE); | ||
| 868 | ip6mr_destroy_unres(mrt, c); | 876 | ip6mr_destroy_unres(mrt, c); |
| 869 | } | 877 | } |
| 870 | 878 | ||
| @@ -958,8 +966,12 @@ static int mif6_add(struct net *net, struct mr6_table *mrt, | |||
| 958 | } | 966 | } |
| 959 | 967 | ||
| 960 | in6_dev = __in6_dev_get(dev); | 968 | in6_dev = __in6_dev_get(dev); |
| 961 | if (in6_dev) | 969 | if (in6_dev) { |
| 962 | in6_dev->cnf.mc_forwarding++; | 970 | in6_dev->cnf.mc_forwarding++; |
| 971 | inet6_netconf_notify_devconf(dev_net(dev), | ||
| 972 | NETCONFA_MC_FORWARDING, | ||
| 973 | dev->ifindex, &in6_dev->cnf); | ||
| 974 | } | ||
| 963 | 975 | ||
| 964 | /* | 976 | /* |
| 965 | * Fill in the VIF structures | 977 | * Fill in the VIF structures |
| @@ -1211,6 +1223,7 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb) | |||
| 1211 | 1223 | ||
| 1212 | atomic_inc(&mrt->cache_resolve_queue_len); | 1224 | atomic_inc(&mrt->cache_resolve_queue_len); |
| 1213 | list_add(&c->list, &mrt->mfc6_unres_queue); | 1225 | list_add(&c->list, &mrt->mfc6_unres_queue); |
| 1226 | mr6_netlink_event(mrt, c, RTM_NEWROUTE); | ||
| 1214 | 1227 | ||
| 1215 | ipmr_do_expire_process(mrt); | 1228 | ipmr_do_expire_process(mrt); |
| 1216 | } | 1229 | } |
| @@ -1248,6 +1261,7 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | |||
| 1248 | list_del(&c->list); | 1261 | list_del(&c->list); |
| 1249 | write_unlock_bh(&mrt_lock); | 1262 | write_unlock_bh(&mrt_lock); |
| 1250 | 1263 | ||
| 1264 | mr6_netlink_event(mrt, c, RTM_DELROUTE); | ||
| 1251 | ip6mr_cache_free(c); | 1265 | ip6mr_cache_free(c); |
| 1252 | return 0; | 1266 | return 0; |
| 1253 | } | 1267 | } |
| @@ -1412,6 +1426,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
| 1412 | if (!mrtsock) | 1426 | if (!mrtsock) |
| 1413 | c->mfc_flags |= MFC_STATIC; | 1427 | c->mfc_flags |= MFC_STATIC; |
| 1414 | write_unlock_bh(&mrt_lock); | 1428 | write_unlock_bh(&mrt_lock); |
| 1429 | mr6_netlink_event(mrt, c, RTM_NEWROUTE); | ||
| 1415 | return 0; | 1430 | return 0; |
| 1416 | } | 1431 | } |
| 1417 | 1432 | ||
| @@ -1456,6 +1471,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
| 1456 | ip6mr_cache_resolve(net, mrt, uc, c); | 1471 | ip6mr_cache_resolve(net, mrt, uc, c); |
| 1457 | ip6mr_cache_free(uc); | 1472 | ip6mr_cache_free(uc); |
| 1458 | } | 1473 | } |
| 1474 | mr6_netlink_event(mrt, c, RTM_NEWROUTE); | ||
| 1459 | return 0; | 1475 | return 0; |
| 1460 | } | 1476 | } |
| 1461 | 1477 | ||
| @@ -1489,6 +1505,7 @@ static void mroute_clean_tables(struct mr6_table *mrt) | |||
| 1489 | list_del(&c->list); | 1505 | list_del(&c->list); |
| 1490 | write_unlock_bh(&mrt_lock); | 1506 | write_unlock_bh(&mrt_lock); |
| 1491 | 1507 | ||
| 1508 | mr6_netlink_event(mrt, c, RTM_DELROUTE); | ||
| 1492 | ip6mr_cache_free(c); | 1509 | ip6mr_cache_free(c); |
| 1493 | } | 1510 | } |
| 1494 | } | 1511 | } |
| @@ -1497,6 +1514,7 @@ static void mroute_clean_tables(struct mr6_table *mrt) | |||
| 1497 | spin_lock_bh(&mfc_unres_lock); | 1514 | spin_lock_bh(&mfc_unres_lock); |
| 1498 | list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) { | 1515 | list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) { |
| 1499 | list_del(&c->list); | 1516 | list_del(&c->list); |
| 1517 | mr6_netlink_event(mrt, c, RTM_DELROUTE); | ||
| 1500 | ip6mr_destroy_unres(mrt, c); | 1518 | ip6mr_destroy_unres(mrt, c); |
| 1501 | } | 1519 | } |
| 1502 | spin_unlock_bh(&mfc_unres_lock); | 1520 | spin_unlock_bh(&mfc_unres_lock); |
| @@ -1513,6 +1531,9 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk) | |||
| 1513 | if (likely(mrt->mroute6_sk == NULL)) { | 1531 | if (likely(mrt->mroute6_sk == NULL)) { |
| 1514 | mrt->mroute6_sk = sk; | 1532 | mrt->mroute6_sk = sk; |
| 1515 | net->ipv6.devconf_all->mc_forwarding++; | 1533 | net->ipv6.devconf_all->mc_forwarding++; |
| 1534 | inet6_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING, | ||
| 1535 | NETCONFA_IFINDEX_ALL, | ||
| 1536 | net->ipv6.devconf_all); | ||
| 1516 | } | 1537 | } |
| 1517 | else | 1538 | else |
| 1518 | err = -EADDRINUSE; | 1539 | err = -EADDRINUSE; |
| @@ -1535,6 +1556,10 @@ int ip6mr_sk_done(struct sock *sk) | |||
| 1535 | write_lock_bh(&mrt_lock); | 1556 | write_lock_bh(&mrt_lock); |
| 1536 | mrt->mroute6_sk = NULL; | 1557 | mrt->mroute6_sk = NULL; |
| 1537 | net->ipv6.devconf_all->mc_forwarding--; | 1558 | net->ipv6.devconf_all->mc_forwarding--; |
| 1559 | inet6_netconf_notify_devconf(net, | ||
| 1560 | NETCONFA_MC_FORWARDING, | ||
| 1561 | NETCONFA_IFINDEX_ALL, | ||
| 1562 | net->ipv6.devconf_all); | ||
| 1538 | write_unlock_bh(&mrt_lock); | 1563 | write_unlock_bh(&mrt_lock); |
| 1539 | 1564 | ||
| 1540 | mroute_clean_tables(mrt); | 1565 | mroute_clean_tables(mrt); |
| @@ -1583,7 +1608,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1583 | return -ENOENT; | 1608 | return -ENOENT; |
| 1584 | 1609 | ||
| 1585 | if (optname != MRT6_INIT) { | 1610 | if (optname != MRT6_INIT) { |
| 1586 | if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN)) | 1611 | if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1587 | return -EACCES; | 1612 | return -EACCES; |
| 1588 | } | 1613 | } |
| 1589 | 1614 | ||
| @@ -1646,9 +1671,12 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1646 | case MRT6_ASSERT: | 1671 | case MRT6_ASSERT: |
| 1647 | { | 1672 | { |
| 1648 | int v; | 1673 | int v; |
| 1674 | |||
| 1675 | if (optlen != sizeof(v)) | ||
| 1676 | return -EINVAL; | ||
| 1649 | if (get_user(v, (int __user *)optval)) | 1677 | if (get_user(v, (int __user *)optval)) |
| 1650 | return -EFAULT; | 1678 | return -EFAULT; |
| 1651 | mrt->mroute_do_assert = !!v; | 1679 | mrt->mroute_do_assert = v; |
| 1652 | return 0; | 1680 | return 0; |
| 1653 | } | 1681 | } |
| 1654 | 1682 | ||
| @@ -1656,6 +1684,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1656 | case MRT6_PIM: | 1684 | case MRT6_PIM: |
| 1657 | { | 1685 | { |
| 1658 | int v; | 1686 | int v; |
| 1687 | |||
| 1688 | if (optlen != sizeof(v)) | ||
| 1689 | return -EINVAL; | ||
| 1659 | if (get_user(v, (int __user *)optval)) | 1690 | if (get_user(v, (int __user *)optval)) |
| 1660 | return -EFAULT; | 1691 | return -EFAULT; |
| 1661 | v = !!v; | 1692 | v = !!v; |
| @@ -2097,8 +2128,8 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | |||
| 2097 | { | 2128 | { |
| 2098 | int ct; | 2129 | int ct; |
| 2099 | struct rtnexthop *nhp; | 2130 | struct rtnexthop *nhp; |
| 2100 | u8 *b = skb_tail_pointer(skb); | 2131 | struct nlattr *mp_attr; |
| 2101 | struct rtattr *mp_head; | 2132 | struct rta_mfc_stats mfcs; |
| 2102 | 2133 | ||
| 2103 | /* If cache is unresolved, don't try to parse IIF and OIF */ | 2134 | /* If cache is unresolved, don't try to parse IIF and OIF */ |
| 2104 | if (c->mf6c_parent >= MAXMIFS) | 2135 | if (c->mf6c_parent >= MAXMIFS) |
| @@ -2107,28 +2138,35 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | |||
| 2107 | if (MIF_EXISTS(mrt, c->mf6c_parent) && | 2138 | if (MIF_EXISTS(mrt, c->mf6c_parent) && |
| 2108 | nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0) | 2139 | nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0) |
| 2109 | return -EMSGSIZE; | 2140 | return -EMSGSIZE; |
| 2110 | 2141 | mp_attr = nla_nest_start(skb, RTA_MULTIPATH); | |
| 2111 | mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); | 2142 | if (mp_attr == NULL) |
| 2143 | return -EMSGSIZE; | ||
| 2112 | 2144 | ||
| 2113 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { | 2145 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { |
| 2114 | if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) { | 2146 | if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) { |
| 2115 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) | 2147 | nhp = nla_reserve_nohdr(skb, sizeof(*nhp)); |
| 2116 | goto rtattr_failure; | 2148 | if (nhp == NULL) { |
| 2117 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); | 2149 | nla_nest_cancel(skb, mp_attr); |
| 2150 | return -EMSGSIZE; | ||
| 2151 | } | ||
| 2152 | |||
| 2118 | nhp->rtnh_flags = 0; | 2153 | nhp->rtnh_flags = 0; |
| 2119 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; | 2154 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; |
| 2120 | nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex; | 2155 | nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex; |
| 2121 | nhp->rtnh_len = sizeof(*nhp); | 2156 | nhp->rtnh_len = sizeof(*nhp); |
| 2122 | } | 2157 | } |
| 2123 | } | 2158 | } |
| 2124 | mp_head->rta_type = RTA_MULTIPATH; | 2159 | |
| 2125 | mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head; | 2160 | nla_nest_end(skb, mp_attr); |
| 2161 | |||
| 2162 | mfcs.mfcs_packets = c->mfc_un.res.pkt; | ||
| 2163 | mfcs.mfcs_bytes = c->mfc_un.res.bytes; | ||
| 2164 | mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if; | ||
| 2165 | if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0) | ||
| 2166 | return -EMSGSIZE; | ||
| 2167 | |||
| 2126 | rtm->rtm_type = RTN_MULTICAST; | 2168 | rtm->rtm_type = RTN_MULTICAST; |
| 2127 | return 1; | 2169 | return 1; |
| 2128 | |||
| 2129 | rtattr_failure: | ||
| 2130 | nlmsg_trim(skb, b); | ||
| 2131 | return -EMSGSIZE; | ||
| 2132 | } | 2170 | } |
| 2133 | 2171 | ||
| 2134 | int ip6mr_get_route(struct net *net, | 2172 | int ip6mr_get_route(struct net *net, |
| @@ -2202,31 +2240,38 @@ int ip6mr_get_route(struct net *net, | |||
| 2202 | } | 2240 | } |
| 2203 | 2241 | ||
| 2204 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 2242 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
| 2205 | u32 portid, u32 seq, struct mfc6_cache *c) | 2243 | u32 portid, u32 seq, struct mfc6_cache *c, int cmd) |
| 2206 | { | 2244 | { |
| 2207 | struct nlmsghdr *nlh; | 2245 | struct nlmsghdr *nlh; |
| 2208 | struct rtmsg *rtm; | 2246 | struct rtmsg *rtm; |
| 2247 | int err; | ||
| 2209 | 2248 | ||
| 2210 | nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI); | 2249 | nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI); |
| 2211 | if (nlh == NULL) | 2250 | if (nlh == NULL) |
| 2212 | return -EMSGSIZE; | 2251 | return -EMSGSIZE; |
| 2213 | 2252 | ||
| 2214 | rtm = nlmsg_data(nlh); | 2253 | rtm = nlmsg_data(nlh); |
| 2215 | rtm->rtm_family = RTNL_FAMILY_IPMR; | 2254 | rtm->rtm_family = RTNL_FAMILY_IP6MR; |
| 2216 | rtm->rtm_dst_len = 128; | 2255 | rtm->rtm_dst_len = 128; |
| 2217 | rtm->rtm_src_len = 128; | 2256 | rtm->rtm_src_len = 128; |
| 2218 | rtm->rtm_tos = 0; | 2257 | rtm->rtm_tos = 0; |
| 2219 | rtm->rtm_table = mrt->id; | 2258 | rtm->rtm_table = mrt->id; |
| 2220 | if (nla_put_u32(skb, RTA_TABLE, mrt->id)) | 2259 | if (nla_put_u32(skb, RTA_TABLE, mrt->id)) |
| 2221 | goto nla_put_failure; | 2260 | goto nla_put_failure; |
| 2261 | rtm->rtm_type = RTN_MULTICAST; | ||
| 2222 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; | 2262 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; |
| 2223 | rtm->rtm_protocol = RTPROT_UNSPEC; | 2263 | if (c->mfc_flags & MFC_STATIC) |
| 2264 | rtm->rtm_protocol = RTPROT_STATIC; | ||
| 2265 | else | ||
| 2266 | rtm->rtm_protocol = RTPROT_MROUTED; | ||
| 2224 | rtm->rtm_flags = 0; | 2267 | rtm->rtm_flags = 0; |
| 2225 | 2268 | ||
| 2226 | if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) || | 2269 | if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) || |
| 2227 | nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp)) | 2270 | nla_put(skb, RTA_DST, 16, &c->mf6c_mcastgrp)) |
| 2228 | goto nla_put_failure; | 2271 | goto nla_put_failure; |
| 2229 | if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0) | 2272 | err = __ip6mr_fill_mroute(mrt, skb, c, rtm); |
| 2273 | /* do not break the dump if cache is unresolved */ | ||
| 2274 | if (err < 0 && err != -ENOENT) | ||
| 2230 | goto nla_put_failure; | 2275 | goto nla_put_failure; |
| 2231 | 2276 | ||
| 2232 | return nlmsg_end(skb, nlh); | 2277 | return nlmsg_end(skb, nlh); |
| @@ -2236,6 +2281,52 @@ nla_put_failure: | |||
| 2236 | return -EMSGSIZE; | 2281 | return -EMSGSIZE; |
| 2237 | } | 2282 | } |
| 2238 | 2283 | ||
| 2284 | static int mr6_msgsize(bool unresolved, int maxvif) | ||
| 2285 | { | ||
| 2286 | size_t len = | ||
| 2287 | NLMSG_ALIGN(sizeof(struct rtmsg)) | ||
| 2288 | + nla_total_size(4) /* RTA_TABLE */ | ||
| 2289 | + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */ | ||
| 2290 | + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */ | ||
| 2291 | ; | ||
| 2292 | |||
| 2293 | if (!unresolved) | ||
| 2294 | len = len | ||
| 2295 | + nla_total_size(4) /* RTA_IIF */ | ||
| 2296 | + nla_total_size(0) /* RTA_MULTIPATH */ | ||
| 2297 | + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) | ||
| 2298 | /* RTA_MFC_STATS */ | ||
| 2299 | + nla_total_size(sizeof(struct rta_mfc_stats)) | ||
| 2300 | ; | ||
| 2301 | |||
| 2302 | return len; | ||
| 2303 | } | ||
| 2304 | |||
| 2305 | static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, | ||
| 2306 | int cmd) | ||
| 2307 | { | ||
| 2308 | struct net *net = read_pnet(&mrt->net); | ||
| 2309 | struct sk_buff *skb; | ||
| 2310 | int err = -ENOBUFS; | ||
| 2311 | |||
| 2312 | skb = nlmsg_new(mr6_msgsize(mfc->mf6c_parent >= MAXMIFS, mrt->maxvif), | ||
| 2313 | GFP_ATOMIC); | ||
| 2314 | if (skb == NULL) | ||
| 2315 | goto errout; | ||
| 2316 | |||
| 2317 | err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd); | ||
| 2318 | if (err < 0) | ||
| 2319 | goto errout; | ||
| 2320 | |||
| 2321 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC); | ||
| 2322 | return; | ||
| 2323 | |||
| 2324 | errout: | ||
| 2325 | kfree_skb(skb); | ||
| 2326 | if (err < 0) | ||
| 2327 | rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err); | ||
| 2328 | } | ||
| 2329 | |||
| 2239 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | 2330 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) |
| 2240 | { | 2331 | { |
| 2241 | struct net *net = sock_net(skb->sk); | 2332 | struct net *net = sock_net(skb->sk); |
| @@ -2262,13 +2353,29 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 2262 | if (ip6mr_fill_mroute(mrt, skb, | 2353 | if (ip6mr_fill_mroute(mrt, skb, |
| 2263 | NETLINK_CB(cb->skb).portid, | 2354 | NETLINK_CB(cb->skb).portid, |
| 2264 | cb->nlh->nlmsg_seq, | 2355 | cb->nlh->nlmsg_seq, |
| 2265 | mfc) < 0) | 2356 | mfc, RTM_NEWROUTE) < 0) |
| 2266 | goto done; | 2357 | goto done; |
| 2267 | next_entry: | 2358 | next_entry: |
| 2268 | e++; | 2359 | e++; |
| 2269 | } | 2360 | } |
| 2270 | e = s_e = 0; | 2361 | e = s_e = 0; |
| 2271 | } | 2362 | } |
| 2363 | spin_lock_bh(&mfc_unres_lock); | ||
| 2364 | list_for_each_entry(mfc, &mrt->mfc6_unres_queue, list) { | ||
| 2365 | if (e < s_e) | ||
| 2366 | goto next_entry2; | ||
| 2367 | if (ip6mr_fill_mroute(mrt, skb, | ||
| 2368 | NETLINK_CB(cb->skb).portid, | ||
| 2369 | cb->nlh->nlmsg_seq, | ||
| 2370 | mfc, RTM_NEWROUTE) < 0) { | ||
| 2371 | spin_unlock_bh(&mfc_unres_lock); | ||
| 2372 | goto done; | ||
| 2373 | } | ||
| 2374 | next_entry2: | ||
| 2375 | e++; | ||
| 2376 | } | ||
| 2377 | spin_unlock_bh(&mfc_unres_lock); | ||
| 2378 | e = s_e = 0; | ||
| 2272 | s_h = 0; | 2379 | s_h = 0; |
| 2273 | next_table: | 2380 | next_table: |
| 2274 | t++; | 2381 | t++; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index ba6d13d1f1e1..ee94d31c9d4d 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -343,7 +343,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 343 | break; | 343 | break; |
| 344 | 344 | ||
| 345 | case IPV6_TRANSPARENT: | 345 | case IPV6_TRANSPARENT: |
| 346 | if (valbool && !capable(CAP_NET_ADMIN) && !capable(CAP_NET_RAW)) { | 346 | if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) && |
| 347 | !ns_capable(net->user_ns, CAP_NET_RAW)) { | ||
| 347 | retv = -EPERM; | 348 | retv = -EPERM; |
| 348 | break; | 349 | break; |
| 349 | } | 350 | } |
| @@ -381,7 +382,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 381 | 382 | ||
| 382 | /* hop-by-hop / destination options are privileged option */ | 383 | /* hop-by-hop / destination options are privileged option */ |
| 383 | retv = -EPERM; | 384 | retv = -EPERM; |
| 384 | if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) | 385 | if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) |
| 385 | break; | 386 | break; |
| 386 | 387 | ||
| 387 | opt = ipv6_renew_options(sk, np->opt, optname, | 388 | opt = ipv6_renew_options(sk, np->opt, optname, |
| @@ -397,7 +398,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 397 | if (optname == IPV6_RTHDR && opt && opt->srcrt) { | 398 | if (optname == IPV6_RTHDR && opt && opt->srcrt) { |
| 398 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | 399 | struct ipv6_rt_hdr *rthdr = opt->srcrt; |
| 399 | switch (rthdr->type) { | 400 | switch (rthdr->type) { |
| 400 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 401 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 401 | case IPV6_SRCRT_TYPE_2: | 402 | case IPV6_SRCRT_TYPE_2: |
| 402 | if (rthdr->hdrlen != 2 || | 403 | if (rthdr->hdrlen != 2 || |
| 403 | rthdr->segments_left != 1) | 404 | rthdr->segments_left != 1) |
| @@ -754,7 +755,7 @@ done: | |||
| 754 | case IPV6_IPSEC_POLICY: | 755 | case IPV6_IPSEC_POLICY: |
| 755 | case IPV6_XFRM_POLICY: | 756 | case IPV6_XFRM_POLICY: |
| 756 | retv = -EPERM; | 757 | retv = -EPERM; |
| 757 | if (!capable(CAP_NET_ADMIN)) | 758 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 758 | break; | 759 | break; |
| 759 | retv = xfrm_user_policy(sk, optname, optval, optlen); | 760 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
| 760 | break; | 761 | break; |
| @@ -827,6 +828,7 @@ pref_skip_coa: | |||
| 827 | if (val < 0 || val > 255) | 828 | if (val < 0 || val > 255) |
| 828 | goto e_inval; | 829 | goto e_inval; |
| 829 | np->min_hopcount = val; | 830 | np->min_hopcount = val; |
| 831 | retv = 0; | ||
| 830 | break; | 832 | break; |
| 831 | case IPV6_DONTFRAG: | 833 | case IPV6_DONTFRAG: |
| 832 | np->dontfrag = valbool; | 834 | np->dontfrag = valbool; |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 92f8e48e4ba4..28dfa5f3801f 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -163,7 +163,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 163 | rt = rt6_lookup(net, addr, NULL, 0, 0); | 163 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
| 164 | if (rt) { | 164 | if (rt) { |
| 165 | dev = rt->dst.dev; | 165 | dev = rt->dst.dev; |
| 166 | dst_release(&rt->dst); | 166 | ip6_rt_put(rt); |
| 167 | } | 167 | } |
| 168 | } else | 168 | } else |
| 169 | dev = dev_get_by_index_rcu(net, ifindex); | 169 | dev = dev_get_by_index_rcu(net, ifindex); |
| @@ -260,7 +260,7 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, | |||
| 260 | 260 | ||
| 261 | if (rt) { | 261 | if (rt) { |
| 262 | dev = rt->dst.dev; | 262 | dev = rt->dst.dev; |
| 263 | dst_release(&rt->dst); | 263 | ip6_rt_put(rt); |
| 264 | } | 264 | } |
| 265 | } else | 265 | } else |
| 266 | dev = dev_get_by_index_rcu(net, ifindex); | 266 | dev = dev_get_by_index_rcu(net, ifindex); |
| @@ -284,6 +284,9 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
| 284 | struct ipv6_mc_socklist *mc_lst; | 284 | struct ipv6_mc_socklist *mc_lst; |
| 285 | struct net *net = sock_net(sk); | 285 | struct net *net = sock_net(sk); |
| 286 | 286 | ||
| 287 | if (!rcu_access_pointer(np->ipv6_mc_list)) | ||
| 288 | return; | ||
| 289 | |||
| 287 | spin_lock(&ipv6_sk_mc_lock); | 290 | spin_lock(&ipv6_sk_mc_lock); |
| 288 | while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list, | 291 | while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list, |
| 289 | lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) { | 292 | lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) { |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2edce30ef733..f2a007b7bde3 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -151,8 +151,8 @@ static inline int ndisc_opt_addr_space(struct net_device *dev) | |||
| 151 | static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, | 151 | static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, |
| 152 | unsigned short addr_type) | 152 | unsigned short addr_type) |
| 153 | { | 153 | { |
| 154 | int space = NDISC_OPT_SPACE(data_len); | ||
| 155 | int pad = ndisc_addr_option_pad(addr_type); | 154 | int pad = ndisc_addr_option_pad(addr_type); |
| 155 | int space = NDISC_OPT_SPACE(data_len + pad); | ||
| 156 | 156 | ||
| 157 | opt[0] = type; | 157 | opt[0] = type; |
| 158 | opt[1] = space>>3; | 158 | opt[1] = space>>3; |
| @@ -370,12 +370,12 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
| 370 | ipv6_dev_mc_dec(dev, &maddr); | 370 | ipv6_dev_mc_dec(dev, &maddr); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | struct sk_buff *ndisc_build_skb(struct net_device *dev, | 373 | static struct sk_buff *ndisc_build_skb(struct net_device *dev, |
| 374 | const struct in6_addr *daddr, | 374 | const struct in6_addr *daddr, |
| 375 | const struct in6_addr *saddr, | 375 | const struct in6_addr *saddr, |
| 376 | struct icmp6hdr *icmp6h, | 376 | struct icmp6hdr *icmp6h, |
| 377 | const struct in6_addr *target, | 377 | const struct in6_addr *target, |
| 378 | int llinfo) | 378 | int llinfo) |
| 379 | { | 379 | { |
| 380 | struct net *net = dev_net(dev); | 380 | struct net *net = dev_net(dev); |
| 381 | struct sock *sk = net->ipv6.ndisc_sk; | 381 | struct sock *sk = net->ipv6.ndisc_sk; |
| @@ -431,14 +431,11 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev, | |||
| 431 | return skb; | 431 | return skb; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | EXPORT_SYMBOL(ndisc_build_skb); | 434 | static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, |
| 435 | 435 | struct neighbour *neigh, | |
| 436 | void ndisc_send_skb(struct sk_buff *skb, | 436 | const struct in6_addr *daddr, |
| 437 | struct net_device *dev, | 437 | const struct in6_addr *saddr, |
| 438 | struct neighbour *neigh, | 438 | struct icmp6hdr *icmp6h) |
| 439 | const struct in6_addr *daddr, | ||
| 440 | const struct in6_addr *saddr, | ||
| 441 | struct icmp6hdr *icmp6h) | ||
| 442 | { | 439 | { |
| 443 | struct flowi6 fl6; | 440 | struct flowi6 fl6; |
| 444 | struct dst_entry *dst; | 441 | struct dst_entry *dst; |
| @@ -473,8 +470,6 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
| 473 | rcu_read_unlock(); | 470 | rcu_read_unlock(); |
| 474 | } | 471 | } |
| 475 | 472 | ||
| 476 | EXPORT_SYMBOL(ndisc_send_skb); | ||
| 477 | |||
| 478 | /* | 473 | /* |
| 479 | * Send a Neighbour Discover packet | 474 | * Send a Neighbour Discover packet |
| 480 | */ | 475 | */ |
| @@ -535,7 +530,6 @@ static void ndisc_send_unsol_na(struct net_device *dev) | |||
| 535 | { | 530 | { |
| 536 | struct inet6_dev *idev; | 531 | struct inet6_dev *idev; |
| 537 | struct inet6_ifaddr *ifa; | 532 | struct inet6_ifaddr *ifa; |
| 538 | struct in6_addr mcaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | ||
| 539 | 533 | ||
| 540 | idev = in6_dev_get(dev); | 534 | idev = in6_dev_get(dev); |
| 541 | if (!idev) | 535 | if (!idev) |
| @@ -543,7 +537,7 @@ static void ndisc_send_unsol_na(struct net_device *dev) | |||
| 543 | 537 | ||
| 544 | read_lock_bh(&idev->lock); | 538 | read_lock_bh(&idev->lock); |
| 545 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 539 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
| 546 | ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, | 540 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr, |
| 547 | /*router=*/ !!idev->cnf.forwarding, | 541 | /*router=*/ !!idev->cnf.forwarding, |
| 548 | /*solicited=*/ false, /*override=*/ true, | 542 | /*solicited=*/ false, /*override=*/ true, |
| 549 | /*inc_opt=*/ true); | 543 | /*inc_opt=*/ true); |
| @@ -905,7 +899,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
| 905 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | 899 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && |
| 906 | net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && | 900 | net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && |
| 907 | pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { | 901 | pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { |
| 908 | /* XXX: idev->cnf.prixy_ndp */ | 902 | /* XXX: idev->cnf.proxy_ndp */ |
| 909 | goto out; | 903 | goto out; |
| 910 | } | 904 | } |
| 911 | 905 | ||
| @@ -1033,18 +1027,6 @@ errout: | |||
| 1033 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); | 1027 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
| 1034 | } | 1028 | } |
| 1035 | 1029 | ||
| 1036 | static inline int accept_ra(struct inet6_dev *in6_dev) | ||
| 1037 | { | ||
| 1038 | /* | ||
| 1039 | * If forwarding is enabled, RA are not accepted unless the special | ||
| 1040 | * hybrid mode (accept_ra=2) is enabled. | ||
| 1041 | */ | ||
| 1042 | if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) | ||
| 1043 | return 0; | ||
| 1044 | |||
| 1045 | return in6_dev->cnf.accept_ra; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static void ndisc_router_discovery(struct sk_buff *skb) | 1030 | static void ndisc_router_discovery(struct sk_buff *skb) |
| 1049 | { | 1031 | { |
| 1050 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); | 1032 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
| @@ -1092,7 +1074,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1092 | return; | 1074 | return; |
| 1093 | } | 1075 | } |
| 1094 | 1076 | ||
| 1095 | if (!accept_ra(in6_dev)) | 1077 | if (!ipv6_accept_ra(in6_dev)) |
| 1096 | goto skip_linkparms; | 1078 | goto skip_linkparms; |
| 1097 | 1079 | ||
| 1098 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1080 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
| @@ -1144,7 +1126,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1144 | ND_PRINTK(0, err, | 1126 | ND_PRINTK(0, err, |
| 1145 | "RA: %s got default router without neighbour\n", | 1127 | "RA: %s got default router without neighbour\n", |
| 1146 | __func__); | 1128 | __func__); |
| 1147 | dst_release(&rt->dst); | 1129 | ip6_rt_put(rt); |
| 1148 | return; | 1130 | return; |
| 1149 | } | 1131 | } |
| 1150 | } | 1132 | } |
| @@ -1169,7 +1151,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1169 | ND_PRINTK(0, err, | 1151 | ND_PRINTK(0, err, |
| 1170 | "RA: %s got default router without neighbour\n", | 1152 | "RA: %s got default router without neighbour\n", |
| 1171 | __func__); | 1153 | __func__); |
| 1172 | dst_release(&rt->dst); | 1154 | ip6_rt_put(rt); |
| 1173 | return; | 1155 | return; |
| 1174 | } | 1156 | } |
| 1175 | neigh->flags |= NTF_ROUTER; | 1157 | neigh->flags |= NTF_ROUTER; |
| @@ -1248,7 +1230,7 @@ skip_linkparms: | |||
| 1248 | NEIGH_UPDATE_F_ISROUTER); | 1230 | NEIGH_UPDATE_F_ISROUTER); |
| 1249 | } | 1231 | } |
| 1250 | 1232 | ||
| 1251 | if (!accept_ra(in6_dev)) | 1233 | if (!ipv6_accept_ra(in6_dev)) |
| 1252 | goto out; | 1234 | goto out; |
| 1253 | 1235 | ||
| 1254 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1236 | #ifdef CONFIG_IPV6_ROUTE_INFO |
| @@ -1325,8 +1307,7 @@ skip_routeinfo: | |||
| 1325 | ND_PRINTK(2, warn, "RA: invalid RA options\n"); | 1307 | ND_PRINTK(2, warn, "RA: invalid RA options\n"); |
| 1326 | } | 1308 | } |
| 1327 | out: | 1309 | out: |
| 1328 | if (rt) | 1310 | ip6_rt_put(rt); |
| 1329 | dst_release(&rt->dst); | ||
| 1330 | if (neigh) | 1311 | if (neigh) |
| 1331 | neigh_release(neigh); | 1312 | neigh_release(neigh); |
| 1332 | } | 1313 | } |
| @@ -1574,11 +1555,18 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
| 1574 | { | 1555 | { |
| 1575 | struct net_device *dev = ptr; | 1556 | struct net_device *dev = ptr; |
| 1576 | struct net *net = dev_net(dev); | 1557 | struct net *net = dev_net(dev); |
| 1558 | struct inet6_dev *idev; | ||
| 1577 | 1559 | ||
| 1578 | switch (event) { | 1560 | switch (event) { |
| 1579 | case NETDEV_CHANGEADDR: | 1561 | case NETDEV_CHANGEADDR: |
| 1580 | neigh_changeaddr(&nd_tbl, dev); | 1562 | neigh_changeaddr(&nd_tbl, dev); |
| 1581 | fib6_run_gc(~0UL, net); | 1563 | fib6_run_gc(~0UL, net); |
| 1564 | idev = in6_dev_get(dev); | ||
| 1565 | if (!idev) | ||
| 1566 | break; | ||
| 1567 | if (idev->cnf.ndisc_notify) | ||
| 1568 | ndisc_send_unsol_na(dev); | ||
| 1569 | in6_dev_put(idev); | ||
| 1582 | break; | 1570 | break; |
| 1583 | case NETDEV_DOWN: | 1571 | case NETDEV_DOWN: |
| 1584 | neigh_ifdown(&nd_tbl, dev); | 1572 | neigh_ifdown(&nd_tbl, dev); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index d7cb04506c3d..125a90d6a795 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -207,8 +207,7 @@ ip6t_get_target_c(const struct ip6t_entry *e) | |||
| 207 | return ip6t_get_target((struct ip6t_entry *)e); | 207 | return ip6t_get_target((struct ip6t_entry *)e); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 210 | #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) |
| 211 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
| 212 | /* This cries for unification! */ | 211 | /* This cries for unification! */ |
| 213 | static const char *const hooknames[] = { | 212 | static const char *const hooknames[] = { |
| 214 | [NF_INET_PRE_ROUTING] = "PREROUTING", | 213 | [NF_INET_PRE_ROUTING] = "PREROUTING", |
| @@ -381,8 +380,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 381 | t = ip6t_get_target_c(e); | 380 | t = ip6t_get_target_c(e); |
| 382 | IP_NF_ASSERT(t->u.kernel.target); | 381 | IP_NF_ASSERT(t->u.kernel.target); |
| 383 | 382 | ||
| 384 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 383 | #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) |
| 385 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | ||
| 386 | /* The packet is traced: log it */ | 384 | /* The packet is traced: log it */ |
| 387 | if (unlikely(skb->nf_trace)) | 385 | if (unlikely(skb->nf_trace)) |
| 388 | trace_packet(skb, hook, in, out, | 386 | trace_packet(skb, hook, in, out, |
| @@ -1856,7 +1854,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
| 1856 | { | 1854 | { |
| 1857 | int ret; | 1855 | int ret; |
| 1858 | 1856 | ||
| 1859 | if (!capable(CAP_NET_ADMIN)) | 1857 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) |
| 1860 | return -EPERM; | 1858 | return -EPERM; |
| 1861 | 1859 | ||
| 1862 | switch (cmd) { | 1860 | switch (cmd) { |
| @@ -1971,7 +1969,7 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 1971 | { | 1969 | { |
| 1972 | int ret; | 1970 | int ret; |
| 1973 | 1971 | ||
| 1974 | if (!capable(CAP_NET_ADMIN)) | 1972 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) |
| 1975 | return -EPERM; | 1973 | return -EPERM; |
| 1976 | 1974 | ||
| 1977 | switch (cmd) { | 1975 | switch (cmd) { |
| @@ -1993,7 +1991,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
| 1993 | { | 1991 | { |
| 1994 | int ret; | 1992 | int ret; |
| 1995 | 1993 | ||
| 1996 | if (!capable(CAP_NET_ADMIN)) | 1994 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) |
| 1997 | return -EPERM; | 1995 | return -EPERM; |
| 1998 | 1996 | ||
| 1999 | switch (cmd) { | 1997 | switch (cmd) { |
| @@ -2018,7 +2016,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 2018 | { | 2016 | { |
| 2019 | int ret; | 2017 | int ret; |
| 2020 | 2018 | ||
| 2021 | if (!capable(CAP_NET_ADMIN)) | 2019 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) |
| 2022 | return -EPERM; | 2020 | return -EPERM; |
| 2023 | 2021 | ||
| 2024 | switch (cmd) { | 2022 | switch (cmd) { |
| @@ -2273,112 +2271,9 @@ static void __exit ip6_tables_fini(void) | |||
| 2273 | unregister_pernet_subsys(&ip6_tables_net_ops); | 2271 | unregister_pernet_subsys(&ip6_tables_net_ops); |
| 2274 | } | 2272 | } |
| 2275 | 2273 | ||
| 2276 | /* | ||
| 2277 | * find the offset to specified header or the protocol number of last header | ||
| 2278 | * if target < 0. "last header" is transport protocol header, ESP, or | ||
| 2279 | * "No next header". | ||
| 2280 | * | ||
| 2281 | * Note that *offset is used as input/output parameter. an if it is not zero, | ||
| 2282 | * then it must be a valid offset to an inner IPv6 header. This can be used | ||
| 2283 | * to explore inner IPv6 header, eg. ICMPv6 error messages. | ||
| 2284 | * | ||
| 2285 | * If target header is found, its offset is set in *offset and return protocol | ||
| 2286 | * number. Otherwise, return -1. | ||
| 2287 | * | ||
| 2288 | * If the first fragment doesn't contain the final protocol header or | ||
| 2289 | * NEXTHDR_NONE it is considered invalid. | ||
| 2290 | * | ||
| 2291 | * Note that non-1st fragment is special case that "the protocol number | ||
| 2292 | * of last header" is "next header" field in Fragment header. In this case, | ||
| 2293 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
| 2294 | * isn't NULL. | ||
| 2295 | * | ||
| 2296 | * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG | ||
| 2297 | * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and | ||
| 2298 | * target < 0, then this function will stop at the AH header. | ||
| 2299 | */ | ||
| 2300 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | ||
| 2301 | int target, unsigned short *fragoff, int *flags) | ||
| 2302 | { | ||
| 2303 | unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); | ||
| 2304 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; | ||
| 2305 | unsigned int len; | ||
| 2306 | |||
| 2307 | if (fragoff) | ||
| 2308 | *fragoff = 0; | ||
| 2309 | |||
| 2310 | if (*offset) { | ||
| 2311 | struct ipv6hdr _ip6, *ip6; | ||
| 2312 | |||
| 2313 | ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); | ||
| 2314 | if (!ip6 || (ip6->version != 6)) { | ||
| 2315 | printk(KERN_ERR "IPv6 header not found\n"); | ||
| 2316 | return -EBADMSG; | ||
| 2317 | } | ||
| 2318 | start = *offset + sizeof(struct ipv6hdr); | ||
| 2319 | nexthdr = ip6->nexthdr; | ||
| 2320 | } | ||
| 2321 | len = skb->len - start; | ||
| 2322 | |||
| 2323 | while (nexthdr != target) { | ||
| 2324 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 2325 | unsigned int hdrlen; | ||
| 2326 | |||
| 2327 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { | ||
| 2328 | if (target < 0) | ||
| 2329 | break; | ||
| 2330 | return -ENOENT; | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | ||
| 2334 | if (hp == NULL) | ||
| 2335 | return -EBADMSG; | ||
| 2336 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 2337 | unsigned short _frag_off; | ||
| 2338 | __be16 *fp; | ||
| 2339 | |||
| 2340 | if (flags) /* Indicate that this is a fragment */ | ||
| 2341 | *flags |= IP6T_FH_F_FRAG; | ||
| 2342 | fp = skb_header_pointer(skb, | ||
| 2343 | start+offsetof(struct frag_hdr, | ||
| 2344 | frag_off), | ||
| 2345 | sizeof(_frag_off), | ||
| 2346 | &_frag_off); | ||
| 2347 | if (fp == NULL) | ||
| 2348 | return -EBADMSG; | ||
| 2349 | |||
| 2350 | _frag_off = ntohs(*fp) & ~0x7; | ||
| 2351 | if (_frag_off) { | ||
| 2352 | if (target < 0 && | ||
| 2353 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
| 2354 | hp->nexthdr == NEXTHDR_NONE)) { | ||
| 2355 | if (fragoff) | ||
| 2356 | *fragoff = _frag_off; | ||
| 2357 | return hp->nexthdr; | ||
| 2358 | } | ||
| 2359 | return -ENOENT; | ||
| 2360 | } | ||
| 2361 | hdrlen = 8; | ||
| 2362 | } else if (nexthdr == NEXTHDR_AUTH) { | ||
| 2363 | if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0)) | ||
| 2364 | break; | ||
| 2365 | hdrlen = (hp->hdrlen + 2) << 2; | ||
| 2366 | } else | ||
| 2367 | hdrlen = ipv6_optlen(hp); | ||
| 2368 | |||
| 2369 | nexthdr = hp->nexthdr; | ||
| 2370 | len -= hdrlen; | ||
| 2371 | start += hdrlen; | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | *offset = start; | ||
| 2375 | return nexthdr; | ||
| 2376 | } | ||
| 2377 | |||
| 2378 | EXPORT_SYMBOL(ip6t_register_table); | 2274 | EXPORT_SYMBOL(ip6t_register_table); |
| 2379 | EXPORT_SYMBOL(ip6t_unregister_table); | 2275 | EXPORT_SYMBOL(ip6t_unregister_table); |
| 2380 | EXPORT_SYMBOL(ip6t_do_table); | 2276 | EXPORT_SYMBOL(ip6t_do_table); |
| 2381 | EXPORT_SYMBOL(ipv6_find_hdr); | ||
| 2382 | 2277 | ||
| 2383 | module_init(ip6_tables_init); | 2278 | module_init(ip6_tables_init); |
| 2384 | module_exit(ip6_tables_fini); | 2279 | module_exit(ip6_tables_fini); |
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c index 5d1d8b04d694..5060d54199ab 100644 --- a/net/ipv6/netfilter/ip6t_rpfilter.c +++ b/net/ipv6/netfilter/ip6t_rpfilter.c | |||
| @@ -67,7 +67,7 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb, | |||
| 67 | if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE)) | 67 | if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE)) |
| 68 | ret = true; | 68 | ret = true; |
| 69 | out: | 69 | out: |
| 70 | dst_release(&rt->dst); | 70 | ip6_rt_put(rt); |
| 71 | return ret; | 71 | return ret; |
| 72 | } | 72 | } |
| 73 | 73 | ||
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index d57dab17a182..6c8ae24b85eb 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
| @@ -137,6 +137,10 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
| 137 | /* ESTABLISHED */ | 137 | /* ESTABLISHED */ |
| 138 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | 138 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || |
| 139 | ctinfo == IP_CT_ESTABLISHED_REPLY); | 139 | ctinfo == IP_CT_ESTABLISHED_REPLY); |
| 140 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) { | ||
| 141 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
| 142 | return NF_DROP; | ||
| 143 | } | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | return nf_nat_packet(ct, ctinfo, hooknum, skb); | 146 | return nf_nat_packet(ct, ctinfo, hooknum, skb); |
| @@ -277,9 +281,7 @@ static int __net_init ip6table_nat_net_init(struct net *net) | |||
| 277 | return -ENOMEM; | 281 | return -ENOMEM; |
| 278 | net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); | 282 | net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); |
| 279 | kfree(repl); | 283 | kfree(repl); |
| 280 | if (IS_ERR(net->ipv6.ip6table_nat)) | 284 | return PTR_RET(net->ipv6.ip6table_nat); |
| 281 | return PTR_ERR(net->ipv6.ip6table_nat); | ||
| 282 | return 0; | ||
| 283 | } | 285 | } |
| 284 | 286 | ||
| 285 | static void __net_exit ip6table_nat_net_exit(struct net *net) | 287 | static void __net_exit ip6table_nat_net_exit(struct net *net) |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 8860d23e61cf..00ee17c3e893 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/netfilter_bridge.h> | 22 | #include <linux/netfilter_bridge.h> |
| 23 | #include <linux/netfilter_ipv6.h> | 23 | #include <linux/netfilter_ipv6.h> |
| 24 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
| 24 | #include <net/netfilter/nf_conntrack.h> | 25 | #include <net/netfilter/nf_conntrack.h> |
| 25 | #include <net/netfilter/nf_conntrack_helper.h> | 26 | #include <net/netfilter/nf_conntrack_helper.h> |
| 26 | #include <net/netfilter/nf_conntrack_l4proto.h> | 27 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| @@ -295,7 +296,56 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | |||
| 295 | }, | 296 | }, |
| 296 | }; | 297 | }; |
| 297 | 298 | ||
| 298 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 299 | static int |
| 300 | ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) | ||
| 301 | { | ||
| 302 | const struct inet_sock *inet = inet_sk(sk); | ||
| 303 | const struct ipv6_pinfo *inet6 = inet6_sk(sk); | ||
| 304 | const struct nf_conntrack_tuple_hash *h; | ||
| 305 | struct sockaddr_in6 sin6; | ||
| 306 | struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; | ||
| 307 | struct nf_conn *ct; | ||
| 308 | |||
| 309 | tuple.src.u3.in6 = inet6->rcv_saddr; | ||
| 310 | tuple.src.u.tcp.port = inet->inet_sport; | ||
| 311 | tuple.dst.u3.in6 = inet6->daddr; | ||
| 312 | tuple.dst.u.tcp.port = inet->inet_dport; | ||
| 313 | tuple.dst.protonum = sk->sk_protocol; | ||
| 314 | |||
| 315 | if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) | ||
| 316 | return -ENOPROTOOPT; | ||
| 317 | |||
| 318 | if (*len < 0 || (unsigned int) *len < sizeof(sin6)) | ||
| 319 | return -EINVAL; | ||
| 320 | |||
| 321 | h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple); | ||
| 322 | if (!h) { | ||
| 323 | pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", | ||
| 324 | &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), | ||
| 325 | &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); | ||
| 326 | return -ENOENT; | ||
| 327 | } | ||
| 328 | |||
| 329 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
| 330 | |||
| 331 | sin6.sin6_family = AF_INET6; | ||
| 332 | sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; | ||
| 333 | sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK; | ||
| 334 | memcpy(&sin6.sin6_addr, | ||
| 335 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, | ||
| 336 | sizeof(sin6.sin6_addr)); | ||
| 337 | |||
| 338 | nf_ct_put(ct); | ||
| 339 | |||
| 340 | if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) | ||
| 341 | sin6.sin6_scope_id = sk->sk_bound_dev_if; | ||
| 342 | else | ||
| 343 | sin6.sin6_scope_id = 0; | ||
| 344 | |||
| 345 | return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
| 299 | 349 | ||
| 300 | #include <linux/netfilter/nfnetlink.h> | 350 | #include <linux/netfilter/nfnetlink.h> |
| 301 | #include <linux/netfilter/nfnetlink_conntrack.h> | 351 | #include <linux/netfilter/nfnetlink_conntrack.h> |
| @@ -346,7 +396,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | |||
| 346 | .invert_tuple = ipv6_invert_tuple, | 396 | .invert_tuple = ipv6_invert_tuple, |
| 347 | .print_tuple = ipv6_print_tuple, | 397 | .print_tuple = ipv6_print_tuple, |
| 348 | .get_l4proto = ipv6_get_l4proto, | 398 | .get_l4proto = ipv6_get_l4proto, |
| 349 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 399 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 350 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, | 400 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, |
| 351 | .nlattr_tuple_size = ipv6_nlattr_tuple_size, | 401 | .nlattr_tuple_size = ipv6_nlattr_tuple_size, |
| 352 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, | 402 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
| @@ -359,6 +409,14 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); | |||
| 359 | MODULE_LICENSE("GPL"); | 409 | MODULE_LICENSE("GPL"); |
| 360 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); | 410 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); |
| 361 | 411 | ||
| 412 | static struct nf_sockopt_ops so_getorigdst6 = { | ||
| 413 | .pf = NFPROTO_IPV6, | ||
| 414 | .get_optmin = IP6T_SO_ORIGINAL_DST, | ||
| 415 | .get_optmax = IP6T_SO_ORIGINAL_DST + 1, | ||
| 416 | .get = ipv6_getorigdst, | ||
| 417 | .owner = THIS_MODULE, | ||
| 418 | }; | ||
| 419 | |||
| 362 | static int ipv6_net_init(struct net *net) | 420 | static int ipv6_net_init(struct net *net) |
| 363 | { | 421 | { |
| 364 | int ret = 0; | 422 | int ret = 0; |
| @@ -425,6 +483,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
| 425 | need_conntrack(); | 483 | need_conntrack(); |
| 426 | nf_defrag_ipv6_enable(); | 484 | nf_defrag_ipv6_enable(); |
| 427 | 485 | ||
| 486 | ret = nf_register_sockopt(&so_getorigdst6); | ||
| 487 | if (ret < 0) { | ||
| 488 | pr_err("Unable to register netfilter socket option\n"); | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 428 | ret = register_pernet_subsys(&ipv6_net_ops); | 492 | ret = register_pernet_subsys(&ipv6_net_ops); |
| 429 | if (ret < 0) | 493 | if (ret < 0) |
| 430 | goto cleanup_pernet; | 494 | goto cleanup_pernet; |
| @@ -440,6 +504,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
| 440 | cleanup_ipv6: | 504 | cleanup_ipv6: |
| 441 | unregister_pernet_subsys(&ipv6_net_ops); | 505 | unregister_pernet_subsys(&ipv6_net_ops); |
| 442 | cleanup_pernet: | 506 | cleanup_pernet: |
| 507 | nf_unregister_sockopt(&so_getorigdst6); | ||
| 443 | return ret; | 508 | return ret; |
| 444 | } | 509 | } |
| 445 | 510 | ||
| @@ -448,6 +513,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) | |||
| 448 | synchronize_net(); | 513 | synchronize_net(); |
| 449 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | 514 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); |
| 450 | unregister_pernet_subsys(&ipv6_net_ops); | 515 | unregister_pernet_subsys(&ipv6_net_ops); |
| 516 | nf_unregister_sockopt(&so_getorigdst6); | ||
| 451 | } | 517 | } |
| 452 | 518 | ||
| 453 | module_init(nf_conntrack_l3proto_ipv6_init); | 519 | module_init(nf_conntrack_l3proto_ipv6_init); |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 2d54b2061d68..24df3dde0076 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
| @@ -232,7 +232,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, | |||
| 232 | return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); | 232 | return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 235 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 236 | 236 | ||
| 237 | #include <linux/netfilter/nfnetlink.h> | 237 | #include <linux/netfilter/nfnetlink.h> |
| 238 | #include <linux/netfilter/nfnetlink_conntrack.h> | 238 | #include <linux/netfilter/nfnetlink_conntrack.h> |
| @@ -375,7 +375,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
| 375 | .get_timeouts = icmpv6_get_timeouts, | 375 | .get_timeouts = icmpv6_get_timeouts, |
| 376 | .new = icmpv6_new, | 376 | .new = icmpv6_new, |
| 377 | .error = icmpv6_error, | 377 | .error = icmpv6_error, |
| 378 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 378 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 379 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, | 379 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
| 380 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, | 380 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, |
| 381 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 381 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index cdd6d045e42e..aacd121fe8c5 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/netfilter_ipv6.h> | 20 | #include <linux/netfilter_ipv6.h> |
| 21 | #include <linux/netfilter_bridge.h> | 21 | #include <linux/netfilter_bridge.h> |
| 22 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 22 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 23 | #include <net/netfilter/nf_conntrack.h> | 23 | #include <net/netfilter/nf_conntrack.h> |
| 24 | #include <net/netfilter/nf_conntrack_helper.h> | 24 | #include <net/netfilter/nf_conntrack_helper.h> |
| 25 | #include <net/netfilter/nf_conntrack_l4proto.h> | 25 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| @@ -35,7 +35,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | |||
| 35 | { | 35 | { |
| 36 | u16 zone = NF_CT_DEFAULT_ZONE; | 36 | u16 zone = NF_CT_DEFAULT_ZONE; |
| 37 | 37 | ||
| 38 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 38 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 39 | if (skb->nfct) | 39 | if (skb->nfct) |
| 40 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | 40 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); |
| 41 | #endif | 41 | #endif |
| @@ -60,7 +60,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
| 60 | { | 60 | { |
| 61 | struct sk_buff *reasm; | 61 | struct sk_buff *reasm; |
| 62 | 62 | ||
| 63 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 63 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 64 | /* Previously seen (loopback)? */ | 64 | /* Previously seen (loopback)? */ |
| 65 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | 65 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) |
| 66 | return NF_ACCEPT; | 66 | return NF_ACCEPT; |
diff --git a/net/ipv6/netfilter/nf_nat_proto_icmpv6.c b/net/ipv6/netfilter/nf_nat_proto_icmpv6.c index 5d6da784305b..61aaf70f376e 100644 --- a/net/ipv6/netfilter/nf_nat_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_nat_proto_icmpv6.c | |||
| @@ -84,7 +84,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_icmpv6 = { | |||
| 84 | .manip_pkt = icmpv6_manip_pkt, | 84 | .manip_pkt = icmpv6_manip_pkt, |
| 85 | .in_range = icmpv6_in_range, | 85 | .in_range = icmpv6_in_range, |
| 86 | .unique_tuple = icmpv6_unique_tuple, | 86 | .unique_tuple = icmpv6_unique_tuple, |
| 87 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 87 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 88 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 88 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 89 | #endif | 89 | #endif |
| 90 | }; | 90 | }; |
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c new file mode 100644 index 000000000000..c2e73e647e44 --- /dev/null +++ b/net/ipv6/output_core.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * IPv6 library code, needed by static components when full IPv6 support is | ||
| 3 | * not configured or static. These functions are needed by GSO/GRO implementation. | ||
| 4 | */ | ||
| 5 | #include <linux/export.h> | ||
| 6 | #include <net/ipv6.h> | ||
| 7 | #include <net/ip6_fib.h> | ||
| 8 | |||
| 9 | void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
| 10 | { | ||
| 11 | static atomic_t ipv6_fragmentation_id; | ||
| 12 | int old, new; | ||
| 13 | |||
| 14 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 15 | if (rt && !(rt->dst.flags & DST_NOPEER)) { | ||
| 16 | struct inet_peer *peer; | ||
| 17 | struct net *net; | ||
| 18 | |||
| 19 | net = dev_net(rt->dst.dev); | ||
| 20 | peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); | ||
| 21 | if (peer) { | ||
| 22 | fhdr->identification = htonl(inet_getid(peer, 0)); | ||
| 23 | inet_putpeer(peer); | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | #endif | ||
| 28 | do { | ||
| 29 | old = atomic_read(&ipv6_fragmentation_id); | ||
| 30 | new = old + 1; | ||
| 31 | if (!new) | ||
| 32 | new = 1; | ||
| 33 | } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); | ||
| 34 | fhdr->identification = htonl(new); | ||
| 35 | } | ||
| 36 | EXPORT_SYMBOL(ipv6_select_ident); | ||
| 37 | |||
| 38 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | ||
| 39 | { | ||
| 40 | u16 offset = sizeof(struct ipv6hdr); | ||
| 41 | struct ipv6_opt_hdr *exthdr = | ||
| 42 | (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); | ||
| 43 | unsigned int packet_len = skb->tail - skb->network_header; | ||
| 44 | int found_rhdr = 0; | ||
| 45 | *nexthdr = &ipv6_hdr(skb)->nexthdr; | ||
| 46 | |||
| 47 | while (offset + 1 <= packet_len) { | ||
| 48 | |||
| 49 | switch (**nexthdr) { | ||
| 50 | |||
| 51 | case NEXTHDR_HOP: | ||
| 52 | break; | ||
| 53 | case NEXTHDR_ROUTING: | ||
| 54 | found_rhdr = 1; | ||
| 55 | break; | ||
| 56 | case NEXTHDR_DEST: | ||
| 57 | #if IS_ENABLED(CONFIG_IPV6_MIP6) | ||
| 58 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) | ||
| 59 | break; | ||
| 60 | #endif | ||
| 61 | if (found_rhdr) | ||
| 62 | return offset; | ||
| 63 | break; | ||
| 64 | default : | ||
| 65 | return offset; | ||
| 66 | } | ||
| 67 | |||
| 68 | offset += ipv6_optlen(exthdr); | ||
| 69 | *nexthdr = &exthdr->nexthdr; | ||
| 70 | exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + | ||
| 71 | offset); | ||
| 72 | } | ||
| 73 | |||
| 74 | return offset; | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL(ip6_find_1stfragopt); | ||
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 053082dfc93e..22d1bd4670da 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
| @@ -25,7 +25,9 @@ | |||
| 25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
| 26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
| 27 | 27 | ||
| 28 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 28 | const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; | 29 | const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; |
| 30 | EXPORT_SYMBOL(inet6_protos); | ||
| 29 | 31 | ||
| 30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 32 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
| 31 | { | 33 | { |
| @@ -50,3 +52,26 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
| 50 | return ret; | 52 | return ret; |
| 51 | } | 53 | } |
| 52 | EXPORT_SYMBOL(inet6_del_protocol); | 54 | EXPORT_SYMBOL(inet6_del_protocol); |
| 55 | #endif | ||
| 56 | |||
| 57 | const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; | ||
| 58 | |||
| 59 | int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) | ||
| 60 | { | ||
| 61 | return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol], | ||
| 62 | NULL, prot) ? 0 : -1; | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL(inet6_add_offload); | ||
| 65 | |||
| 66 | int inet6_del_offload(const struct net_offload *prot, unsigned char protocol) | ||
| 67 | { | ||
| 68 | int ret; | ||
| 69 | |||
| 70 | ret = (cmpxchg((const struct net_offload **)&inet6_offloads[protocol], | ||
| 71 | prot, NULL) == prot) ? 0 : -1; | ||
| 72 | |||
| 73 | synchronize_net(); | ||
| 74 | |||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | EXPORT_SYMBOL(inet6_del_offload); | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d8e95c77db99..6cd29b1e8b92 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -50,7 +50,7 @@ | |||
| 50 | #include <net/udp.h> | 50 | #include <net/udp.h> |
| 51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
| 52 | #include <net/tcp_states.h> | 52 | #include <net/tcp_states.h> |
| 53 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 53 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 54 | #include <net/mip6.h> | 54 | #include <net/mip6.h> |
| 55 | #endif | 55 | #endif |
| 56 | #include <linux/mroute6.h> | 56 | #include <linux/mroute6.h> |
| @@ -123,7 +123,7 @@ static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb) | |||
| 123 | return 1; | 123 | return 1; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 126 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 127 | typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb); | 127 | typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb); |
| 128 | 128 | ||
| 129 | static mh_filter_t __rcu *mh_filter __read_mostly; | 129 | static mh_filter_t __rcu *mh_filter __read_mostly; |
| @@ -184,7 +184,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
| 184 | filtered = icmpv6_filter(sk, skb); | 184 | filtered = icmpv6_filter(sk, skb); |
| 185 | break; | 185 | break; |
| 186 | 186 | ||
| 187 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 187 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 188 | case IPPROTO_MH: | 188 | case IPPROTO_MH: |
| 189 | { | 189 | { |
| 190 | /* XXX: To validate MH only once for each packet, | 190 | /* XXX: To validate MH only once for each packet, |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index da8a4e301b1b..e5253ec9e0fc 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
| @@ -616,6 +616,10 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) | |||
| 616 | table[0].data = &net->ipv6.frags.high_thresh; | 616 | table[0].data = &net->ipv6.frags.high_thresh; |
| 617 | table[1].data = &net->ipv6.frags.low_thresh; | 617 | table[1].data = &net->ipv6.frags.low_thresh; |
| 618 | table[2].data = &net->ipv6.frags.timeout; | 618 | table[2].data = &net->ipv6.frags.timeout; |
| 619 | |||
| 620 | /* Don't export sysctls to unprivileged users */ | ||
| 621 | if (net->user_ns != &init_user_ns) | ||
| 622 | table[0].procname = NULL; | ||
| 619 | } | 623 | } |
| 620 | 624 | ||
| 621 | hdr = register_net_sysctl(net, "net/ipv6", table); | 625 | hdr = register_net_sysctl(net, "net/ipv6", table); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b1e6cf0b95fd..e229a3bc345d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -57,6 +57,7 @@ | |||
| 57 | #include <net/xfrm.h> | 57 | #include <net/xfrm.h> |
| 58 | #include <net/netevent.h> | 58 | #include <net/netevent.h> |
| 59 | #include <net/netlink.h> | 59 | #include <net/netlink.h> |
| 60 | #include <net/nexthop.h> | ||
| 60 | 61 | ||
| 61 | #include <asm/uaccess.h> | 62 | #include <asm/uaccess.h> |
| 62 | 63 | ||
| @@ -289,6 +290,8 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, | |||
| 289 | memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); | 290 | memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); |
| 290 | rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); | 291 | rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); |
| 291 | rt->rt6i_genid = rt_genid(net); | 292 | rt->rt6i_genid = rt_genid(net); |
| 293 | INIT_LIST_HEAD(&rt->rt6i_siblings); | ||
| 294 | rt->rt6i_nsiblings = 0; | ||
| 292 | } | 295 | } |
| 293 | return rt; | 296 | return rt; |
| 294 | } | 297 | } |
| @@ -318,13 +321,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
| 318 | } | 321 | } |
| 319 | } | 322 | } |
| 320 | 323 | ||
| 321 | static atomic_t __rt6_peer_genid = ATOMIC_INIT(0); | ||
| 322 | |||
| 323 | static u32 rt6_peer_genid(void) | ||
| 324 | { | ||
| 325 | return atomic_read(&__rt6_peer_genid); | ||
| 326 | } | ||
| 327 | |||
| 328 | void rt6_bind_peer(struct rt6_info *rt, int create) | 324 | void rt6_bind_peer(struct rt6_info *rt, int create) |
| 329 | { | 325 | { |
| 330 | struct inet_peer_base *base; | 326 | struct inet_peer_base *base; |
| @@ -338,8 +334,6 @@ void rt6_bind_peer(struct rt6_info *rt, int create) | |||
| 338 | if (peer) { | 334 | if (peer) { |
| 339 | if (!rt6_set_peer(rt, peer)) | 335 | if (!rt6_set_peer(rt, peer)) |
| 340 | inet_putpeer(peer); | 336 | inet_putpeer(peer); |
| 341 | else | ||
| 342 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
| 343 | } | 337 | } |
| 344 | } | 338 | } |
| 345 | 339 | ||
| @@ -385,6 +379,69 @@ static bool rt6_need_strict(const struct in6_addr *daddr) | |||
| 385 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); | 379 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
| 386 | } | 380 | } |
| 387 | 381 | ||
| 382 | /* Multipath route selection: | ||
| 383 | * Hash based function using packet header and flowlabel. | ||
| 384 | * Adapted from fib_info_hashfn() | ||
| 385 | */ | ||
| 386 | static int rt6_info_hash_nhsfn(unsigned int candidate_count, | ||
| 387 | const struct flowi6 *fl6) | ||
| 388 | { | ||
| 389 | unsigned int val = fl6->flowi6_proto; | ||
| 390 | |||
| 391 | val ^= (__force u32)fl6->daddr.s6_addr32[0]; | ||
| 392 | val ^= (__force u32)fl6->daddr.s6_addr32[1]; | ||
| 393 | val ^= (__force u32)fl6->daddr.s6_addr32[2]; | ||
| 394 | val ^= (__force u32)fl6->daddr.s6_addr32[3]; | ||
| 395 | |||
| 396 | val ^= (__force u32)fl6->saddr.s6_addr32[0]; | ||
| 397 | val ^= (__force u32)fl6->saddr.s6_addr32[1]; | ||
| 398 | val ^= (__force u32)fl6->saddr.s6_addr32[2]; | ||
| 399 | val ^= (__force u32)fl6->saddr.s6_addr32[3]; | ||
| 400 | |||
| 401 | /* Work only if this not encapsulated */ | ||
| 402 | switch (fl6->flowi6_proto) { | ||
| 403 | case IPPROTO_UDP: | ||
| 404 | case IPPROTO_TCP: | ||
| 405 | case IPPROTO_SCTP: | ||
| 406 | val ^= (__force u16)fl6->fl6_sport; | ||
| 407 | val ^= (__force u16)fl6->fl6_dport; | ||
| 408 | break; | ||
| 409 | |||
| 410 | case IPPROTO_ICMPV6: | ||
| 411 | val ^= (__force u16)fl6->fl6_icmp_type; | ||
| 412 | val ^= (__force u16)fl6->fl6_icmp_code; | ||
| 413 | break; | ||
| 414 | } | ||
| 415 | /* RFC6438 recommands to use flowlabel */ | ||
| 416 | val ^= (__force u32)fl6->flowlabel; | ||
| 417 | |||
| 418 | /* Perhaps, we need to tune, this function? */ | ||
| 419 | val = val ^ (val >> 7) ^ (val >> 12); | ||
| 420 | return val % candidate_count; | ||
| 421 | } | ||
| 422 | |||
| 423 | static struct rt6_info *rt6_multipath_select(struct rt6_info *match, | ||
| 424 | struct flowi6 *fl6) | ||
| 425 | { | ||
| 426 | struct rt6_info *sibling, *next_sibling; | ||
| 427 | int route_choosen; | ||
| 428 | |||
| 429 | route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6); | ||
| 430 | /* Don't change the route, if route_choosen == 0 | ||
| 431 | * (siblings does not include ourself) | ||
| 432 | */ | ||
| 433 | if (route_choosen) | ||
| 434 | list_for_each_entry_safe(sibling, next_sibling, | ||
| 435 | &match->rt6i_siblings, rt6i_siblings) { | ||
| 436 | route_choosen--; | ||
| 437 | if (route_choosen == 0) { | ||
| 438 | match = sibling; | ||
| 439 | break; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | return match; | ||
| 443 | } | ||
| 444 | |||
| 388 | /* | 445 | /* |
| 389 | * Route lookup. Any table->tb6_lock is implied. | 446 | * Route lookup. Any table->tb6_lock is implied. |
| 390 | */ | 447 | */ |
| @@ -487,35 +544,32 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) | |||
| 487 | return 0; | 544 | return 0; |
| 488 | } | 545 | } |
| 489 | 546 | ||
| 490 | static inline int rt6_check_neigh(struct rt6_info *rt) | 547 | static inline bool rt6_check_neigh(struct rt6_info *rt) |
| 491 | { | 548 | { |
| 492 | struct neighbour *neigh; | 549 | struct neighbour *neigh; |
| 493 | int m; | 550 | bool ret = false; |
| 494 | 551 | ||
| 495 | neigh = rt->n; | 552 | neigh = rt->n; |
| 496 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 553 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
| 497 | !(rt->rt6i_flags & RTF_GATEWAY)) | 554 | !(rt->rt6i_flags & RTF_GATEWAY)) |
| 498 | m = 1; | 555 | ret = true; |
| 499 | else if (neigh) { | 556 | else if (neigh) { |
| 500 | read_lock_bh(&neigh->lock); | 557 | read_lock_bh(&neigh->lock); |
| 501 | if (neigh->nud_state & NUD_VALID) | 558 | if (neigh->nud_state & NUD_VALID) |
| 502 | m = 2; | 559 | ret = true; |
| 503 | #ifdef CONFIG_IPV6_ROUTER_PREF | 560 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 504 | else if (neigh->nud_state & NUD_FAILED) | 561 | else if (!(neigh->nud_state & NUD_FAILED)) |
| 505 | m = 0; | 562 | ret = true; |
| 506 | #endif | 563 | #endif |
| 507 | else | ||
| 508 | m = 1; | ||
| 509 | read_unlock_bh(&neigh->lock); | 564 | read_unlock_bh(&neigh->lock); |
| 510 | } else | 565 | } |
| 511 | m = 0; | 566 | return ret; |
| 512 | return m; | ||
| 513 | } | 567 | } |
| 514 | 568 | ||
| 515 | static int rt6_score_route(struct rt6_info *rt, int oif, | 569 | static int rt6_score_route(struct rt6_info *rt, int oif, |
| 516 | int strict) | 570 | int strict) |
| 517 | { | 571 | { |
| 518 | int m, n; | 572 | int m; |
| 519 | 573 | ||
| 520 | m = rt6_check_dev(rt, oif); | 574 | m = rt6_check_dev(rt, oif); |
| 521 | if (!m && (strict & RT6_LOOKUP_F_IFACE)) | 575 | if (!m && (strict & RT6_LOOKUP_F_IFACE)) |
| @@ -523,8 +577,7 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
| 523 | #ifdef CONFIG_IPV6_ROUTER_PREF | 577 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 524 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; | 578 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; |
| 525 | #endif | 579 | #endif |
| 526 | n = rt6_check_neigh(rt); | 580 | if (!rt6_check_neigh(rt) && (strict & RT6_LOOKUP_F_REACHABLE)) |
| 527 | if (!n && (strict & RT6_LOOKUP_F_REACHABLE)) | ||
| 528 | return -1; | 581 | return -1; |
| 529 | return m; | 582 | return m; |
| 530 | } | 583 | } |
| @@ -666,7 +719,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
| 666 | else | 719 | else |
| 667 | rt6_set_expires(rt, jiffies + HZ * lifetime); | 720 | rt6_set_expires(rt, jiffies + HZ * lifetime); |
| 668 | 721 | ||
| 669 | dst_release(&rt->dst); | 722 | ip6_rt_put(rt); |
| 670 | } | 723 | } |
| 671 | return 0; | 724 | return 0; |
| 672 | } | 725 | } |
| @@ -702,6 +755,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, | |||
| 702 | restart: | 755 | restart: |
| 703 | rt = fn->leaf; | 756 | rt = fn->leaf; |
| 704 | rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); | 757 | rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); |
| 758 | if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0) | ||
| 759 | rt = rt6_multipath_select(rt, fl6); | ||
| 705 | BACKTRACK(net, &fl6->saddr); | 760 | BACKTRACK(net, &fl6->saddr); |
| 706 | out: | 761 | out: |
| 707 | dst_use(&rt->dst, jiffies); | 762 | dst_use(&rt->dst, jiffies); |
| @@ -863,7 +918,8 @@ restart_2: | |||
| 863 | 918 | ||
| 864 | restart: | 919 | restart: |
| 865 | rt = rt6_select(fn, oif, strict | reachable); | 920 | rt = rt6_select(fn, oif, strict | reachable); |
| 866 | 921 | if (rt->rt6i_nsiblings && oif == 0) | |
| 922 | rt = rt6_multipath_select(rt, fl6); | ||
| 867 | BACKTRACK(net, &fl6->saddr); | 923 | BACKTRACK(net, &fl6->saddr); |
| 868 | if (rt == net->ipv6.ip6_null_entry || | 924 | if (rt == net->ipv6.ip6_null_entry || |
| 869 | rt->rt6i_flags & RTF_CACHE) | 925 | rt->rt6i_flags & RTF_CACHE) |
| @@ -879,7 +935,7 @@ restart: | |||
| 879 | else | 935 | else |
| 880 | goto out2; | 936 | goto out2; |
| 881 | 937 | ||
| 882 | dst_release(&rt->dst); | 938 | ip6_rt_put(rt); |
| 883 | rt = nrt ? : net->ipv6.ip6_null_entry; | 939 | rt = nrt ? : net->ipv6.ip6_null_entry; |
| 884 | 940 | ||
| 885 | dst_hold(&rt->dst); | 941 | dst_hold(&rt->dst); |
| @@ -896,7 +952,7 @@ restart: | |||
| 896 | * Race condition! In the gap, when table->tb6_lock was | 952 | * Race condition! In the gap, when table->tb6_lock was |
| 897 | * released someone could insert this route. Relookup. | 953 | * released someone could insert this route. Relookup. |
| 898 | */ | 954 | */ |
| 899 | dst_release(&rt->dst); | 955 | ip6_rt_put(rt); |
| 900 | goto relookup; | 956 | goto relookup; |
| 901 | 957 | ||
| 902 | out: | 958 | out: |
| @@ -1030,14 +1086,9 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
| 1030 | if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev))) | 1086 | if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev))) |
| 1031 | return NULL; | 1087 | return NULL; |
| 1032 | 1088 | ||
| 1033 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { | 1089 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) |
| 1034 | if (rt->rt6i_peer_genid != rt6_peer_genid()) { | ||
| 1035 | if (!rt6_has_peer(rt)) | ||
| 1036 | rt6_bind_peer(rt, 0); | ||
| 1037 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
| 1038 | } | ||
| 1039 | return dst; | 1090 | return dst; |
| 1040 | } | 1091 | |
| 1041 | return NULL; | 1092 | return NULL; |
| 1042 | } | 1093 | } |
| 1043 | 1094 | ||
| @@ -1316,12 +1367,6 @@ out: | |||
| 1316 | return entries > rt_max_size; | 1367 | return entries > rt_max_size; |
| 1317 | } | 1368 | } |
| 1318 | 1369 | ||
| 1319 | /* Clean host part of a prefix. Not necessary in radix tree, | ||
| 1320 | but results in cleaner routing tables. | ||
| 1321 | |||
| 1322 | Remove it only when all the things will work! | ||
| 1323 | */ | ||
| 1324 | |||
| 1325 | int ip6_dst_hoplimit(struct dst_entry *dst) | 1370 | int ip6_dst_hoplimit(struct dst_entry *dst) |
| 1326 | { | 1371 | { |
| 1327 | int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); | 1372 | int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); |
| @@ -1507,7 +1552,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1507 | goto out; | 1552 | goto out; |
| 1508 | if (dev) { | 1553 | if (dev) { |
| 1509 | if (dev != grt->dst.dev) { | 1554 | if (dev != grt->dst.dev) { |
| 1510 | dst_release(&grt->dst); | 1555 | ip6_rt_put(grt); |
| 1511 | goto out; | 1556 | goto out; |
| 1512 | } | 1557 | } |
| 1513 | } else { | 1558 | } else { |
| @@ -1518,7 +1563,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1518 | } | 1563 | } |
| 1519 | if (!(grt->rt6i_flags & RTF_GATEWAY)) | 1564 | if (!(grt->rt6i_flags & RTF_GATEWAY)) |
| 1520 | err = 0; | 1565 | err = 0; |
| 1521 | dst_release(&grt->dst); | 1566 | ip6_rt_put(grt); |
| 1522 | 1567 | ||
| 1523 | if (err) | 1568 | if (err) |
| 1524 | goto out; | 1569 | goto out; |
| @@ -1604,7 +1649,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) | |||
| 1604 | write_unlock_bh(&table->tb6_lock); | 1649 | write_unlock_bh(&table->tb6_lock); |
| 1605 | 1650 | ||
| 1606 | out: | 1651 | out: |
| 1607 | dst_release(&rt->dst); | 1652 | ip6_rt_put(rt); |
| 1608 | return err; | 1653 | return err; |
| 1609 | } | 1654 | } |
| 1610 | 1655 | ||
| @@ -1987,7 +2032,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
| 1987 | switch(cmd) { | 2032 | switch(cmd) { |
| 1988 | case SIOCADDRT: /* Add a route */ | 2033 | case SIOCADDRT: /* Add a route */ |
| 1989 | case SIOCDELRT: /* Delete a route */ | 2034 | case SIOCDELRT: /* Delete a route */ |
| 1990 | if (!capable(CAP_NET_ADMIN)) | 2035 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1991 | return -EPERM; | 2036 | return -EPERM; |
| 1992 | err = copy_from_user(&rtmsg, arg, | 2037 | err = copy_from_user(&rtmsg, arg, |
| 1993 | sizeof(struct in6_rtmsg)); | 2038 | sizeof(struct in6_rtmsg)); |
| @@ -2249,6 +2294,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { | |||
| 2249 | [RTA_IIF] = { .type = NLA_U32 }, | 2294 | [RTA_IIF] = { .type = NLA_U32 }, |
| 2250 | [RTA_PRIORITY] = { .type = NLA_U32 }, | 2295 | [RTA_PRIORITY] = { .type = NLA_U32 }, |
| 2251 | [RTA_METRICS] = { .type = NLA_NESTED }, | 2296 | [RTA_METRICS] = { .type = NLA_NESTED }, |
| 2297 | [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, | ||
| 2252 | }; | 2298 | }; |
| 2253 | 2299 | ||
| 2254 | static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | 2300 | static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, |
| @@ -2326,11 +2372,71 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 2326 | if (tb[RTA_TABLE]) | 2372 | if (tb[RTA_TABLE]) |
| 2327 | cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); | 2373 | cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); |
| 2328 | 2374 | ||
| 2375 | if (tb[RTA_MULTIPATH]) { | ||
| 2376 | cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); | ||
| 2377 | cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); | ||
| 2378 | } | ||
| 2379 | |||
| 2329 | err = 0; | 2380 | err = 0; |
| 2330 | errout: | 2381 | errout: |
| 2331 | return err; | 2382 | return err; |
| 2332 | } | 2383 | } |
| 2333 | 2384 | ||
| 2385 | static int ip6_route_multipath(struct fib6_config *cfg, int add) | ||
| 2386 | { | ||
| 2387 | struct fib6_config r_cfg; | ||
| 2388 | struct rtnexthop *rtnh; | ||
| 2389 | int remaining; | ||
| 2390 | int attrlen; | ||
| 2391 | int err = 0, last_err = 0; | ||
| 2392 | |||
| 2393 | beginning: | ||
| 2394 | rtnh = (struct rtnexthop *)cfg->fc_mp; | ||
| 2395 | remaining = cfg->fc_mp_len; | ||
| 2396 | |||
| 2397 | /* Parse a Multipath Entry */ | ||
| 2398 | while (rtnh_ok(rtnh, remaining)) { | ||
| 2399 | memcpy(&r_cfg, cfg, sizeof(*cfg)); | ||
| 2400 | if (rtnh->rtnh_ifindex) | ||
| 2401 | r_cfg.fc_ifindex = rtnh->rtnh_ifindex; | ||
| 2402 | |||
| 2403 | attrlen = rtnh_attrlen(rtnh); | ||
| 2404 | if (attrlen > 0) { | ||
| 2405 | struct nlattr *nla, *attrs = rtnh_attrs(rtnh); | ||
| 2406 | |||
| 2407 | nla = nla_find(attrs, attrlen, RTA_GATEWAY); | ||
| 2408 | if (nla) { | ||
| 2409 | nla_memcpy(&r_cfg.fc_gateway, nla, 16); | ||
| 2410 | r_cfg.fc_flags |= RTF_GATEWAY; | ||
| 2411 | } | ||
| 2412 | } | ||
| 2413 | err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); | ||
| 2414 | if (err) { | ||
| 2415 | last_err = err; | ||
| 2416 | /* If we are trying to remove a route, do not stop the | ||
| 2417 | * loop when ip6_route_del() fails (because next hop is | ||
| 2418 | * already gone), we should try to remove all next hops. | ||
| 2419 | */ | ||
| 2420 | if (add) { | ||
| 2421 | /* If add fails, we should try to delete all | ||
| 2422 | * next hops that have been already added. | ||
| 2423 | */ | ||
| 2424 | add = 0; | ||
| 2425 | goto beginning; | ||
| 2426 | } | ||
| 2427 | } | ||
| 2428 | /* Because each route is added like a single route we remove | ||
| 2429 | * this flag after the first nexthop (if there is a collision, | ||
| 2430 | * we have already fail to add the first nexthop: | ||
| 2431 | * fib6_add_rt2node() has reject it). | ||
| 2432 | */ | ||
| 2433 | cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL; | ||
| 2434 | rtnh = rtnh_next(rtnh, &remaining); | ||
| 2435 | } | ||
| 2436 | |||
| 2437 | return last_err; | ||
| 2438 | } | ||
| 2439 | |||
| 2334 | static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 2440 | static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
| 2335 | { | 2441 | { |
| 2336 | struct fib6_config cfg; | 2442 | struct fib6_config cfg; |
| @@ -2340,7 +2446,10 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a | |||
| 2340 | if (err < 0) | 2446 | if (err < 0) |
| 2341 | return err; | 2447 | return err; |
| 2342 | 2448 | ||
| 2343 | return ip6_route_del(&cfg); | 2449 | if (cfg.fc_mp) |
| 2450 | return ip6_route_multipath(&cfg, 0); | ||
| 2451 | else | ||
| 2452 | return ip6_route_del(&cfg); | ||
| 2344 | } | 2453 | } |
| 2345 | 2454 | ||
| 2346 | static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 2455 | static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
| @@ -2352,7 +2461,10 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a | |||
| 2352 | if (err < 0) | 2461 | if (err < 0) |
| 2353 | return err; | 2462 | return err; |
| 2354 | 2463 | ||
| 2355 | return ip6_route_add(&cfg); | 2464 | if (cfg.fc_mp) |
| 2465 | return ip6_route_multipath(&cfg, 1); | ||
| 2466 | else | ||
| 2467 | return ip6_route_add(&cfg); | ||
| 2356 | } | 2468 | } |
| 2357 | 2469 | ||
| 2358 | static inline size_t rt6_nlmsg_size(void) | 2470 | static inline size_t rt6_nlmsg_size(void) |
| @@ -2596,7 +2708,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
| 2596 | 2708 | ||
| 2597 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2709 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
| 2598 | if (!skb) { | 2710 | if (!skb) { |
| 2599 | dst_release(&rt->dst); | 2711 | ip6_rt_put(rt); |
| 2600 | err = -ENOBUFS; | 2712 | err = -ENOBUFS; |
| 2601 | goto errout; | 2713 | goto errout; |
| 2602 | } | 2714 | } |
| @@ -2873,6 +2985,10 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) | |||
| 2873 | table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; | 2985 | table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; |
| 2874 | table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; | 2986 | table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; |
| 2875 | table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | 2987 | table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; |
| 2988 | |||
| 2989 | /* Don't export sysctls to unprivileged users */ | ||
| 2990 | if (net->user_ns != &init_user_ns) | ||
| 2991 | table[0].procname = NULL; | ||
| 2876 | } | 2992 | } |
| 2877 | 2993 | ||
| 2878 | return table; | 2994 | return table; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3ed54ffd8d50..cfba99b2c2a4 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -65,9 +65,14 @@ | |||
| 65 | #define HASH_SIZE 16 | 65 | #define HASH_SIZE 16 |
| 66 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 66 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
| 67 | 67 | ||
| 68 | static bool log_ecn_error = true; | ||
| 69 | module_param(log_ecn_error, bool, 0644); | ||
| 70 | MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | ||
| 71 | |||
| 68 | static int ipip6_tunnel_init(struct net_device *dev); | 72 | static int ipip6_tunnel_init(struct net_device *dev); |
| 69 | static void ipip6_tunnel_setup(struct net_device *dev); | 73 | static void ipip6_tunnel_setup(struct net_device *dev); |
| 70 | static void ipip6_dev_free(struct net_device *dev); | 74 | static void ipip6_dev_free(struct net_device *dev); |
| 75 | static struct rtnl_link_ops sit_link_ops __read_mostly; | ||
| 71 | 76 | ||
| 72 | static int sit_net_id __read_mostly; | 77 | static int sit_net_id __read_mostly; |
| 73 | struct sit_net { | 78 | struct sit_net { |
| @@ -80,22 +85,6 @@ struct sit_net { | |||
| 80 | struct net_device *fb_tunnel_dev; | 85 | struct net_device *fb_tunnel_dev; |
| 81 | }; | 86 | }; |
| 82 | 87 | ||
| 83 | /* | ||
| 84 | * Locking : hash tables are protected by RCU and RTNL | ||
| 85 | */ | ||
| 86 | |||
| 87 | #define for_each_ip_tunnel_rcu(start) \ | ||
| 88 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
| 89 | |||
| 90 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
| 91 | struct pcpu_tstats { | ||
| 92 | u64 rx_packets; | ||
| 93 | u64 rx_bytes; | ||
| 94 | u64 tx_packets; | ||
| 95 | u64 tx_bytes; | ||
| 96 | struct u64_stats_sync syncp; | ||
| 97 | }; | ||
| 98 | |||
| 99 | static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev, | 88 | static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev, |
| 100 | struct rtnl_link_stats64 *tot) | 89 | struct rtnl_link_stats64 *tot) |
| 101 | { | 90 | { |
| @@ -121,6 +110,7 @@ static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev, | |||
| 121 | } | 110 | } |
| 122 | 111 | ||
| 123 | tot->rx_errors = dev->stats.rx_errors; | 112 | tot->rx_errors = dev->stats.rx_errors; |
| 113 | tot->rx_frame_errors = dev->stats.rx_frame_errors; | ||
| 124 | tot->tx_fifo_errors = dev->stats.tx_fifo_errors; | 114 | tot->tx_fifo_errors = dev->stats.tx_fifo_errors; |
| 125 | tot->tx_carrier_errors = dev->stats.tx_carrier_errors; | 115 | tot->tx_carrier_errors = dev->stats.tx_carrier_errors; |
| 126 | tot->tx_dropped = dev->stats.tx_dropped; | 116 | tot->tx_dropped = dev->stats.tx_dropped; |
| @@ -141,20 +131,20 @@ static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, | |||
| 141 | struct ip_tunnel *t; | 131 | struct ip_tunnel *t; |
| 142 | struct sit_net *sitn = net_generic(net, sit_net_id); | 132 | struct sit_net *sitn = net_generic(net, sit_net_id); |
| 143 | 133 | ||
| 144 | for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) { | 134 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { |
| 145 | if (local == t->parms.iph.saddr && | 135 | if (local == t->parms.iph.saddr && |
| 146 | remote == t->parms.iph.daddr && | 136 | remote == t->parms.iph.daddr && |
| 147 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 137 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 148 | (t->dev->flags & IFF_UP)) | 138 | (t->dev->flags & IFF_UP)) |
| 149 | return t; | 139 | return t; |
| 150 | } | 140 | } |
| 151 | for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) { | 141 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { |
| 152 | if (remote == t->parms.iph.daddr && | 142 | if (remote == t->parms.iph.daddr && |
| 153 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 143 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 154 | (t->dev->flags & IFF_UP)) | 144 | (t->dev->flags & IFF_UP)) |
| 155 | return t; | 145 | return t; |
| 156 | } | 146 | } |
| 157 | for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) { | 147 | for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { |
| 158 | if (local == t->parms.iph.saddr && | 148 | if (local == t->parms.iph.saddr && |
| 159 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 149 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 160 | (t->dev->flags & IFF_UP)) | 150 | (t->dev->flags & IFF_UP)) |
| @@ -231,6 +221,37 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | |||
| 231 | #endif | 221 | #endif |
| 232 | } | 222 | } |
| 233 | 223 | ||
| 224 | static int ipip6_tunnel_create(struct net_device *dev) | ||
| 225 | { | ||
| 226 | struct ip_tunnel *t = netdev_priv(dev); | ||
| 227 | struct net *net = dev_net(dev); | ||
| 228 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
| 229 | int err; | ||
| 230 | |||
| 231 | err = ipip6_tunnel_init(dev); | ||
| 232 | if (err < 0) | ||
| 233 | goto out; | ||
| 234 | ipip6_tunnel_clone_6rd(dev, sitn); | ||
| 235 | |||
| 236 | if ((__force u16)t->parms.i_flags & SIT_ISATAP) | ||
| 237 | dev->priv_flags |= IFF_ISATAP; | ||
| 238 | |||
| 239 | err = register_netdevice(dev); | ||
| 240 | if (err < 0) | ||
| 241 | goto out; | ||
| 242 | |||
| 243 | strcpy(t->parms.name, dev->name); | ||
| 244 | dev->rtnl_link_ops = &sit_link_ops; | ||
| 245 | |||
| 246 | dev_hold(dev); | ||
| 247 | |||
| 248 | ipip6_tunnel_link(sitn, t); | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | out: | ||
| 252 | return err; | ||
| 253 | } | ||
| 254 | |||
| 234 | static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, | 255 | static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, |
| 235 | struct ip_tunnel_parm *parms, int create) | 256 | struct ip_tunnel_parm *parms, int create) |
| 236 | { | 257 | { |
| @@ -271,21 +292,9 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, | |||
| 271 | nt = netdev_priv(dev); | 292 | nt = netdev_priv(dev); |
| 272 | 293 | ||
| 273 | nt->parms = *parms; | 294 | nt->parms = *parms; |
| 274 | if (ipip6_tunnel_init(dev) < 0) | 295 | if (ipip6_tunnel_create(dev) < 0) |
| 275 | goto failed_free; | 296 | goto failed_free; |
| 276 | ipip6_tunnel_clone_6rd(dev, sitn); | ||
| 277 | 297 | ||
| 278 | if (parms->i_flags & SIT_ISATAP) | ||
| 279 | dev->priv_flags |= IFF_ISATAP; | ||
| 280 | |||
| 281 | if (register_netdevice(dev) < 0) | ||
| 282 | goto failed_free; | ||
| 283 | |||
| 284 | strcpy(nt->parms.name, dev->name); | ||
| 285 | |||
| 286 | dev_hold(dev); | ||
| 287 | |||
| 288 | ipip6_tunnel_link(sitn, nt); | ||
| 289 | return nt; | 298 | return nt; |
| 290 | 299 | ||
| 291 | failed_free: | 300 | failed_free: |
| @@ -581,16 +590,11 @@ out: | |||
| 581 | return err; | 590 | return err; |
| 582 | } | 591 | } |
| 583 | 592 | ||
| 584 | static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) | ||
| 585 | { | ||
| 586 | if (INET_ECN_is_ce(iph->tos)) | ||
| 587 | IP6_ECN_set_ce(ipv6_hdr(skb)); | ||
| 588 | } | ||
| 589 | |||
| 590 | static int ipip6_rcv(struct sk_buff *skb) | 593 | static int ipip6_rcv(struct sk_buff *skb) |
| 591 | { | 594 | { |
| 592 | const struct iphdr *iph; | 595 | const struct iphdr *iph; |
| 593 | struct ip_tunnel *tunnel; | 596 | struct ip_tunnel *tunnel; |
| 597 | int err; | ||
| 594 | 598 | ||
| 595 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 599 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
| 596 | goto out; | 600 | goto out; |
| @@ -612,18 +616,27 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 612 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 616 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && |
| 613 | !isatap_chksrc(skb, iph, tunnel)) { | 617 | !isatap_chksrc(skb, iph, tunnel)) { |
| 614 | tunnel->dev->stats.rx_errors++; | 618 | tunnel->dev->stats.rx_errors++; |
| 615 | kfree_skb(skb); | 619 | goto out; |
| 616 | return 0; | 620 | } |
| 621 | |||
| 622 | __skb_tunnel_rx(skb, tunnel->dev); | ||
| 623 | |||
| 624 | err = IP_ECN_decapsulate(iph, skb); | ||
| 625 | if (unlikely(err)) { | ||
| 626 | if (log_ecn_error) | ||
| 627 | net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", | ||
| 628 | &iph->saddr, iph->tos); | ||
| 629 | if (err > 1) { | ||
| 630 | ++tunnel->dev->stats.rx_frame_errors; | ||
| 631 | ++tunnel->dev->stats.rx_errors; | ||
| 632 | goto out; | ||
| 633 | } | ||
| 617 | } | 634 | } |
| 618 | 635 | ||
| 619 | tstats = this_cpu_ptr(tunnel->dev->tstats); | 636 | tstats = this_cpu_ptr(tunnel->dev->tstats); |
| 620 | tstats->rx_packets++; | 637 | tstats->rx_packets++; |
| 621 | tstats->rx_bytes += skb->len; | 638 | tstats->rx_bytes += skb->len; |
| 622 | 639 | ||
| 623 | __skb_tunnel_rx(skb, tunnel->dev); | ||
| 624 | |||
| 625 | ipip6_ecn_decapsulate(iph, skb); | ||
| 626 | |||
| 627 | netif_rx(skb); | 640 | netif_rx(skb); |
| 628 | 641 | ||
| 629 | return 0; | 642 | return 0; |
| @@ -683,7 +696,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 683 | struct net_device *dev) | 696 | struct net_device *dev) |
| 684 | { | 697 | { |
| 685 | struct ip_tunnel *tunnel = netdev_priv(dev); | 698 | struct ip_tunnel *tunnel = netdev_priv(dev); |
| 686 | struct pcpu_tstats *tstats; | ||
| 687 | const struct iphdr *tiph = &tunnel->parms.iph; | 699 | const struct iphdr *tiph = &tunnel->parms.iph; |
| 688 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); | 700 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); |
| 689 | u8 tos = tunnel->parms.iph.tos; | 701 | u8 tos = tunnel->parms.iph.tos; |
| @@ -864,9 +876,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 864 | if ((iph->ttl = tiph->ttl) == 0) | 876 | if ((iph->ttl = tiph->ttl) == 0) |
| 865 | iph->ttl = iph6->hop_limit; | 877 | iph->ttl = iph6->hop_limit; |
| 866 | 878 | ||
| 867 | nf_reset(skb); | 879 | iptunnel_xmit(skb, dev); |
| 868 | tstats = this_cpu_ptr(dev->tstats); | ||
| 869 | __IPTUNNEL_XMIT(tstats, &dev->stats); | ||
| 870 | return NETDEV_TX_OK; | 880 | return NETDEV_TX_OK; |
| 871 | 881 | ||
| 872 | tx_error_icmp: | 882 | tx_error_icmp: |
| @@ -914,6 +924,59 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
| 914 | dev->iflink = tunnel->parms.link; | 924 | dev->iflink = tunnel->parms.link; |
| 915 | } | 925 | } |
| 916 | 926 | ||
| 927 | static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) | ||
| 928 | { | ||
| 929 | struct net *net = dev_net(t->dev); | ||
| 930 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
| 931 | |||
| 932 | ipip6_tunnel_unlink(sitn, t); | ||
| 933 | synchronize_net(); | ||
| 934 | t->parms.iph.saddr = p->iph.saddr; | ||
| 935 | t->parms.iph.daddr = p->iph.daddr; | ||
| 936 | memcpy(t->dev->dev_addr, &p->iph.saddr, 4); | ||
| 937 | memcpy(t->dev->broadcast, &p->iph.daddr, 4); | ||
| 938 | ipip6_tunnel_link(sitn, t); | ||
| 939 | t->parms.iph.ttl = p->iph.ttl; | ||
| 940 | t->parms.iph.tos = p->iph.tos; | ||
| 941 | if (t->parms.link != p->link) { | ||
| 942 | t->parms.link = p->link; | ||
| 943 | ipip6_tunnel_bind_dev(t->dev); | ||
| 944 | } | ||
| 945 | netdev_state_change(t->dev); | ||
| 946 | } | ||
| 947 | |||
| 948 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 949 | static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, | ||
| 950 | struct ip_tunnel_6rd *ip6rd) | ||
| 951 | { | ||
| 952 | struct in6_addr prefix; | ||
| 953 | __be32 relay_prefix; | ||
| 954 | |||
| 955 | if (ip6rd->relay_prefixlen > 32 || | ||
| 956 | ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64) | ||
| 957 | return -EINVAL; | ||
| 958 | |||
| 959 | ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen); | ||
| 960 | if (!ipv6_addr_equal(&prefix, &ip6rd->prefix)) | ||
| 961 | return -EINVAL; | ||
| 962 | if (ip6rd->relay_prefixlen) | ||
| 963 | relay_prefix = ip6rd->relay_prefix & | ||
| 964 | htonl(0xffffffffUL << | ||
| 965 | (32 - ip6rd->relay_prefixlen)); | ||
| 966 | else | ||
| 967 | relay_prefix = 0; | ||
| 968 | if (relay_prefix != ip6rd->relay_prefix) | ||
| 969 | return -EINVAL; | ||
| 970 | |||
| 971 | t->ip6rd.prefix = prefix; | ||
| 972 | t->ip6rd.relay_prefix = relay_prefix; | ||
| 973 | t->ip6rd.prefixlen = ip6rd->prefixlen; | ||
| 974 | t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen; | ||
| 975 | netdev_state_change(t->dev); | ||
| 976 | return 0; | ||
| 977 | } | ||
| 978 | #endif | ||
| 979 | |||
| 917 | static int | 980 | static int |
| 918 | ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | 981 | ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) |
| 919 | { | 982 | { |
| @@ -966,7 +1029,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 966 | case SIOCADDTUNNEL: | 1029 | case SIOCADDTUNNEL: |
| 967 | case SIOCCHGTUNNEL: | 1030 | case SIOCCHGTUNNEL: |
| 968 | err = -EPERM; | 1031 | err = -EPERM; |
| 969 | if (!capable(CAP_NET_ADMIN)) | 1032 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 970 | goto done; | 1033 | goto done; |
| 971 | 1034 | ||
| 972 | err = -EFAULT; | 1035 | err = -EFAULT; |
| @@ -995,28 +1058,13 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 995 | break; | 1058 | break; |
| 996 | } | 1059 | } |
| 997 | t = netdev_priv(dev); | 1060 | t = netdev_priv(dev); |
| 998 | ipip6_tunnel_unlink(sitn, t); | ||
| 999 | synchronize_net(); | ||
| 1000 | t->parms.iph.saddr = p.iph.saddr; | ||
| 1001 | t->parms.iph.daddr = p.iph.daddr; | ||
| 1002 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | ||
| 1003 | memcpy(dev->broadcast, &p.iph.daddr, 4); | ||
| 1004 | ipip6_tunnel_link(sitn, t); | ||
| 1005 | netdev_state_change(dev); | ||
| 1006 | } | 1061 | } |
| 1062 | |||
| 1063 | ipip6_tunnel_update(t, &p); | ||
| 1007 | } | 1064 | } |
| 1008 | 1065 | ||
| 1009 | if (t) { | 1066 | if (t) { |
| 1010 | err = 0; | 1067 | err = 0; |
| 1011 | if (cmd == SIOCCHGTUNNEL) { | ||
| 1012 | t->parms.iph.ttl = p.iph.ttl; | ||
| 1013 | t->parms.iph.tos = p.iph.tos; | ||
| 1014 | if (t->parms.link != p.link) { | ||
| 1015 | t->parms.link = p.link; | ||
| 1016 | ipip6_tunnel_bind_dev(dev); | ||
| 1017 | netdev_state_change(dev); | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) | 1068 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) |
| 1021 | err = -EFAULT; | 1069 | err = -EFAULT; |
| 1022 | } else | 1070 | } else |
| @@ -1025,7 +1073,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1025 | 1073 | ||
| 1026 | case SIOCDELTUNNEL: | 1074 | case SIOCDELTUNNEL: |
| 1027 | err = -EPERM; | 1075 | err = -EPERM; |
| 1028 | if (!capable(CAP_NET_ADMIN)) | 1076 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1029 | goto done; | 1077 | goto done; |
| 1030 | 1078 | ||
| 1031 | if (dev == sitn->fb_tunnel_dev) { | 1079 | if (dev == sitn->fb_tunnel_dev) { |
| @@ -1058,7 +1106,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1058 | case SIOCDELPRL: | 1106 | case SIOCDELPRL: |
| 1059 | case SIOCCHGPRL: | 1107 | case SIOCCHGPRL: |
| 1060 | err = -EPERM; | 1108 | err = -EPERM; |
| 1061 | if (!capable(CAP_NET_ADMIN)) | 1109 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1062 | goto done; | 1110 | goto done; |
| 1063 | err = -EINVAL; | 1111 | err = -EINVAL; |
| 1064 | if (dev == sitn->fb_tunnel_dev) | 1112 | if (dev == sitn->fb_tunnel_dev) |
| @@ -1087,7 +1135,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1087 | case SIOCCHG6RD: | 1135 | case SIOCCHG6RD: |
| 1088 | case SIOCDEL6RD: | 1136 | case SIOCDEL6RD: |
| 1089 | err = -EPERM; | 1137 | err = -EPERM; |
| 1090 | if (!capable(CAP_NET_ADMIN)) | 1138 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1091 | goto done; | 1139 | goto done; |
| 1092 | 1140 | ||
| 1093 | err = -EFAULT; | 1141 | err = -EFAULT; |
| @@ -1098,31 +1146,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 1098 | t = netdev_priv(dev); | 1146 | t = netdev_priv(dev); |
| 1099 | 1147 | ||
| 1100 | if (cmd != SIOCDEL6RD) { | 1148 | if (cmd != SIOCDEL6RD) { |
| 1101 | struct in6_addr prefix; | 1149 | err = ipip6_tunnel_update_6rd(t, &ip6rd); |
| 1102 | __be32 relay_prefix; | 1150 | if (err < 0) |
| 1103 | |||
| 1104 | err = -EINVAL; | ||
| 1105 | if (ip6rd.relay_prefixlen > 32 || | ||
| 1106 | ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64) | ||
| 1107 | goto done; | ||
| 1108 | |||
| 1109 | ipv6_addr_prefix(&prefix, &ip6rd.prefix, | ||
| 1110 | ip6rd.prefixlen); | ||
| 1111 | if (!ipv6_addr_equal(&prefix, &ip6rd.prefix)) | ||
| 1112 | goto done; | ||
| 1113 | if (ip6rd.relay_prefixlen) | ||
| 1114 | relay_prefix = ip6rd.relay_prefix & | ||
| 1115 | htonl(0xffffffffUL << | ||
| 1116 | (32 - ip6rd.relay_prefixlen)); | ||
| 1117 | else | ||
| 1118 | relay_prefix = 0; | ||
| 1119 | if (relay_prefix != ip6rd.relay_prefix) | ||
| 1120 | goto done; | 1151 | goto done; |
| 1121 | |||
| 1122 | t->ip6rd.prefix = prefix; | ||
| 1123 | t->ip6rd.relay_prefix = relay_prefix; | ||
| 1124 | t->ip6rd.prefixlen = ip6rd.prefixlen; | ||
| 1125 | t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen; | ||
| 1126 | } else | 1152 | } else |
| 1127 | ipip6_tunnel_clone_6rd(dev, sitn); | 1153 | ipip6_tunnel_clone_6rd(dev, sitn); |
| 1128 | 1154 | ||
| @@ -1216,6 +1242,239 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
| 1216 | return 0; | 1242 | return 0; |
| 1217 | } | 1243 | } |
| 1218 | 1244 | ||
| 1245 | static void ipip6_netlink_parms(struct nlattr *data[], | ||
| 1246 | struct ip_tunnel_parm *parms) | ||
| 1247 | { | ||
| 1248 | memset(parms, 0, sizeof(*parms)); | ||
| 1249 | |||
| 1250 | parms->iph.version = 4; | ||
| 1251 | parms->iph.protocol = IPPROTO_IPV6; | ||
| 1252 | parms->iph.ihl = 5; | ||
| 1253 | parms->iph.ttl = 64; | ||
| 1254 | |||
| 1255 | if (!data) | ||
| 1256 | return; | ||
| 1257 | |||
| 1258 | if (data[IFLA_IPTUN_LINK]) | ||
| 1259 | parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); | ||
| 1260 | |||
| 1261 | if (data[IFLA_IPTUN_LOCAL]) | ||
| 1262 | parms->iph.saddr = nla_get_be32(data[IFLA_IPTUN_LOCAL]); | ||
| 1263 | |||
| 1264 | if (data[IFLA_IPTUN_REMOTE]) | ||
| 1265 | parms->iph.daddr = nla_get_be32(data[IFLA_IPTUN_REMOTE]); | ||
| 1266 | |||
| 1267 | if (data[IFLA_IPTUN_TTL]) { | ||
| 1268 | parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); | ||
| 1269 | if (parms->iph.ttl) | ||
| 1270 | parms->iph.frag_off = htons(IP_DF); | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | if (data[IFLA_IPTUN_TOS]) | ||
| 1274 | parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); | ||
| 1275 | |||
| 1276 | if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) | ||
| 1277 | parms->iph.frag_off = htons(IP_DF); | ||
| 1278 | |||
| 1279 | if (data[IFLA_IPTUN_FLAGS]) | ||
| 1280 | parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]); | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1284 | /* This function returns true when 6RD attributes are present in the nl msg */ | ||
| 1285 | static bool ipip6_netlink_6rd_parms(struct nlattr *data[], | ||
| 1286 | struct ip_tunnel_6rd *ip6rd) | ||
| 1287 | { | ||
| 1288 | bool ret = false; | ||
| 1289 | memset(ip6rd, 0, sizeof(*ip6rd)); | ||
| 1290 | |||
| 1291 | if (!data) | ||
| 1292 | return ret; | ||
| 1293 | |||
| 1294 | if (data[IFLA_IPTUN_6RD_PREFIX]) { | ||
| 1295 | ret = true; | ||
| 1296 | nla_memcpy(&ip6rd->prefix, data[IFLA_IPTUN_6RD_PREFIX], | ||
| 1297 | sizeof(struct in6_addr)); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) { | ||
| 1301 | ret = true; | ||
| 1302 | ip6rd->relay_prefix = | ||
| 1303 | nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]); | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | if (data[IFLA_IPTUN_6RD_PREFIXLEN]) { | ||
| 1307 | ret = true; | ||
| 1308 | ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) { | ||
| 1312 | ret = true; | ||
| 1313 | ip6rd->relay_prefixlen = | ||
| 1314 | nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | return ret; | ||
| 1318 | } | ||
| 1319 | #endif | ||
| 1320 | |||
| 1321 | static int ipip6_newlink(struct net *src_net, struct net_device *dev, | ||
| 1322 | struct nlattr *tb[], struct nlattr *data[]) | ||
| 1323 | { | ||
| 1324 | struct net *net = dev_net(dev); | ||
| 1325 | struct ip_tunnel *nt; | ||
| 1326 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1327 | struct ip_tunnel_6rd ip6rd; | ||
| 1328 | #endif | ||
| 1329 | int err; | ||
| 1330 | |||
| 1331 | nt = netdev_priv(dev); | ||
| 1332 | ipip6_netlink_parms(data, &nt->parms); | ||
| 1333 | |||
| 1334 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) | ||
| 1335 | return -EEXIST; | ||
| 1336 | |||
| 1337 | err = ipip6_tunnel_create(dev); | ||
| 1338 | if (err < 0) | ||
| 1339 | return err; | ||
| 1340 | |||
| 1341 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1342 | if (ipip6_netlink_6rd_parms(data, &ip6rd)) | ||
| 1343 | err = ipip6_tunnel_update_6rd(nt, &ip6rd); | ||
| 1344 | #endif | ||
| 1345 | |||
| 1346 | return err; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], | ||
| 1350 | struct nlattr *data[]) | ||
| 1351 | { | ||
| 1352 | struct ip_tunnel *t; | ||
| 1353 | struct ip_tunnel_parm p; | ||
| 1354 | struct net *net = dev_net(dev); | ||
| 1355 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
| 1356 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1357 | struct ip_tunnel_6rd ip6rd; | ||
| 1358 | #endif | ||
| 1359 | |||
| 1360 | if (dev == sitn->fb_tunnel_dev) | ||
| 1361 | return -EINVAL; | ||
| 1362 | |||
| 1363 | ipip6_netlink_parms(data, &p); | ||
| 1364 | |||
| 1365 | if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || | ||
| 1366 | (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) | ||
| 1367 | return -EINVAL; | ||
| 1368 | |||
| 1369 | t = ipip6_tunnel_locate(net, &p, 0); | ||
| 1370 | |||
| 1371 | if (t) { | ||
| 1372 | if (t->dev != dev) | ||
| 1373 | return -EEXIST; | ||
| 1374 | } else | ||
| 1375 | t = netdev_priv(dev); | ||
| 1376 | |||
| 1377 | ipip6_tunnel_update(t, &p); | ||
| 1378 | |||
| 1379 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1380 | if (ipip6_netlink_6rd_parms(data, &ip6rd)) | ||
| 1381 | return ipip6_tunnel_update_6rd(t, &ip6rd); | ||
| 1382 | #endif | ||
| 1383 | |||
| 1384 | return 0; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | static size_t ipip6_get_size(const struct net_device *dev) | ||
| 1388 | { | ||
| 1389 | return | ||
| 1390 | /* IFLA_IPTUN_LINK */ | ||
| 1391 | nla_total_size(4) + | ||
| 1392 | /* IFLA_IPTUN_LOCAL */ | ||
| 1393 | nla_total_size(4) + | ||
| 1394 | /* IFLA_IPTUN_REMOTE */ | ||
| 1395 | nla_total_size(4) + | ||
| 1396 | /* IFLA_IPTUN_TTL */ | ||
| 1397 | nla_total_size(1) + | ||
| 1398 | /* IFLA_IPTUN_TOS */ | ||
| 1399 | nla_total_size(1) + | ||
| 1400 | /* IFLA_IPTUN_PMTUDISC */ | ||
| 1401 | nla_total_size(1) + | ||
| 1402 | /* IFLA_IPTUN_FLAGS */ | ||
| 1403 | nla_total_size(2) + | ||
| 1404 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1405 | /* IFLA_IPTUN_6RD_PREFIX */ | ||
| 1406 | nla_total_size(sizeof(struct in6_addr)) + | ||
| 1407 | /* IFLA_IPTUN_6RD_RELAY_PREFIX */ | ||
| 1408 | nla_total_size(4) + | ||
| 1409 | /* IFLA_IPTUN_6RD_PREFIXLEN */ | ||
| 1410 | nla_total_size(2) + | ||
| 1411 | /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ | ||
| 1412 | nla_total_size(2) + | ||
| 1413 | #endif | ||
| 1414 | 0; | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) | ||
| 1418 | { | ||
| 1419 | struct ip_tunnel *tunnel = netdev_priv(dev); | ||
| 1420 | struct ip_tunnel_parm *parm = &tunnel->parms; | ||
| 1421 | |||
| 1422 | if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || | ||
| 1423 | nla_put_be32(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || | ||
| 1424 | nla_put_be32(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || | ||
| 1425 | nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || | ||
| 1426 | nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || | ||
| 1427 | nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, | ||
| 1428 | !!(parm->iph.frag_off & htons(IP_DF))) || | ||
| 1429 | nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) | ||
| 1430 | goto nla_put_failure; | ||
| 1431 | |||
| 1432 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1433 | if (nla_put(skb, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr), | ||
| 1434 | &tunnel->ip6rd.prefix) || | ||
| 1435 | nla_put_be32(skb, IFLA_IPTUN_6RD_RELAY_PREFIX, | ||
| 1436 | tunnel->ip6rd.relay_prefix) || | ||
| 1437 | nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN, | ||
| 1438 | tunnel->ip6rd.prefixlen) || | ||
| 1439 | nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, | ||
| 1440 | tunnel->ip6rd.relay_prefixlen)) | ||
| 1441 | goto nla_put_failure; | ||
| 1442 | #endif | ||
| 1443 | |||
| 1444 | return 0; | ||
| 1445 | |||
| 1446 | nla_put_failure: | ||
| 1447 | return -EMSGSIZE; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { | ||
| 1451 | [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, | ||
| 1452 | [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, | ||
| 1453 | [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, | ||
| 1454 | [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, | ||
| 1455 | [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, | ||
| 1456 | [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, | ||
| 1457 | [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, | ||
| 1458 | #ifdef CONFIG_IPV6_SIT_6RD | ||
| 1459 | [IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) }, | ||
| 1460 | [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 }, | ||
| 1461 | [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, | ||
| 1462 | [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, | ||
| 1463 | #endif | ||
| 1464 | }; | ||
| 1465 | |||
| 1466 | static struct rtnl_link_ops sit_link_ops __read_mostly = { | ||
| 1467 | .kind = "sit", | ||
| 1468 | .maxtype = IFLA_IPTUN_MAX, | ||
| 1469 | .policy = ipip6_policy, | ||
| 1470 | .priv_size = sizeof(struct ip_tunnel), | ||
| 1471 | .setup = ipip6_tunnel_setup, | ||
| 1472 | .newlink = ipip6_newlink, | ||
| 1473 | .changelink = ipip6_changelink, | ||
| 1474 | .get_size = ipip6_get_size, | ||
| 1475 | .fill_info = ipip6_fill_info, | ||
| 1476 | }; | ||
| 1477 | |||
| 1219 | static struct xfrm_tunnel sit_handler __read_mostly = { | 1478 | static struct xfrm_tunnel sit_handler __read_mostly = { |
| 1220 | .handler = ipip6_rcv, | 1479 | .handler = ipip6_rcv, |
| 1221 | .err_handler = ipip6_err, | 1480 | .err_handler = ipip6_err, |
| @@ -1302,6 +1561,7 @@ static struct pernet_operations sit_net_ops = { | |||
| 1302 | 1561 | ||
| 1303 | static void __exit sit_cleanup(void) | 1562 | static void __exit sit_cleanup(void) |
| 1304 | { | 1563 | { |
| 1564 | rtnl_link_unregister(&sit_link_ops); | ||
| 1305 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | 1565 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); |
| 1306 | 1566 | ||
| 1307 | unregister_pernet_device(&sit_net_ops); | 1567 | unregister_pernet_device(&sit_net_ops); |
| @@ -1319,10 +1579,21 @@ static int __init sit_init(void) | |||
| 1319 | return err; | 1579 | return err; |
| 1320 | err = xfrm4_tunnel_register(&sit_handler, AF_INET6); | 1580 | err = xfrm4_tunnel_register(&sit_handler, AF_INET6); |
| 1321 | if (err < 0) { | 1581 | if (err < 0) { |
| 1322 | unregister_pernet_device(&sit_net_ops); | ||
| 1323 | pr_info("%s: can't add protocol\n", __func__); | 1582 | pr_info("%s: can't add protocol\n", __func__); |
| 1583 | goto xfrm_tunnel_failed; | ||
| 1324 | } | 1584 | } |
| 1585 | err = rtnl_link_register(&sit_link_ops); | ||
| 1586 | if (err < 0) | ||
| 1587 | goto rtnl_link_failed; | ||
| 1588 | |||
| 1589 | out: | ||
| 1325 | return err; | 1590 | return err; |
| 1591 | |||
| 1592 | rtnl_link_failed: | ||
| 1593 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | ||
| 1594 | xfrm_tunnel_failed: | ||
| 1595 | unregister_pernet_device(&sit_net_ops); | ||
| 1596 | goto out; | ||
| 1326 | } | 1597 | } |
| 1327 | 1598 | ||
| 1328 | module_init(sit_init); | 1599 | module_init(sit_init); |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 182ab9a85d6c..40161977f7cf 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
| @@ -214,7 +214,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 214 | ireq6->iif = inet6_iif(skb); | 214 | ireq6->iif = inet6_iif(skb); |
| 215 | 215 | ||
| 216 | req->expires = 0UL; | 216 | req->expires = 0UL; |
| 217 | req->retrans = 0; | 217 | req->num_retrans = 0; |
| 218 | ireq->ecn_ok = ecn_ok; | 218 | ireq->ecn_ok = ecn_ok; |
| 219 | ireq->snd_wscale = tcp_opt.snd_wscale; | 219 | ireq->snd_wscale = tcp_opt.snd_wscale; |
| 220 | ireq->sack_ok = tcp_opt.sack_ok; | 220 | ireq->sack_ok = tcp_opt.sack_ok; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 26175bffbaa0..6565cf55eb1e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -77,9 +77,6 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 77 | struct request_sock *req); | 77 | struct request_sock *req); |
| 78 | 78 | ||
| 79 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 79 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
| 80 | static void __tcp_v6_send_check(struct sk_buff *skb, | ||
| 81 | const struct in6_addr *saddr, | ||
| 82 | const struct in6_addr *daddr); | ||
| 83 | 80 | ||
| 84 | static const struct inet_connection_sock_af_ops ipv6_mapped; | 81 | static const struct inet_connection_sock_af_ops ipv6_mapped; |
| 85 | static const struct inet_connection_sock_af_ops ipv6_specific; | 82 | static const struct inet_connection_sock_af_ops ipv6_specific; |
| @@ -119,14 +116,6 @@ static void tcp_v6_hash(struct sock *sk) | |||
| 119 | } | 116 | } |
| 120 | } | 117 | } |
| 121 | 118 | ||
| 122 | static __inline__ __sum16 tcp_v6_check(int len, | ||
| 123 | const struct in6_addr *saddr, | ||
| 124 | const struct in6_addr *daddr, | ||
| 125 | __wsum base) | ||
| 126 | { | ||
| 127 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); | ||
| 128 | } | ||
| 129 | |||
| 130 | static __u32 tcp_v6_init_sequence(const struct sk_buff *skb) | 119 | static __u32 tcp_v6_init_sequence(const struct sk_buff *skb) |
| 131 | { | 120 | { |
| 132 | return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, | 121 | return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, |
| @@ -306,7 +295,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 306 | if (err) | 295 | if (err) |
| 307 | goto late_failure; | 296 | goto late_failure; |
| 308 | 297 | ||
| 309 | if (!tp->write_seq) | 298 | if (!tp->write_seq && likely(!tp->repair)) |
| 310 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, | 299 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, |
| 311 | np->daddr.s6_addr32, | 300 | np->daddr.s6_addr32, |
| 312 | inet->inet_sport, | 301 | inet->inet_sport, |
| @@ -495,9 +484,12 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | |||
| 495 | struct request_values *rvp) | 484 | struct request_values *rvp) |
| 496 | { | 485 | { |
| 497 | struct flowi6 fl6; | 486 | struct flowi6 fl6; |
| 487 | int res; | ||
| 498 | 488 | ||
| 499 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | 489 | res = tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); |
| 500 | return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); | 490 | if (!res) |
| 491 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 492 | return res; | ||
| 501 | } | 493 | } |
| 502 | 494 | ||
| 503 | static void tcp_v6_reqsk_destructor(struct request_sock *req) | 495 | static void tcp_v6_reqsk_destructor(struct request_sock *req) |
| @@ -719,94 +711,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
| 719 | }; | 711 | }; |
| 720 | #endif | 712 | #endif |
| 721 | 713 | ||
| 722 | static void __tcp_v6_send_check(struct sk_buff *skb, | ||
| 723 | const struct in6_addr *saddr, const struct in6_addr *daddr) | ||
| 724 | { | ||
| 725 | struct tcphdr *th = tcp_hdr(skb); | ||
| 726 | |||
| 727 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
| 728 | th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); | ||
| 729 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
| 730 | skb->csum_offset = offsetof(struct tcphdr, check); | ||
| 731 | } else { | ||
| 732 | th->check = tcp_v6_check(skb->len, saddr, daddr, | ||
| 733 | csum_partial(th, th->doff << 2, | ||
| 734 | skb->csum)); | ||
| 735 | } | ||
| 736 | } | ||
| 737 | |||
| 738 | static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) | ||
| 739 | { | ||
| 740 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 741 | |||
| 742 | __tcp_v6_send_check(skb, &np->saddr, &np->daddr); | ||
| 743 | } | ||
| 744 | |||
| 745 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | ||
| 746 | { | ||
| 747 | const struct ipv6hdr *ipv6h; | ||
| 748 | struct tcphdr *th; | ||
| 749 | |||
| 750 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
| 751 | return -EINVAL; | ||
| 752 | |||
| 753 | ipv6h = ipv6_hdr(skb); | ||
| 754 | th = tcp_hdr(skb); | ||
| 755 | |||
| 756 | th->check = 0; | ||
| 757 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 758 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
| 759 | return 0; | ||
| 760 | } | ||
| 761 | |||
| 762 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | ||
| 763 | struct sk_buff *skb) | ||
| 764 | { | ||
| 765 | const struct ipv6hdr *iph = skb_gro_network_header(skb); | ||
| 766 | __wsum wsum; | ||
| 767 | __sum16 sum; | ||
| 768 | |||
| 769 | switch (skb->ip_summed) { | ||
| 770 | case CHECKSUM_COMPLETE: | ||
| 771 | if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, | ||
| 772 | skb->csum)) { | ||
| 773 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 774 | break; | ||
| 775 | } | ||
| 776 | flush: | ||
| 777 | NAPI_GRO_CB(skb)->flush = 1; | ||
| 778 | return NULL; | ||
| 779 | |||
| 780 | case CHECKSUM_NONE: | ||
| 781 | wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, | ||
| 782 | skb_gro_len(skb), | ||
| 783 | IPPROTO_TCP, 0)); | ||
| 784 | sum = csum_fold(skb_checksum(skb, | ||
| 785 | skb_gro_offset(skb), | ||
| 786 | skb_gro_len(skb), | ||
| 787 | wsum)); | ||
| 788 | if (sum) | ||
| 789 | goto flush; | ||
| 790 | |||
| 791 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 792 | break; | ||
| 793 | } | ||
| 794 | |||
| 795 | return tcp_gro_receive(head, skb); | ||
| 796 | } | ||
| 797 | |||
| 798 | static int tcp6_gro_complete(struct sk_buff *skb) | ||
| 799 | { | ||
| 800 | const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 801 | struct tcphdr *th = tcp_hdr(skb); | ||
| 802 | |||
| 803 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), | ||
| 804 | &iph->saddr, &iph->daddr, 0); | ||
| 805 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | ||
| 806 | |||
| 807 | return tcp_gro_complete(skb); | ||
| 808 | } | ||
| 809 | |||
| 810 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | 714 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
| 811 | u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass) | 715 | u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass) |
| 812 | { | 716 | { |
| @@ -1364,7 +1268,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1364 | 1268 | ||
| 1365 | tcp_initialize_rcv_mss(newsk); | 1269 | tcp_initialize_rcv_mss(newsk); |
| 1366 | tcp_synack_rtt_meas(newsk, req); | 1270 | tcp_synack_rtt_meas(newsk, req); |
| 1367 | newtp->total_retrans = req->retrans; | 1271 | newtp->total_retrans = req->num_retrans; |
| 1368 | 1272 | ||
| 1369 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; | 1273 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; |
| 1370 | newinet->inet_rcv_saddr = LOOPBACK4_IPV6; | 1274 | newinet->inet_rcv_saddr = LOOPBACK4_IPV6; |
| @@ -1741,11 +1645,11 @@ static void tcp_v6_early_demux(struct sk_buff *skb) | |||
| 1741 | skb->destructor = sock_edemux; | 1645 | skb->destructor = sock_edemux; |
| 1742 | if (sk->sk_state != TCP_TIME_WAIT) { | 1646 | if (sk->sk_state != TCP_TIME_WAIT) { |
| 1743 | struct dst_entry *dst = sk->sk_rx_dst; | 1647 | struct dst_entry *dst = sk->sk_rx_dst; |
| 1744 | struct inet_sock *icsk = inet_sk(sk); | 1648 | |
| 1745 | if (dst) | 1649 | if (dst) |
| 1746 | dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); | 1650 | dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); |
| 1747 | if (dst && | 1651 | if (dst && |
| 1748 | icsk->rx_dst_ifindex == skb->skb_iif) | 1652 | inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) |
| 1749 | skb_dst_set_noref(skb, dst); | 1653 | skb_dst_set_noref(skb, dst); |
| 1750 | } | 1654 | } |
| 1751 | } | 1655 | } |
| @@ -1866,7 +1770,7 @@ static void get_openreq6(struct seq_file *seq, | |||
| 1866 | 0,0, /* could print option size, but that is af dependent. */ | 1770 | 0,0, /* could print option size, but that is af dependent. */ |
| 1867 | 1, /* timers active (only the expire timer) */ | 1771 | 1, /* timers active (only the expire timer) */ |
| 1868 | jiffies_to_clock_t(ttd), | 1772 | jiffies_to_clock_t(ttd), |
| 1869 | req->retrans, | 1773 | req->num_timeout, |
| 1870 | from_kuid_munged(seq_user_ns(seq), uid), | 1774 | from_kuid_munged(seq_user_ns(seq), uid), |
| 1871 | 0, /* non standard timer */ | 1775 | 0, /* non standard timer */ |
| 1872 | 0, /* open_requests have no inode */ | 1776 | 0, /* open_requests have no inode */ |
| @@ -2063,10 +1967,6 @@ static const struct inet6_protocol tcpv6_protocol = { | |||
| 2063 | .early_demux = tcp_v6_early_demux, | 1967 | .early_demux = tcp_v6_early_demux, |
| 2064 | .handler = tcp_v6_rcv, | 1968 | .handler = tcp_v6_rcv, |
| 2065 | .err_handler = tcp_v6_err, | 1969 | .err_handler = tcp_v6_err, |
| 2066 | .gso_send_check = tcp_v6_gso_send_check, | ||
| 2067 | .gso_segment = tcp_tso_segment, | ||
| 2068 | .gro_receive = tcp6_gro_receive, | ||
| 2069 | .gro_complete = tcp6_gro_complete, | ||
| 2070 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 1970 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
| 2071 | }; | 1971 | }; |
| 2072 | 1972 | ||
| @@ -2121,10 +2021,10 @@ int __init tcpv6_init(void) | |||
| 2121 | out: | 2021 | out: |
| 2122 | return ret; | 2022 | return ret; |
| 2123 | 2023 | ||
| 2124 | out_tcpv6_protocol: | ||
| 2125 | inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); | ||
| 2126 | out_tcpv6_protosw: | 2024 | out_tcpv6_protosw: |
| 2127 | inet6_unregister_protosw(&tcpv6_protosw); | 2025 | inet6_unregister_protosw(&tcpv6_protosw); |
| 2026 | out_tcpv6_protocol: | ||
| 2027 | inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); | ||
| 2128 | goto out; | 2028 | goto out; |
| 2129 | } | 2029 | } |
| 2130 | 2030 | ||
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c new file mode 100644 index 000000000000..2ec6bf6a0aa0 --- /dev/null +++ b/net/ipv6/tcpv6_offload.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * IPV6 GSO/GRO offload support | ||
| 3 | * Linux INET6 implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * TCPv6 GSO/GRO support | ||
| 11 | */ | ||
| 12 | #include <linux/skbuff.h> | ||
| 13 | #include <net/protocol.h> | ||
| 14 | #include <net/tcp.h> | ||
| 15 | #include <net/ip6_checksum.h> | ||
| 16 | #include "ip6_offload.h" | ||
| 17 | |||
| 18 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | ||
| 19 | { | ||
| 20 | const struct ipv6hdr *ipv6h; | ||
| 21 | struct tcphdr *th; | ||
| 22 | |||
| 23 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
| 24 | return -EINVAL; | ||
| 25 | |||
| 26 | ipv6h = ipv6_hdr(skb); | ||
| 27 | th = tcp_hdr(skb); | ||
| 28 | |||
| 29 | th->check = 0; | ||
| 30 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 31 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | ||
| 36 | struct sk_buff *skb) | ||
| 37 | { | ||
| 38 | const struct ipv6hdr *iph = skb_gro_network_header(skb); | ||
| 39 | __wsum wsum; | ||
| 40 | __sum16 sum; | ||
| 41 | |||
| 42 | switch (skb->ip_summed) { | ||
| 43 | case CHECKSUM_COMPLETE: | ||
| 44 | if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, | ||
| 45 | skb->csum)) { | ||
| 46 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | flush: | ||
| 50 | NAPI_GRO_CB(skb)->flush = 1; | ||
| 51 | return NULL; | ||
| 52 | |||
| 53 | case CHECKSUM_NONE: | ||
| 54 | wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, | ||
| 55 | skb_gro_len(skb), | ||
| 56 | IPPROTO_TCP, 0)); | ||
| 57 | sum = csum_fold(skb_checksum(skb, | ||
| 58 | skb_gro_offset(skb), | ||
| 59 | skb_gro_len(skb), | ||
| 60 | wsum)); | ||
| 61 | if (sum) | ||
| 62 | goto flush; | ||
| 63 | |||
| 64 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | |||
| 68 | return tcp_gro_receive(head, skb); | ||
| 69 | } | ||
| 70 | |||
| 71 | static int tcp6_gro_complete(struct sk_buff *skb) | ||
| 72 | { | ||
| 73 | const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 74 | struct tcphdr *th = tcp_hdr(skb); | ||
| 75 | |||
| 76 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), | ||
| 77 | &iph->saddr, &iph->daddr, 0); | ||
| 78 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | ||
| 79 | |||
| 80 | return tcp_gro_complete(skb); | ||
| 81 | } | ||
| 82 | |||
| 83 | static const struct net_offload tcpv6_offload = { | ||
| 84 | .callbacks = { | ||
| 85 | .gso_send_check = tcp_v6_gso_send_check, | ||
| 86 | .gso_segment = tcp_tso_segment, | ||
| 87 | .gro_receive = tcp6_gro_receive, | ||
| 88 | .gro_complete = tcp6_gro_complete, | ||
| 89 | }, | ||
| 90 | }; | ||
| 91 | |||
| 92 | int __init tcpv6_offload_init(void) | ||
| 93 | { | ||
| 94 | return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP); | ||
| 95 | } | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index fc9997260a6b..dfaa29b8b293 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -1343,103 +1343,9 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1343 | } | 1343 | } |
| 1344 | #endif | 1344 | #endif |
| 1345 | 1345 | ||
| 1346 | static int udp6_ufo_send_check(struct sk_buff *skb) | ||
| 1347 | { | ||
| 1348 | const struct ipv6hdr *ipv6h; | ||
| 1349 | struct udphdr *uh; | ||
| 1350 | |||
| 1351 | if (!pskb_may_pull(skb, sizeof(*uh))) | ||
| 1352 | return -EINVAL; | ||
| 1353 | |||
| 1354 | ipv6h = ipv6_hdr(skb); | ||
| 1355 | uh = udp_hdr(skb); | ||
| 1356 | |||
| 1357 | uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 1358 | IPPROTO_UDP, 0); | ||
| 1359 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
| 1360 | skb->csum_offset = offsetof(struct udphdr, check); | ||
| 1361 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 1362 | return 0; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | ||
| 1366 | netdev_features_t features) | ||
| 1367 | { | ||
| 1368 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 1369 | unsigned int mss; | ||
| 1370 | unsigned int unfrag_ip6hlen, unfrag_len; | ||
| 1371 | struct frag_hdr *fptr; | ||
| 1372 | u8 *mac_start, *prevhdr; | ||
| 1373 | u8 nexthdr; | ||
| 1374 | u8 frag_hdr_sz = sizeof(struct frag_hdr); | ||
| 1375 | int offset; | ||
| 1376 | __wsum csum; | ||
| 1377 | |||
| 1378 | mss = skb_shinfo(skb)->gso_size; | ||
| 1379 | if (unlikely(skb->len <= mss)) | ||
| 1380 | goto out; | ||
| 1381 | |||
| 1382 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { | ||
| 1383 | /* Packet is from an untrusted source, reset gso_segs. */ | ||
| 1384 | int type = skb_shinfo(skb)->gso_type; | ||
| 1385 | |||
| 1386 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || | ||
| 1387 | !(type & (SKB_GSO_UDP)))) | ||
| 1388 | goto out; | ||
| 1389 | |||
| 1390 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | ||
| 1391 | |||
| 1392 | segs = NULL; | ||
| 1393 | goto out; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | ||
| 1397 | * do checksum of UDP packets sent as multiple IP fragments. | ||
| 1398 | */ | ||
| 1399 | offset = skb_checksum_start_offset(skb); | ||
| 1400 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
| 1401 | offset += skb->csum_offset; | ||
| 1402 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
| 1403 | skb->ip_summed = CHECKSUM_NONE; | ||
| 1404 | |||
| 1405 | /* Check if there is enough headroom to insert fragment header. */ | ||
| 1406 | if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) && | ||
| 1407 | pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) | ||
| 1408 | goto out; | ||
| 1409 | |||
| 1410 | /* Find the unfragmentable header and shift it left by frag_hdr_sz | ||
| 1411 | * bytes to insert fragment header. | ||
| 1412 | */ | ||
| 1413 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 1414 | nexthdr = *prevhdr; | ||
| 1415 | *prevhdr = NEXTHDR_FRAGMENT; | ||
| 1416 | unfrag_len = skb_network_header(skb) - skb_mac_header(skb) + | ||
| 1417 | unfrag_ip6hlen; | ||
| 1418 | mac_start = skb_mac_header(skb); | ||
| 1419 | memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len); | ||
| 1420 | |||
| 1421 | skb->mac_header -= frag_hdr_sz; | ||
| 1422 | skb->network_header -= frag_hdr_sz; | ||
| 1423 | |||
| 1424 | fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); | ||
| 1425 | fptr->nexthdr = nexthdr; | ||
| 1426 | fptr->reserved = 0; | ||
| 1427 | ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb)); | ||
| 1428 | |||
| 1429 | /* Fragment the skb. ipv6 header and the remaining fields of the | ||
| 1430 | * fragment header are updated in ipv6_gso_segment() | ||
| 1431 | */ | ||
| 1432 | segs = skb_segment(skb, features); | ||
| 1433 | |||
| 1434 | out: | ||
| 1435 | return segs; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | static const struct inet6_protocol udpv6_protocol = { | 1346 | static const struct inet6_protocol udpv6_protocol = { |
| 1439 | .handler = udpv6_rcv, | 1347 | .handler = udpv6_rcv, |
| 1440 | .err_handler = udpv6_err, | 1348 | .err_handler = udpv6_err, |
| 1441 | .gso_send_check = udp6_ufo_send_check, | ||
| 1442 | .gso_segment = udp6_ufo_fragment, | ||
| 1443 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 1349 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
| 1444 | }; | 1350 | }; |
| 1445 | 1351 | ||
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c new file mode 100644 index 000000000000..0c8934a317c2 --- /dev/null +++ b/net/ipv6/udp_offload.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* | ||
| 2 | * IPV6 GSO/GRO offload support | ||
| 3 | * Linux INET6 implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * UDPv6 GSO support | ||
| 11 | */ | ||
| 12 | #include <linux/skbuff.h> | ||
| 13 | #include <net/protocol.h> | ||
| 14 | #include <net/ipv6.h> | ||
| 15 | #include <net/udp.h> | ||
| 16 | #include <net/ip6_checksum.h> | ||
| 17 | #include "ip6_offload.h" | ||
| 18 | |||
| 19 | static int udp6_ufo_send_check(struct sk_buff *skb) | ||
| 20 | { | ||
| 21 | const struct ipv6hdr *ipv6h; | ||
| 22 | struct udphdr *uh; | ||
| 23 | |||
| 24 | if (!pskb_may_pull(skb, sizeof(*uh))) | ||
| 25 | return -EINVAL; | ||
| 26 | |||
| 27 | ipv6h = ipv6_hdr(skb); | ||
| 28 | uh = udp_hdr(skb); | ||
| 29 | |||
| 30 | uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 31 | IPPROTO_UDP, 0); | ||
| 32 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
| 33 | skb->csum_offset = offsetof(struct udphdr, check); | ||
| 34 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | ||
| 39 | netdev_features_t features) | ||
| 40 | { | ||
| 41 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 42 | unsigned int mss; | ||
| 43 | unsigned int unfrag_ip6hlen, unfrag_len; | ||
| 44 | struct frag_hdr *fptr; | ||
| 45 | u8 *mac_start, *prevhdr; | ||
| 46 | u8 nexthdr; | ||
| 47 | u8 frag_hdr_sz = sizeof(struct frag_hdr); | ||
| 48 | int offset; | ||
| 49 | __wsum csum; | ||
| 50 | |||
| 51 | mss = skb_shinfo(skb)->gso_size; | ||
| 52 | if (unlikely(skb->len <= mss)) | ||
| 53 | goto out; | ||
| 54 | |||
| 55 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { | ||
| 56 | /* Packet is from an untrusted source, reset gso_segs. */ | ||
| 57 | int type = skb_shinfo(skb)->gso_type; | ||
| 58 | |||
| 59 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || | ||
| 60 | !(type & (SKB_GSO_UDP)))) | ||
| 61 | goto out; | ||
| 62 | |||
| 63 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | ||
| 64 | |||
| 65 | segs = NULL; | ||
| 66 | goto out; | ||
| 67 | } | ||
| 68 | |||
| 69 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | ||
| 70 | * do checksum of UDP packets sent as multiple IP fragments. | ||
| 71 | */ | ||
| 72 | offset = skb_checksum_start_offset(skb); | ||
| 73 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
| 74 | offset += skb->csum_offset; | ||
| 75 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
| 76 | skb->ip_summed = CHECKSUM_NONE; | ||
| 77 | |||
| 78 | /* Check if there is enough headroom to insert fragment header. */ | ||
| 79 | if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) && | ||
| 80 | pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) | ||
| 81 | goto out; | ||
| 82 | |||
| 83 | /* Find the unfragmentable header and shift it left by frag_hdr_sz | ||
| 84 | * bytes to insert fragment header. | ||
| 85 | */ | ||
| 86 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 87 | nexthdr = *prevhdr; | ||
| 88 | *prevhdr = NEXTHDR_FRAGMENT; | ||
| 89 | unfrag_len = skb_network_header(skb) - skb_mac_header(skb) + | ||
| 90 | unfrag_ip6hlen; | ||
| 91 | mac_start = skb_mac_header(skb); | ||
| 92 | memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len); | ||
| 93 | |||
| 94 | skb->mac_header -= frag_hdr_sz; | ||
| 95 | skb->network_header -= frag_hdr_sz; | ||
| 96 | |||
| 97 | fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); | ||
| 98 | fptr->nexthdr = nexthdr; | ||
| 99 | fptr->reserved = 0; | ||
| 100 | ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb)); | ||
| 101 | |||
| 102 | /* Fragment the skb. ipv6 header and the remaining fields of the | ||
| 103 | * fragment header are updated in ipv6_gso_segment() | ||
| 104 | */ | ||
| 105 | segs = skb_segment(skb, features); | ||
| 106 | |||
| 107 | out: | ||
| 108 | return segs; | ||
| 109 | } | ||
| 110 | static const struct net_offload udpv6_offload = { | ||
| 111 | .callbacks = { | ||
| 112 | .gso_send_check = udp6_ufo_send_check, | ||
| 113 | .gso_segment = udp6_ufo_fragment, | ||
| 114 | }, | ||
| 115 | }; | ||
| 116 | |||
| 117 | int __init udp_offload_init(void) | ||
| 118 | { | ||
| 119 | return inet6_add_offload(&udpv6_offload, IPPROTO_UDP); | ||
| 120 | } | ||
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index f8c4c08ffb60..c9844135c9ca 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | #include <net/ip.h> | 20 | #include <net/ip.h> |
| 21 | #include <net/ipv6.h> | 21 | #include <net/ipv6.h> |
| 22 | #include <net/ip6_route.h> | 22 | #include <net/ip6_route.h> |
| 23 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 23 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 24 | #include <net/mip6.h> | 24 | #include <net/mip6.h> |
| 25 | #endif | 25 | #endif |
| 26 | 26 | ||
| @@ -182,7 +182,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
| 182 | fl6->flowi6_proto = nexthdr; | 182 | fl6->flowi6_proto = nexthdr; |
| 183 | return; | 183 | return; |
| 184 | 184 | ||
| 185 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 185 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 186 | case IPPROTO_MH: | 186 | case IPPROTO_MH: |
| 187 | if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) { | 187 | if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) { |
| 188 | struct ip6_mh *mh; | 188 | struct ip6_mh *mh; |
| @@ -327,21 +327,7 @@ static struct ctl_table_header *sysctl_hdr; | |||
| 327 | int __init xfrm6_init(void) | 327 | int __init xfrm6_init(void) |
| 328 | { | 328 | { |
| 329 | int ret; | 329 | int ret; |
| 330 | unsigned int gc_thresh; | 330 | |
| 331 | |||
| 332 | /* | ||
| 333 | * We need a good default value for the xfrm6 gc threshold. | ||
| 334 | * In ipv4 we set it to the route hash table size * 8, which | ||
| 335 | * is half the size of the maximaum route cache for ipv4. It | ||
| 336 | * would be good to do the same thing for v6, except the table is | ||
| 337 | * constructed differently here. Here each table for a net namespace | ||
| 338 | * can have FIB_TABLE_HASHSZ entries, so lets go with the same | ||
| 339 | * computation that we used for ipv4 here. Also, lets keep the initial | ||
| 340 | * gc_thresh to a minimum of 1024, since, the ipv6 route cache defaults | ||
| 341 | * to that as a minimum as well | ||
| 342 | */ | ||
| 343 | gc_thresh = FIB6_TABLE_HASHSZ * 8; | ||
| 344 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; | ||
| 345 | dst_entries_init(&xfrm6_dst_ops); | 331 | dst_entries_init(&xfrm6_dst_ops); |
| 346 | 332 | ||
| 347 | ret = xfrm6_policy_init(); | 333 | ret = xfrm6_policy_init(); |
| @@ -370,7 +356,6 @@ void xfrm6_fini(void) | |||
| 370 | if (sysctl_hdr) | 356 | if (sysctl_hdr) |
| 371 | unregister_net_sysctl_table(sysctl_hdr); | 357 | unregister_net_sysctl_table(sysctl_hdr); |
| 372 | #endif | 358 | #endif |
| 373 | //xfrm6_input_fini(); | ||
| 374 | xfrm6_policy_fini(); | 359 | xfrm6_policy_fini(); |
| 375 | xfrm6_state_fini(); | 360 | xfrm6_state_fini(); |
| 376 | dst_entries_destroy(&xfrm6_dst_ops); | 361 | dst_entries_destroy(&xfrm6_dst_ops); |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index 3f2f7c4ab721..d8c70b8efc24 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
| @@ -101,7 +101,7 @@ static int __xfrm6_state_sort_cmp(void *p) | |||
| 101 | return 1; | 101 | return 1; |
| 102 | else | 102 | else |
| 103 | return 3; | 103 | return 3; |
| 104 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 104 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 105 | case XFRM_MODE_ROUTEOPTIMIZATION: | 105 | case XFRM_MODE_ROUTEOPTIMIZATION: |
| 106 | case XFRM_MODE_IN_TRIGGER: | 106 | case XFRM_MODE_IN_TRIGGER: |
| 107 | return 2; | 107 | return 2; |
| @@ -134,7 +134,7 @@ static int __xfrm6_tmpl_sort_cmp(void *p) | |||
| 134 | switch (v->mode) { | 134 | switch (v->mode) { |
| 135 | case XFRM_MODE_TRANSPORT: | 135 | case XFRM_MODE_TRANSPORT: |
| 136 | return 1; | 136 | return 1; |
| 137 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 137 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
| 138 | case XFRM_MODE_ROUTEOPTIMIZATION: | 138 | case XFRM_MODE_ROUTEOPTIMIZATION: |
| 139 | case XFRM_MODE_IN_TRIGGER: | 139 | case XFRM_MODE_IN_TRIGGER: |
| 140 | return 2; | 140 | return 2; |
