.. | .. |
---|
| 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); |
---|