| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Linux NET3: IP/IP protocol decoder modified to support |
|---|
| 3 | 4 | * virtual tunnel interface |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Authors: |
|---|
| 6 | 7 | * Saurabh Mohan (saurabh.mohan@vyatta.com) 05/07/2012 |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or |
|---|
| 9 | | - * modify it under the terms of the GNU General Public License |
|---|
| 10 | | - * as published by the Free Software Foundation; either version |
|---|
| 11 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 12 | | - * |
|---|
| 13 | 8 | */ |
|---|
| 14 | 9 | |
|---|
| 15 | 10 | /* |
|---|
| .. | .. |
|---|
| 96 | 91 | return vti_rcv(skb, 0, false); |
|---|
| 97 | 92 | } |
|---|
| 98 | 93 | |
|---|
| 99 | | -static int vti_rcv_tunnel(struct sk_buff *skb) |
|---|
| 100 | | -{ |
|---|
| 101 | | - struct ip_tunnel_net *itn = net_generic(dev_net(skb->dev), vti_net_id); |
|---|
| 102 | | - const struct iphdr *iph = ip_hdr(skb); |
|---|
| 103 | | - struct ip_tunnel *tunnel; |
|---|
| 104 | | - |
|---|
| 105 | | - tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
|---|
| 106 | | - iph->saddr, iph->daddr, 0); |
|---|
| 107 | | - if (tunnel) { |
|---|
| 108 | | - struct tnl_ptk_info tpi = { |
|---|
| 109 | | - .proto = htons(ETH_P_IP), |
|---|
| 110 | | - }; |
|---|
| 111 | | - |
|---|
| 112 | | - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) |
|---|
| 113 | | - goto drop; |
|---|
| 114 | | - if (iptunnel_pull_header(skb, 0, tpi.proto, false)) |
|---|
| 115 | | - goto drop; |
|---|
| 116 | | - return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, false); |
|---|
| 117 | | - } |
|---|
| 118 | | - |
|---|
| 119 | | - return -EINVAL; |
|---|
| 120 | | -drop: |
|---|
| 121 | | - kfree_skb(skb); |
|---|
| 122 | | - return 0; |
|---|
| 123 | | -} |
|---|
| 124 | | - |
|---|
| 125 | 94 | static int vti_rcv_cb(struct sk_buff *skb, int err) |
|---|
| 126 | 95 | { |
|---|
| 127 | 96 | unsigned short family; |
|---|
| 128 | 97 | struct net_device *dev; |
|---|
| 129 | | - struct pcpu_sw_netstats *tstats; |
|---|
| 130 | 98 | struct xfrm_state *x; |
|---|
| 131 | | - struct xfrm_mode *inner_mode; |
|---|
| 99 | + const struct xfrm_mode *inner_mode; |
|---|
| 132 | 100 | struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4; |
|---|
| 133 | 101 | u32 orig_mark = skb->mark; |
|---|
| 134 | 102 | int ret; |
|---|
| .. | .. |
|---|
| 147 | 115 | |
|---|
| 148 | 116 | x = xfrm_input_state(skb); |
|---|
| 149 | 117 | |
|---|
| 150 | | - inner_mode = x->inner_mode; |
|---|
| 118 | + inner_mode = &x->inner_mode; |
|---|
| 151 | 119 | |
|---|
| 152 | 120 | if (x->sel.family == AF_UNSPEC) { |
|---|
| 153 | 121 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); |
|---|
| .. | .. |
|---|
| 158 | 126 | } |
|---|
| 159 | 127 | } |
|---|
| 160 | 128 | |
|---|
| 161 | | - family = inner_mode->afinfo->family; |
|---|
| 129 | + family = inner_mode->family; |
|---|
| 162 | 130 | |
|---|
| 163 | 131 | skb->mark = be32_to_cpu(tunnel->parms.i_key); |
|---|
| 164 | 132 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); |
|---|
| .. | .. |
|---|
| 169 | 137 | |
|---|
| 170 | 138 | skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev))); |
|---|
| 171 | 139 | skb->dev = dev; |
|---|
| 172 | | - |
|---|
| 173 | | - tstats = this_cpu_ptr(dev->tstats); |
|---|
| 174 | | - |
|---|
| 175 | | - u64_stats_update_begin(&tstats->syncp); |
|---|
| 176 | | - tstats->rx_packets++; |
|---|
| 177 | | - tstats->rx_bytes += skb->len; |
|---|
| 178 | | - u64_stats_update_end(&tstats->syncp); |
|---|
| 140 | + dev_sw_netstats_rx_add(dev, skb->len); |
|---|
| 179 | 141 | |
|---|
| 180 | 142 | return 0; |
|---|
| 181 | 143 | } |
|---|
| .. | .. |
|---|
| 249 | 211 | } |
|---|
| 250 | 212 | |
|---|
| 251 | 213 | dst_hold(dst); |
|---|
| 252 | | - dst = xfrm_lookup(tunnel->net, dst, fl, NULL, 0); |
|---|
| 214 | + dst = xfrm_lookup_route(tunnel->net, dst, fl, NULL, 0); |
|---|
| 253 | 215 | if (IS_ERR(dst)) { |
|---|
| 254 | 216 | dev->stats.tx_carrier_errors++; |
|---|
| 255 | 217 | goto tx_error_icmp; |
|---|
| 256 | 218 | } |
|---|
| 219 | + |
|---|
| 220 | + if (dst->flags & DST_XFRM_QUEUE) |
|---|
| 221 | + goto queued; |
|---|
| 257 | 222 | |
|---|
| 258 | 223 | if (!vti_state_check(dst->xfrm, parms->iph.daddr, parms->iph.saddr)) { |
|---|
| 259 | 224 | dev->stats.tx_carrier_errors++; |
|---|
| .. | .. |
|---|
| 273 | 238 | if (skb->len > mtu) { |
|---|
| 274 | 239 | skb_dst_update_pmtu_no_confirm(skb, mtu); |
|---|
| 275 | 240 | if (skb->protocol == htons(ETH_P_IP)) { |
|---|
| 276 | | - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
|---|
| 277 | | - htonl(mtu)); |
|---|
| 241 | + icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
|---|
| 242 | + htonl(mtu)); |
|---|
| 278 | 243 | } else { |
|---|
| 279 | 244 | if (mtu < IPV6_MIN_MTU) |
|---|
| 280 | 245 | mtu = IPV6_MIN_MTU; |
|---|
| 281 | 246 | |
|---|
| 282 | | - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 247 | + icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
|---|
| 283 | 248 | } |
|---|
| 284 | 249 | |
|---|
| 285 | 250 | dst_release(dst); |
|---|
| 286 | 251 | goto tx_error; |
|---|
| 287 | 252 | } |
|---|
| 288 | 253 | |
|---|
| 254 | +queued: |
|---|
| 289 | 255 | skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev))); |
|---|
| 290 | 256 | skb_dst_set(skb, dst); |
|---|
| 291 | 257 | skb->dev = skb_dst(skb)->dev; |
|---|
| .. | .. |
|---|
| 319 | 285 | |
|---|
| 320 | 286 | switch (skb->protocol) { |
|---|
| 321 | 287 | case htons(ETH_P_IP): |
|---|
| 322 | | - xfrm_decode_session(skb, &fl, AF_INET); |
|---|
| 323 | 288 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
|---|
| 289 | + xfrm_decode_session(skb, &fl, AF_INET); |
|---|
| 324 | 290 | break; |
|---|
| 325 | 291 | case htons(ETH_P_IPV6): |
|---|
| 326 | | - xfrm_decode_session(skb, &fl, AF_INET6); |
|---|
| 327 | 292 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); |
|---|
| 293 | + xfrm_decode_session(skb, &fl, AF_INET6); |
|---|
| 328 | 294 | break; |
|---|
| 329 | 295 | default: |
|---|
| 330 | 296 | goto tx_err; |
|---|
| .. | .. |
|---|
| 395 | 361 | return 0; |
|---|
| 396 | 362 | |
|---|
| 397 | 363 | if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) |
|---|
| 398 | | - ipv4_update_pmtu(skb, net, info, 0, 0, protocol, 0); |
|---|
| 364 | + ipv4_update_pmtu(skb, net, info, 0, protocol); |
|---|
| 399 | 365 | else |
|---|
| 400 | | - ipv4_redirect(skb, net, 0, 0, protocol, 0); |
|---|
| 366 | + ipv4_redirect(skb, net, 0, protocol); |
|---|
| 401 | 367 | xfrm_state_put(x); |
|---|
| 402 | 368 | |
|---|
| 403 | 369 | return 0; |
|---|
| 404 | 370 | } |
|---|
| 405 | 371 | |
|---|
| 406 | 372 | static int |
|---|
| 407 | | -vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
|---|
| 373 | +vti_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) |
|---|
| 408 | 374 | { |
|---|
| 409 | 375 | int err = 0; |
|---|
| 410 | | - struct ip_tunnel_parm p; |
|---|
| 411 | | - |
|---|
| 412 | | - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
|---|
| 413 | | - return -EFAULT; |
|---|
| 414 | 376 | |
|---|
| 415 | 377 | if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { |
|---|
| 416 | | - if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || |
|---|
| 417 | | - p.iph.ihl != 5) |
|---|
| 378 | + if (p->iph.version != 4 || p->iph.protocol != IPPROTO_IPIP || |
|---|
| 379 | + p->iph.ihl != 5) |
|---|
| 418 | 380 | return -EINVAL; |
|---|
| 419 | 381 | } |
|---|
| 420 | 382 | |
|---|
| 421 | | - if (!(p.i_flags & GRE_KEY)) |
|---|
| 422 | | - p.i_key = 0; |
|---|
| 423 | | - if (!(p.o_flags & GRE_KEY)) |
|---|
| 424 | | - p.o_key = 0; |
|---|
| 383 | + if (!(p->i_flags & GRE_KEY)) |
|---|
| 384 | + p->i_key = 0; |
|---|
| 385 | + if (!(p->o_flags & GRE_KEY)) |
|---|
| 386 | + p->o_key = 0; |
|---|
| 425 | 387 | |
|---|
| 426 | | - p.i_flags = VTI_ISVTI; |
|---|
| 388 | + p->i_flags = VTI_ISVTI; |
|---|
| 427 | 389 | |
|---|
| 428 | | - err = ip_tunnel_ioctl(dev, &p, cmd); |
|---|
| 390 | + err = ip_tunnel_ctl(dev, p, cmd); |
|---|
| 429 | 391 | if (err) |
|---|
| 430 | 392 | return err; |
|---|
| 431 | 393 | |
|---|
| 432 | 394 | if (cmd != SIOCDELTUNNEL) { |
|---|
| 433 | | - p.i_flags |= GRE_KEY; |
|---|
| 434 | | - p.o_flags |= GRE_KEY; |
|---|
| 395 | + p->i_flags |= GRE_KEY; |
|---|
| 396 | + p->o_flags |= GRE_KEY; |
|---|
| 435 | 397 | } |
|---|
| 436 | | - |
|---|
| 437 | | - if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) |
|---|
| 438 | | - return -EFAULT; |
|---|
| 439 | 398 | return 0; |
|---|
| 440 | 399 | } |
|---|
| 441 | 400 | |
|---|
| .. | .. |
|---|
| 443 | 402 | .ndo_init = vti_tunnel_init, |
|---|
| 444 | 403 | .ndo_uninit = ip_tunnel_uninit, |
|---|
| 445 | 404 | .ndo_start_xmit = vti_tunnel_xmit, |
|---|
| 446 | | - .ndo_do_ioctl = vti_tunnel_ioctl, |
|---|
| 405 | + .ndo_do_ioctl = ip_tunnel_ioctl, |
|---|
| 447 | 406 | .ndo_change_mtu = ip_tunnel_change_mtu, |
|---|
| 448 | 407 | .ndo_get_stats64 = ip_tunnel_get_stats64, |
|---|
| 449 | 408 | .ndo_get_iflink = ip_tunnel_get_iflink, |
|---|
| 409 | + .ndo_tunnel_ctl = vti_tunnel_ctl, |
|---|
| 450 | 410 | }; |
|---|
| 451 | 411 | |
|---|
| 452 | 412 | static void vti_tunnel_setup(struct net_device *dev) |
|---|
| 453 | 413 | { |
|---|
| 454 | 414 | dev->netdev_ops = &vti_netdev_ops; |
|---|
| 415 | + dev->header_ops = &ip_tunnel_header_ops; |
|---|
| 455 | 416 | dev->type = ARPHRD_TUNNEL; |
|---|
| 456 | 417 | ip_tunnel_setup(dev, vti_net_id); |
|---|
| 457 | 418 | } |
|---|
| .. | .. |
|---|
| 506 | 467 | .priority = 100, |
|---|
| 507 | 468 | }; |
|---|
| 508 | 469 | |
|---|
| 509 | | -static struct xfrm_tunnel ipip_handler __read_mostly = { |
|---|
| 470 | +#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
|---|
| 471 | +static int vti_rcv_tunnel(struct sk_buff *skb) |
|---|
| 472 | +{ |
|---|
| 473 | + XFRM_SPI_SKB_CB(skb)->family = AF_INET; |
|---|
| 474 | + XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); |
|---|
| 475 | + |
|---|
| 476 | + return vti_input(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr, 0, false); |
|---|
| 477 | +} |
|---|
| 478 | + |
|---|
| 479 | +static struct xfrm_tunnel vti_ipip_handler __read_mostly = { |
|---|
| 510 | 480 | .handler = vti_rcv_tunnel, |
|---|
| 481 | + .cb_handler = vti_rcv_cb, |
|---|
| 511 | 482 | .err_handler = vti4_err, |
|---|
| 512 | 483 | .priority = 0, |
|---|
| 513 | 484 | }; |
|---|
| 485 | + |
|---|
| 486 | +#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 487 | +static struct xfrm_tunnel vti_ipip6_handler __read_mostly = { |
|---|
| 488 | + .handler = vti_rcv_tunnel, |
|---|
| 489 | + .cb_handler = vti_rcv_cb, |
|---|
| 490 | + .err_handler = vti4_err, |
|---|
| 491 | + .priority = 0, |
|---|
| 492 | +}; |
|---|
| 493 | +#endif |
|---|
| 494 | +#endif |
|---|
| 514 | 495 | |
|---|
| 515 | 496 | static int __net_init vti_init_net(struct net *net) |
|---|
| 516 | 497 | { |
|---|
| .. | .. |
|---|
| 637 | 618 | [IFLA_VTI_LINK] = { .type = NLA_U32 }, |
|---|
| 638 | 619 | [IFLA_VTI_IKEY] = { .type = NLA_U32 }, |
|---|
| 639 | 620 | [IFLA_VTI_OKEY] = { .type = NLA_U32 }, |
|---|
| 640 | | - [IFLA_VTI_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) }, |
|---|
| 641 | | - [IFLA_VTI_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, |
|---|
| 621 | + [IFLA_VTI_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) }, |
|---|
| 622 | + [IFLA_VTI_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) }, |
|---|
| 642 | 623 | [IFLA_VTI_FWMARK] = { .type = NLA_U32 }, |
|---|
| 643 | 624 | }; |
|---|
| 644 | 625 | |
|---|
| .. | .. |
|---|
| 680 | 661 | if (err < 0) |
|---|
| 681 | 662 | goto xfrm_proto_comp_failed; |
|---|
| 682 | 663 | |
|---|
| 664 | +#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
|---|
| 683 | 665 | msg = "ipip tunnel"; |
|---|
| 684 | | - err = xfrm4_tunnel_register(&ipip_handler, AF_INET); |
|---|
| 666 | + err = xfrm4_tunnel_register(&vti_ipip_handler, AF_INET); |
|---|
| 685 | 667 | if (err < 0) |
|---|
| 686 | | - goto xfrm_tunnel_failed; |
|---|
| 668 | + goto xfrm_tunnel_ipip_failed; |
|---|
| 669 | +#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 670 | + err = xfrm4_tunnel_register(&vti_ipip6_handler, AF_INET6); |
|---|
| 671 | + if (err < 0) |
|---|
| 672 | + goto xfrm_tunnel_ipip6_failed; |
|---|
| 673 | +#endif |
|---|
| 674 | +#endif |
|---|
| 687 | 675 | |
|---|
| 688 | 676 | msg = "netlink interface"; |
|---|
| 689 | 677 | err = rtnl_link_register(&vti_link_ops); |
|---|
| .. | .. |
|---|
| 693 | 681 | return err; |
|---|
| 694 | 682 | |
|---|
| 695 | 683 | rtnl_link_failed: |
|---|
| 696 | | - xfrm4_tunnel_deregister(&ipip_handler, AF_INET); |
|---|
| 697 | | -xfrm_tunnel_failed: |
|---|
| 684 | +#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
|---|
| 685 | +#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 686 | + xfrm4_tunnel_deregister(&vti_ipip6_handler, AF_INET6); |
|---|
| 687 | +xfrm_tunnel_ipip6_failed: |
|---|
| 688 | +#endif |
|---|
| 689 | + xfrm4_tunnel_deregister(&vti_ipip_handler, AF_INET); |
|---|
| 690 | +xfrm_tunnel_ipip_failed: |
|---|
| 691 | +#endif |
|---|
| 698 | 692 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
|---|
| 699 | 693 | xfrm_proto_comp_failed: |
|---|
| 700 | 694 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
|---|
| .. | .. |
|---|
| 710 | 704 | static void __exit vti_fini(void) |
|---|
| 711 | 705 | { |
|---|
| 712 | 706 | rtnl_link_unregister(&vti_link_ops); |
|---|
| 713 | | - xfrm4_tunnel_deregister(&ipip_handler, AF_INET); |
|---|
| 707 | +#if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) |
|---|
| 708 | +#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 709 | + xfrm4_tunnel_deregister(&vti_ipip6_handler, AF_INET6); |
|---|
| 710 | +#endif |
|---|
| 711 | + xfrm4_tunnel_deregister(&vti_ipip_handler, AF_INET); |
|---|
| 712 | +#endif |
|---|
| 714 | 713 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
|---|
| 715 | 714 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
|---|
| 716 | 715 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); |
|---|