| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * GRE over IPv6 protocol decoder. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Authors: Dmitry Kozlov (xeb@mail.ru) |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | 6 | */ |
|---|
| 12 | 7 | |
|---|
| 13 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 425 | 420 | } |
|---|
| 426 | 421 | |
|---|
| 427 | 422 | |
|---|
| 428 | | -static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
|---|
| 423 | +static int ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
|---|
| 429 | 424 | u8 type, u8 code, int offset, __be32 info) |
|---|
| 430 | 425 | { |
|---|
| 431 | 426 | struct net *net = dev_net(skb->dev); |
|---|
| 432 | | - const struct gre_base_hdr *greh; |
|---|
| 433 | 427 | const struct ipv6hdr *ipv6h; |
|---|
| 434 | | - int grehlen = sizeof(*greh); |
|---|
| 428 | + struct tnl_ptk_info tpi; |
|---|
| 435 | 429 | struct ip6_tnl *t; |
|---|
| 436 | | - int key_off = 0; |
|---|
| 437 | | - __be16 flags; |
|---|
| 438 | | - __be32 key; |
|---|
| 439 | 430 | |
|---|
| 440 | | - if (!pskb_may_pull(skb, offset + grehlen)) |
|---|
| 441 | | - return; |
|---|
| 442 | | - greh = (const struct gre_base_hdr *)(skb->data + offset); |
|---|
| 443 | | - flags = greh->flags; |
|---|
| 444 | | - if (flags & (GRE_VERSION | GRE_ROUTING)) |
|---|
| 445 | | - return; |
|---|
| 446 | | - if (flags & GRE_CSUM) |
|---|
| 447 | | - grehlen += 4; |
|---|
| 448 | | - if (flags & GRE_KEY) { |
|---|
| 449 | | - key_off = grehlen + offset; |
|---|
| 450 | | - grehlen += 4; |
|---|
| 451 | | - } |
|---|
| 431 | + if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IPV6), |
|---|
| 432 | + offset) < 0) |
|---|
| 433 | + return -EINVAL; |
|---|
| 452 | 434 | |
|---|
| 453 | | - if (!pskb_may_pull(skb, offset + grehlen)) |
|---|
| 454 | | - return; |
|---|
| 455 | 435 | ipv6h = (const struct ipv6hdr *)skb->data; |
|---|
| 456 | | - greh = (const struct gre_base_hdr *)(skb->data + offset); |
|---|
| 457 | | - key = key_off ? *(__be32 *)(skb->data + key_off) : 0; |
|---|
| 458 | | - |
|---|
| 459 | 436 | t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, |
|---|
| 460 | | - key, greh->protocol); |
|---|
| 437 | + tpi.key, tpi.proto); |
|---|
| 461 | 438 | if (!t) |
|---|
| 462 | | - return; |
|---|
| 439 | + return -ENOENT; |
|---|
| 463 | 440 | |
|---|
| 464 | 441 | switch (type) { |
|---|
| 465 | | - struct ipv6_tlv_tnl_enc_lim *tel; |
|---|
| 466 | | - __u32 teli; |
|---|
| 467 | 442 | case ICMPV6_DEST_UNREACH: |
|---|
| 468 | 443 | net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n", |
|---|
| 469 | 444 | t->parms.name); |
|---|
| 470 | 445 | if (code != ICMPV6_PORT_UNREACH) |
|---|
| 471 | 446 | break; |
|---|
| 472 | | - return; |
|---|
| 447 | + return 0; |
|---|
| 473 | 448 | case ICMPV6_TIME_EXCEED: |
|---|
| 474 | 449 | if (code == ICMPV6_EXC_HOPLIMIT) { |
|---|
| 475 | 450 | net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n", |
|---|
| 476 | 451 | t->parms.name); |
|---|
| 477 | 452 | break; |
|---|
| 478 | 453 | } |
|---|
| 479 | | - return; |
|---|
| 480 | | - case ICMPV6_PARAMPROB: |
|---|
| 454 | + return 0; |
|---|
| 455 | + case ICMPV6_PARAMPROB: { |
|---|
| 456 | + struct ipv6_tlv_tnl_enc_lim *tel; |
|---|
| 457 | + __u32 teli; |
|---|
| 458 | + |
|---|
| 481 | 459 | teli = 0; |
|---|
| 482 | 460 | if (code == ICMPV6_HDR_FIELD) |
|---|
| 483 | 461 | teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); |
|---|
| .. | .. |
|---|
| 492 | 470 | net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n", |
|---|
| 493 | 471 | t->parms.name); |
|---|
| 494 | 472 | } |
|---|
| 495 | | - return; |
|---|
| 473 | + return 0; |
|---|
| 474 | + } |
|---|
| 496 | 475 | case ICMPV6_PKT_TOOBIG: |
|---|
| 497 | 476 | ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); |
|---|
| 498 | | - return; |
|---|
| 477 | + return 0; |
|---|
| 499 | 478 | case NDISC_REDIRECT: |
|---|
| 500 | 479 | ip6_redirect(skb, net, skb->dev->ifindex, 0, |
|---|
| 501 | 480 | sock_net_uid(net, NULL)); |
|---|
| 502 | | - return; |
|---|
| 481 | + return 0; |
|---|
| 503 | 482 | } |
|---|
| 504 | 483 | |
|---|
| 505 | 484 | if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) |
|---|
| .. | .. |
|---|
| 507 | 486 | else |
|---|
| 508 | 487 | t->err_count = 1; |
|---|
| 509 | 488 | t->err_time = jiffies; |
|---|
| 489 | + |
|---|
| 490 | + return 0; |
|---|
| 510 | 491 | } |
|---|
| 511 | 492 | |
|---|
| 512 | 493 | static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) |
|---|
| .. | .. |
|---|
| 542 | 523 | return PACKET_REJECT; |
|---|
| 543 | 524 | } |
|---|
| 544 | 525 | |
|---|
| 545 | | -static int ip6erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, |
|---|
| 526 | +static int ip6erspan_rcv(struct sk_buff *skb, |
|---|
| 527 | + struct tnl_ptk_info *tpi, |
|---|
| 546 | 528 | int gre_hdr_len) |
|---|
| 547 | 529 | { |
|---|
| 548 | 530 | struct erspan_base_hdr *ershdr; |
|---|
| .. | .. |
|---|
| 695 | 677 | |
|---|
| 696 | 678 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
|---|
| 697 | 679 | if (tel->encap_limit == 0) { |
|---|
| 698 | | - icmpv6_send(skb, ICMPV6_PARAMPROB, |
|---|
| 699 | | - ICMPV6_HDR_FIELD, offset + 2); |
|---|
| 680 | + icmpv6_ndo_send(skb, ICMPV6_PARAMPROB, |
|---|
| 681 | + ICMPV6_HDR_FIELD, offset + 2); |
|---|
| 700 | 682 | return -1; |
|---|
| 701 | 683 | } |
|---|
| 702 | 684 | *encap_limit = tel->encap_limit - 1; |
|---|
| .. | .. |
|---|
| 724 | 706 | return 0; |
|---|
| 725 | 707 | } |
|---|
| 726 | 708 | |
|---|
| 709 | +static struct ip_tunnel_info *skb_tunnel_info_txcheck(struct sk_buff *skb) |
|---|
| 710 | +{ |
|---|
| 711 | + struct ip_tunnel_info *tun_info; |
|---|
| 712 | + |
|---|
| 713 | + tun_info = skb_tunnel_info(skb); |
|---|
| 714 | + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))) |
|---|
| 715 | + return ERR_PTR(-EINVAL); |
|---|
| 716 | + |
|---|
| 717 | + return tun_info; |
|---|
| 718 | +} |
|---|
| 719 | + |
|---|
| 727 | 720 | static netdev_tx_t __gre6_xmit(struct sk_buff *skb, |
|---|
| 728 | 721 | struct net_device *dev, __u8 dsfield, |
|---|
| 729 | 722 | struct flowi6 *fl6, int encap_limit, |
|---|
| .. | .. |
|---|
| 731 | 724 | { |
|---|
| 732 | 725 | struct ip6_tnl *tunnel = netdev_priv(dev); |
|---|
| 733 | 726 | __be16 protocol; |
|---|
| 727 | + __be16 flags; |
|---|
| 734 | 728 | |
|---|
| 735 | 729 | if (dev->type == ARPHRD_ETHER) |
|---|
| 736 | 730 | IPCB(skb)->flags = 0; |
|---|
| .. | .. |
|---|
| 740 | 734 | else |
|---|
| 741 | 735 | fl6->daddr = tunnel->parms.raddr; |
|---|
| 742 | 736 | |
|---|
| 743 | | - if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen)) |
|---|
| 744 | | - return -ENOMEM; |
|---|
| 745 | | - |
|---|
| 746 | 737 | /* Push GRE header. */ |
|---|
| 747 | 738 | protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto; |
|---|
| 748 | 739 | |
|---|
| 749 | 740 | if (tunnel->parms.collect_md) { |
|---|
| 750 | 741 | struct ip_tunnel_info *tun_info; |
|---|
| 751 | 742 | const struct ip_tunnel_key *key; |
|---|
| 752 | | - __be16 flags; |
|---|
| 743 | + int tun_hlen; |
|---|
| 753 | 744 | |
|---|
| 754 | | - tun_info = skb_tunnel_info(skb); |
|---|
| 755 | | - if (unlikely(!tun_info || |
|---|
| 756 | | - !(tun_info->mode & IP_TUNNEL_INFO_TX) || |
|---|
| 757 | | - ip_tunnel_info_af(tun_info) != AF_INET6)) |
|---|
| 745 | + tun_info = skb_tunnel_info_txcheck(skb); |
|---|
| 746 | + if (IS_ERR(tun_info) || |
|---|
| 747 | + unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) |
|---|
| 758 | 748 | return -EINVAL; |
|---|
| 759 | 749 | |
|---|
| 760 | 750 | key = &tun_info->key; |
|---|
| .. | .. |
|---|
| 763 | 753 | fl6->daddr = key->u.ipv6.dst; |
|---|
| 764 | 754 | fl6->flowlabel = key->label; |
|---|
| 765 | 755 | fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL); |
|---|
| 756 | + fl6->fl6_gre_key = tunnel_id_to_key32(key->tun_id); |
|---|
| 766 | 757 | |
|---|
| 767 | 758 | dsfield = key->tos; |
|---|
| 768 | 759 | flags = key->tun_flags & |
|---|
| 769 | 760 | (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ); |
|---|
| 770 | | - tunnel->tun_hlen = gre_calc_hlen(flags); |
|---|
| 761 | + tun_hlen = gre_calc_hlen(flags); |
|---|
| 771 | 762 | |
|---|
| 772 | | - gre_build_header(skb, tunnel->tun_hlen, |
|---|
| 763 | + if (skb_cow_head(skb, dev->needed_headroom ?: tun_hlen + tunnel->encap_hlen)) |
|---|
| 764 | + return -ENOMEM; |
|---|
| 765 | + |
|---|
| 766 | + gre_build_header(skb, tun_hlen, |
|---|
| 773 | 767 | flags, protocol, |
|---|
| 774 | 768 | tunnel_id_to_key32(tun_info->key.tun_id), |
|---|
| 775 | | - (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) |
|---|
| 769 | + (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) |
|---|
| 776 | 770 | : 0); |
|---|
| 777 | 771 | |
|---|
| 778 | 772 | } else { |
|---|
| 779 | | - if (tunnel->parms.o_flags & TUNNEL_SEQ) |
|---|
| 780 | | - tunnel->o_seqno++; |
|---|
| 773 | + if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen)) |
|---|
| 774 | + return -ENOMEM; |
|---|
| 781 | 775 | |
|---|
| 782 | | - gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, |
|---|
| 776 | + flags = tunnel->parms.o_flags; |
|---|
| 777 | + |
|---|
| 778 | + gre_build_header(skb, tunnel->tun_hlen, flags, |
|---|
| 783 | 779 | protocol, tunnel->parms.o_key, |
|---|
| 784 | | - htonl(tunnel->o_seqno)); |
|---|
| 780 | + (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) |
|---|
| 781 | + : 0); |
|---|
| 785 | 782 | } |
|---|
| 786 | 783 | |
|---|
| 787 | 784 | return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu, |
|---|
| .. | .. |
|---|
| 812 | 809 | if (err != 0) { |
|---|
| 813 | 810 | /* XXX: send ICMP error even if DF is not set. */ |
|---|
| 814 | 811 | if (err == -EMSGSIZE) |
|---|
| 815 | | - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
|---|
| 816 | | - htonl(mtu)); |
|---|
| 812 | + icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
|---|
| 813 | + htonl(mtu)); |
|---|
| 817 | 814 | return -1; |
|---|
| 818 | 815 | } |
|---|
| 819 | 816 | |
|---|
| .. | .. |
|---|
| 844 | 841 | &mtu, skb->protocol); |
|---|
| 845 | 842 | if (err != 0) { |
|---|
| 846 | 843 | if (err == -EMSGSIZE) |
|---|
| 847 | | - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 844 | + icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 848 | 845 | return -1; |
|---|
| 849 | 846 | } |
|---|
| 850 | 847 | |
|---|
| .. | .. |
|---|
| 925 | 922 | return NETDEV_TX_OK; |
|---|
| 926 | 923 | |
|---|
| 927 | 924 | tx_err: |
|---|
| 928 | | - stats->tx_errors++; |
|---|
| 925 | + if (!t->parms.collect_md || !IS_ERR(skb_tunnel_info_txcheck(skb))) |
|---|
| 926 | + stats->tx_errors++; |
|---|
| 929 | 927 | stats->tx_dropped++; |
|---|
| 930 | 928 | kfree_skb(skb); |
|---|
| 931 | 929 | return NETDEV_TX_OK; |
|---|
| .. | .. |
|---|
| 934 | 932 | static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, |
|---|
| 935 | 933 | struct net_device *dev) |
|---|
| 936 | 934 | { |
|---|
| 935 | + struct ip_tunnel_info *tun_info = NULL; |
|---|
| 937 | 936 | struct ip6_tnl *t = netdev_priv(dev); |
|---|
| 938 | 937 | struct dst_entry *dst = skb_dst(skb); |
|---|
| 939 | 938 | struct net_device_stats *stats; |
|---|
| .. | .. |
|---|
| 945 | 944 | __be16 proto; |
|---|
| 946 | 945 | __u32 mtu; |
|---|
| 947 | 946 | int nhoff; |
|---|
| 948 | | - int thoff; |
|---|
| 949 | 947 | |
|---|
| 950 | 948 | if (!pskb_inet_may_pull(skb)) |
|---|
| 951 | 949 | goto tx_err; |
|---|
| .. | .. |
|---|
| 957 | 955 | goto tx_err; |
|---|
| 958 | 956 | |
|---|
| 959 | 957 | if (skb->len > dev->mtu + dev->hard_header_len) { |
|---|
| 960 | | - pskb_trim(skb, dev->mtu + dev->hard_header_len); |
|---|
| 958 | + if (pskb_trim(skb, dev->mtu + dev->hard_header_len)) |
|---|
| 959 | + goto tx_err; |
|---|
| 961 | 960 | truncate = true; |
|---|
| 962 | 961 | } |
|---|
| 963 | 962 | |
|---|
| 964 | | - nhoff = skb_network_header(skb) - skb_mac_header(skb); |
|---|
| 963 | + nhoff = skb_network_offset(skb); |
|---|
| 965 | 964 | if (skb->protocol == htons(ETH_P_IP) && |
|---|
| 966 | 965 | (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff)) |
|---|
| 967 | 966 | truncate = true; |
|---|
| 968 | 967 | |
|---|
| 969 | | - thoff = skb_transport_header(skb) - skb_mac_header(skb); |
|---|
| 970 | | - if (skb->protocol == htons(ETH_P_IPV6) && |
|---|
| 971 | | - (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff)) |
|---|
| 972 | | - truncate = true; |
|---|
| 968 | + if (skb->protocol == htons(ETH_P_IPV6)) { |
|---|
| 969 | + int thoff; |
|---|
| 970 | + |
|---|
| 971 | + if (skb_transport_header_was_set(skb)) |
|---|
| 972 | + thoff = skb_transport_offset(skb); |
|---|
| 973 | + else |
|---|
| 974 | + thoff = nhoff + sizeof(struct ipv6hdr); |
|---|
| 975 | + if (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff) |
|---|
| 976 | + truncate = true; |
|---|
| 977 | + } |
|---|
| 973 | 978 | |
|---|
| 974 | 979 | if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen)) |
|---|
| 975 | 980 | goto tx_err; |
|---|
| .. | .. |
|---|
| 981 | 986 | * for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}. |
|---|
| 982 | 987 | */ |
|---|
| 983 | 988 | if (t->parms.collect_md) { |
|---|
| 984 | | - struct ip_tunnel_info *tun_info; |
|---|
| 985 | 989 | const struct ip_tunnel_key *key; |
|---|
| 986 | 990 | struct erspan_metadata *md; |
|---|
| 987 | 991 | __be32 tun_id; |
|---|
| 988 | 992 | |
|---|
| 989 | | - tun_info = skb_tunnel_info(skb); |
|---|
| 990 | | - if (unlikely(!tun_info || |
|---|
| 991 | | - !(tun_info->mode & IP_TUNNEL_INFO_TX) || |
|---|
| 992 | | - ip_tunnel_info_af(tun_info) != AF_INET6)) |
|---|
| 993 | + tun_info = skb_tunnel_info_txcheck(skb); |
|---|
| 994 | + if (IS_ERR(tun_info) || |
|---|
| 995 | + unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) |
|---|
| 993 | 996 | goto tx_err; |
|---|
| 994 | 997 | |
|---|
| 995 | 998 | key = &tun_info->key; |
|---|
| .. | .. |
|---|
| 998 | 1001 | fl6.daddr = key->u.ipv6.dst; |
|---|
| 999 | 1002 | fl6.flowlabel = key->label; |
|---|
| 1000 | 1003 | fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); |
|---|
| 1004 | + fl6.fl6_gre_key = tunnel_id_to_key32(key->tun_id); |
|---|
| 1001 | 1005 | |
|---|
| 1002 | 1006 | dsfield = key->tos; |
|---|
| 1003 | 1007 | if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT)) |
|---|
| .. | .. |
|---|
| 1012 | 1016 | ntohl(tun_id), |
|---|
| 1013 | 1017 | ntohl(md->u.index), truncate, |
|---|
| 1014 | 1018 | false); |
|---|
| 1019 | + proto = htons(ETH_P_ERSPAN); |
|---|
| 1015 | 1020 | } else if (md->version == 2) { |
|---|
| 1016 | 1021 | erspan_build_header_v2(skb, |
|---|
| 1017 | 1022 | ntohl(tun_id), |
|---|
| 1018 | 1023 | md->u.md2.dir, |
|---|
| 1019 | 1024 | get_hwid(&md->u.md2), |
|---|
| 1020 | 1025 | truncate, false); |
|---|
| 1026 | + proto = htons(ETH_P_ERSPAN2); |
|---|
| 1021 | 1027 | } else { |
|---|
| 1022 | 1028 | goto tx_err; |
|---|
| 1023 | 1029 | } |
|---|
| .. | .. |
|---|
| 1040 | 1046 | break; |
|---|
| 1041 | 1047 | } |
|---|
| 1042 | 1048 | |
|---|
| 1043 | | - if (t->parms.erspan_ver == 1) |
|---|
| 1049 | + if (t->parms.erspan_ver == 1) { |
|---|
| 1044 | 1050 | erspan_build_header(skb, ntohl(t->parms.o_key), |
|---|
| 1045 | 1051 | t->parms.index, |
|---|
| 1046 | 1052 | truncate, false); |
|---|
| 1047 | | - else if (t->parms.erspan_ver == 2) |
|---|
| 1053 | + proto = htons(ETH_P_ERSPAN); |
|---|
| 1054 | + } else if (t->parms.erspan_ver == 2) { |
|---|
| 1048 | 1055 | erspan_build_header_v2(skb, ntohl(t->parms.o_key), |
|---|
| 1049 | 1056 | t->parms.dir, |
|---|
| 1050 | 1057 | t->parms.hwid, |
|---|
| 1051 | 1058 | truncate, false); |
|---|
| 1052 | | - else |
|---|
| 1059 | + proto = htons(ETH_P_ERSPAN2); |
|---|
| 1060 | + } else { |
|---|
| 1053 | 1061 | goto tx_err; |
|---|
| 1062 | + } |
|---|
| 1054 | 1063 | |
|---|
| 1055 | 1064 | fl6.daddr = t->parms.raddr; |
|---|
| 1056 | 1065 | } |
|---|
| 1057 | 1066 | |
|---|
| 1058 | 1067 | /* Push GRE header. */ |
|---|
| 1059 | | - proto = (t->parms.erspan_ver == 1) ? htons(ETH_P_ERSPAN) |
|---|
| 1060 | | - : htons(ETH_P_ERSPAN2); |
|---|
| 1061 | | - gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(t->o_seqno++)); |
|---|
| 1068 | + gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(atomic_fetch_inc(&t->o_seqno))); |
|---|
| 1062 | 1069 | |
|---|
| 1063 | 1070 | /* TooBig packet may have updated dst->dev's mtu */ |
|---|
| 1064 | 1071 | if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) |
|---|
| .. | .. |
|---|
| 1070 | 1077 | /* XXX: send ICMP error even if DF is not set. */ |
|---|
| 1071 | 1078 | if (err == -EMSGSIZE) { |
|---|
| 1072 | 1079 | if (skb->protocol == htons(ETH_P_IP)) |
|---|
| 1073 | | - icmp_send(skb, ICMP_DEST_UNREACH, |
|---|
| 1074 | | - ICMP_FRAG_NEEDED, htonl(mtu)); |
|---|
| 1080 | + icmp_ndo_send(skb, ICMP_DEST_UNREACH, |
|---|
| 1081 | + ICMP_FRAG_NEEDED, htonl(mtu)); |
|---|
| 1075 | 1082 | else |
|---|
| 1076 | | - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 1083 | + icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 1077 | 1084 | } |
|---|
| 1078 | 1085 | |
|---|
| 1079 | 1086 | goto tx_err; |
|---|
| .. | .. |
|---|
| 1082 | 1089 | |
|---|
| 1083 | 1090 | tx_err: |
|---|
| 1084 | 1091 | stats = &t->dev->stats; |
|---|
| 1085 | | - stats->tx_errors++; |
|---|
| 1092 | + if (!IS_ERR(tun_info)) |
|---|
| 1093 | + stats->tx_errors++; |
|---|
| 1086 | 1094 | stats->tx_dropped++; |
|---|
| 1087 | 1095 | kfree_skb(skb); |
|---|
| 1088 | 1096 | return NETDEV_TX_OK; |
|---|
| .. | .. |
|---|
| 1105 | 1113 | fl6->flowi6_oif = p->link; |
|---|
| 1106 | 1114 | fl6->flowlabel = 0; |
|---|
| 1107 | 1115 | fl6->flowi6_proto = IPPROTO_GRE; |
|---|
| 1116 | + fl6->fl6_gre_key = t->parms.o_key; |
|---|
| 1108 | 1117 | |
|---|
| 1109 | 1118 | if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) |
|---|
| 1110 | 1119 | fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; |
|---|
| .. | .. |
|---|
| 1148 | 1157 | dev->needed_headroom = dst_len; |
|---|
| 1149 | 1158 | |
|---|
| 1150 | 1159 | if (set_mtu) { |
|---|
| 1151 | | - dev->mtu = rt->dst.dev->mtu - t_hlen; |
|---|
| 1152 | | - if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
|---|
| 1153 | | - dev->mtu -= 8; |
|---|
| 1154 | | - if (dev->type == ARPHRD_ETHER) |
|---|
| 1155 | | - dev->mtu -= ETH_HLEN; |
|---|
| 1160 | + int mtu = rt->dst.dev->mtu - t_hlen; |
|---|
| 1156 | 1161 | |
|---|
| 1157 | | - if (dev->mtu < IPV6_MIN_MTU) |
|---|
| 1158 | | - dev->mtu = IPV6_MIN_MTU; |
|---|
| 1162 | + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
|---|
| 1163 | + mtu -= 8; |
|---|
| 1164 | + if (dev->type == ARPHRD_ETHER) |
|---|
| 1165 | + mtu -= ETH_HLEN; |
|---|
| 1166 | + |
|---|
| 1167 | + if (mtu < IPV6_MIN_MTU) |
|---|
| 1168 | + mtu = IPV6_MIN_MTU; |
|---|
| 1169 | + WRITE_ONCE(dev->mtu, mtu); |
|---|
| 1159 | 1170 | } |
|---|
| 1160 | 1171 | } |
|---|
| 1161 | 1172 | ip6_rt_put(rt); |
|---|
| .. | .. |
|---|
| 1550 | 1561 | static struct inet6_protocol ip6gre_protocol __read_mostly = { |
|---|
| 1551 | 1562 | .handler = gre_rcv, |
|---|
| 1552 | 1563 | .err_handler = ip6gre_err, |
|---|
| 1553 | | - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
|---|
| 1564 | + .flags = INET6_PROTO_FINAL, |
|---|
| 1554 | 1565 | }; |
|---|
| 1555 | 1566 | |
|---|
| 1556 | 1567 | static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head) |
|---|
| .. | .. |
|---|
| 1931 | 1942 | netif_keep_dst(dev); |
|---|
| 1932 | 1943 | } |
|---|
| 1933 | 1944 | |
|---|
| 1934 | | -bool is_ip6gretap_dev(const struct net_device *dev) |
|---|
| 1935 | | -{ |
|---|
| 1936 | | - return dev->netdev_ops == &ip6gre_tap_netdev_ops; |
|---|
| 1937 | | -} |
|---|
| 1938 | | -EXPORT_SYMBOL_GPL(is_ip6gretap_dev); |
|---|
| 1939 | | - |
|---|
| 1940 | 1945 | static bool ip6gre_netlink_encap_parms(struct nlattr *data[], |
|---|
| 1941 | 1946 | struct ip_tunnel_encap *ipencap) |
|---|
| 1942 | 1947 | { |
|---|
| .. | .. |
|---|
| 2205 | 2210 | [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, |
|---|
| 2206 | 2211 | [IFLA_GRE_IKEY] = { .type = NLA_U32 }, |
|---|
| 2207 | 2212 | [IFLA_GRE_OKEY] = { .type = NLA_U32 }, |
|---|
| 2208 | | - [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct ipv6hdr, saddr) }, |
|---|
| 2209 | | - [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct ipv6hdr, daddr) }, |
|---|
| 2213 | + [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct ipv6hdr, saddr) }, |
|---|
| 2214 | + [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct ipv6hdr, daddr) }, |
|---|
| 2210 | 2215 | [IFLA_GRE_TTL] = { .type = NLA_U8 }, |
|---|
| 2211 | 2216 | [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, |
|---|
| 2212 | 2217 | [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, |
|---|