162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux NET3: IP/IP protocol decoder. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Fixes: 962306a36Sopenharmony_ci * Alan Cox : Merged and made usable non modular (its so tiny its silly as 1062306a36Sopenharmony_ci * a module taking up 2 pages). 1162306a36Sopenharmony_ci * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph) 1262306a36Sopenharmony_ci * to keep ip_forward happy. 1362306a36Sopenharmony_ci * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8). 1462306a36Sopenharmony_ci * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL 1562306a36Sopenharmony_ci * David Woodhouse : Perform some basic ICMP handling. 1662306a36Sopenharmony_ci * IPIP Routing without decapsulation. 1762306a36Sopenharmony_ci * Carlos Picoto : GRE over IP support 1862306a36Sopenharmony_ci * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c. 1962306a36Sopenharmony_ci * I do not want to merge them together. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* tunnel.c: an IP tunnel driver 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci The purpose of this driver is to provide an IP tunnel through 2562306a36Sopenharmony_ci which you can tunnel network traffic transparently across subnets. 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci This was written by looking at Nick Holloway's dummy driver 2862306a36Sopenharmony_ci Thanks for the great code! 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci Minor tweaks: 3362306a36Sopenharmony_ci Cleaned up the code a little and added some pre-1.3.0 tweaks. 3462306a36Sopenharmony_ci dev->hard_header/hard_header_len changed to use no headers. 3562306a36Sopenharmony_ci Comments/bracketing tweaked. 3662306a36Sopenharmony_ci Made the tunnels use dev->name not tunnel: when error reporting. 3762306a36Sopenharmony_ci Added tx_dropped stat 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci Reworked: 4262306a36Sopenharmony_ci Changed to tunnel to destination gateway in addition to the 4362306a36Sopenharmony_ci tunnel's pointopoint address 4462306a36Sopenharmony_ci Almost completely rewritten 4562306a36Sopenharmony_ci Note: There is currently no firewall or ICMP handling done. 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci*/ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* Things I wish I had known when writing the tunnel driver: 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci When the tunnel_xmit() function is called, the skb contains the 5462306a36Sopenharmony_ci packet to be sent (plus a great deal of extra info), and dev 5562306a36Sopenharmony_ci contains the tunnel device that _we_ are. 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci When we are passed a packet, we are expected to fill in the 5862306a36Sopenharmony_ci source address with our source IP address. 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci What is the proper way to allocate, copy and free a buffer? 6162306a36Sopenharmony_ci After you allocate it, it is a "0 length" chunk of memory 6262306a36Sopenharmony_ci starting at zero. If you want to add headers to the buffer 6362306a36Sopenharmony_ci later, you'll have to call "skb_reserve(skb, amount)" with 6462306a36Sopenharmony_ci the amount of memory you want reserved. Then, you call 6562306a36Sopenharmony_ci "skb_put(skb, amount)" with the amount of space you want in 6662306a36Sopenharmony_ci the buffer. skb_put() returns a pointer to the top (#0) of 6762306a36Sopenharmony_ci that buffer. skb->len is set to the amount of space you have 6862306a36Sopenharmony_ci "allocated" with skb_put(). You can then write up to skb->len 6962306a36Sopenharmony_ci bytes to that buffer. If you need more, you can call skb_put() 7062306a36Sopenharmony_ci again with the additional amount of space you need. You can 7162306a36Sopenharmony_ci find out how much more space you can allocate by calling 7262306a36Sopenharmony_ci "skb_tailroom(skb)". 7362306a36Sopenharmony_ci Now, to add header space, call "skb_push(skb, header_len)". 7462306a36Sopenharmony_ci This creates space at the beginning of the buffer and returns 7562306a36Sopenharmony_ci a pointer to this new space. If later you need to strip a 7662306a36Sopenharmony_ci header from a buffer, call "skb_pull(skb, header_len)". 7762306a36Sopenharmony_ci skb_headroom() will return how much space is left at the top 7862306a36Sopenharmony_ci of the buffer (before the main data). Remember, this headroom 7962306a36Sopenharmony_ci space must be reserved before the skb_put() function is called. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci For comments look at net/ipv4/ip_gre.c --ANK 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#include <linux/capability.h> 9062306a36Sopenharmony_ci#include <linux/module.h> 9162306a36Sopenharmony_ci#include <linux/types.h> 9262306a36Sopenharmony_ci#include <linux/kernel.h> 9362306a36Sopenharmony_ci#include <linux/slab.h> 9462306a36Sopenharmony_ci#include <linux/uaccess.h> 9562306a36Sopenharmony_ci#include <linux/skbuff.h> 9662306a36Sopenharmony_ci#include <linux/netdevice.h> 9762306a36Sopenharmony_ci#include <linux/in.h> 9862306a36Sopenharmony_ci#include <linux/tcp.h> 9962306a36Sopenharmony_ci#include <linux/udp.h> 10062306a36Sopenharmony_ci#include <linux/if_arp.h> 10162306a36Sopenharmony_ci#include <linux/init.h> 10262306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h> 10362306a36Sopenharmony_ci#include <linux/if_ether.h> 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#include <net/sock.h> 10662306a36Sopenharmony_ci#include <net/ip.h> 10762306a36Sopenharmony_ci#include <net/icmp.h> 10862306a36Sopenharmony_ci#include <net/ip_tunnels.h> 10962306a36Sopenharmony_ci#include <net/inet_ecn.h> 11062306a36Sopenharmony_ci#include <net/xfrm.h> 11162306a36Sopenharmony_ci#include <net/net_namespace.h> 11262306a36Sopenharmony_ci#include <net/netns/generic.h> 11362306a36Sopenharmony_ci#include <net/dst_metadata.h> 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic bool log_ecn_error = true; 11662306a36Sopenharmony_cimodule_param(log_ecn_error, bool, 0644); 11762306a36Sopenharmony_ciMODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic unsigned int ipip_net_id __read_mostly; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int ipip_tunnel_init(struct net_device *dev); 12262306a36Sopenharmony_cistatic struct rtnl_link_ops ipip_link_ops __read_mostly; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int ipip_err(struct sk_buff *skb, u32 info) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci /* All the routers (except for Linux) return only 12762306a36Sopenharmony_ci * 8 bytes of packet payload. It means, that precise relaying of 12862306a36Sopenharmony_ci * ICMP in the real Internet is absolutely infeasible. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 13162306a36Sopenharmony_ci struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 13262306a36Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 13362306a36Sopenharmony_ci const int type = icmp_hdr(skb)->type; 13462306a36Sopenharmony_ci const int code = icmp_hdr(skb)->code; 13562306a36Sopenharmony_ci struct ip_tunnel *t; 13662306a36Sopenharmony_ci int err = 0; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 13962306a36Sopenharmony_ci iph->daddr, iph->saddr, 0); 14062306a36Sopenharmony_ci if (!t) { 14162306a36Sopenharmony_ci err = -ENOENT; 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci switch (type) { 14662306a36Sopenharmony_ci case ICMP_DEST_UNREACH: 14762306a36Sopenharmony_ci switch (code) { 14862306a36Sopenharmony_ci case ICMP_SR_FAILED: 14962306a36Sopenharmony_ci /* Impossible event. */ 15062306a36Sopenharmony_ci goto out; 15162306a36Sopenharmony_ci default: 15262306a36Sopenharmony_ci /* All others are translated to HOST_UNREACH. 15362306a36Sopenharmony_ci * rfc2003 contains "deep thoughts" about NET_UNREACH, 15462306a36Sopenharmony_ci * I believe they are just ether pollution. --ANK 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci case ICMP_TIME_EXCEEDED: 16162306a36Sopenharmony_ci if (code != ICMP_EXC_TTL) 16262306a36Sopenharmony_ci goto out; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci case ICMP_REDIRECT: 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci goto out; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 17362306a36Sopenharmony_ci ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol); 17462306a36Sopenharmony_ci goto out; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (type == ICMP_REDIRECT) { 17862306a36Sopenharmony_ci ipv4_redirect(skb, net, t->parms.link, iph->protocol); 17962306a36Sopenharmony_ci goto out; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (t->parms.iph.daddr == 0) { 18362306a36Sopenharmony_ci err = -ENOENT; 18462306a36Sopenharmony_ci goto out; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 18862306a36Sopenharmony_ci goto out; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 19162306a36Sopenharmony_ci t->err_count++; 19262306a36Sopenharmony_ci else 19362306a36Sopenharmony_ci t->err_count = 1; 19462306a36Sopenharmony_ci t->err_time = jiffies; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciout: 19762306a36Sopenharmony_ci return err; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const struct tnl_ptk_info ipip_tpi = { 20162306a36Sopenharmony_ci /* no tunnel info required for ipip. */ 20262306a36Sopenharmony_ci .proto = htons(ETH_P_IP), 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 20662306a36Sopenharmony_cistatic const struct tnl_ptk_info mplsip_tpi = { 20762306a36Sopenharmony_ci /* no tunnel info required for mplsip. */ 20862306a36Sopenharmony_ci .proto = htons(ETH_P_MPLS_UC), 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci#endif 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 21562306a36Sopenharmony_ci struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 21662306a36Sopenharmony_ci struct metadata_dst *tun_dst = NULL; 21762306a36Sopenharmony_ci struct ip_tunnel *tunnel; 21862306a36Sopenharmony_ci const struct iphdr *iph; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci iph = ip_hdr(skb); 22162306a36Sopenharmony_ci tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 22262306a36Sopenharmony_ci iph->saddr, iph->daddr, 0); 22362306a36Sopenharmony_ci if (tunnel) { 22462306a36Sopenharmony_ci const struct tnl_ptk_info *tpi; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (tunnel->parms.iph.protocol != ipproto && 22762306a36Sopenharmony_ci tunnel->parms.iph.protocol != 0) 22862306a36Sopenharmony_ci goto drop; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 23162306a36Sopenharmony_ci goto drop; 23262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 23362306a36Sopenharmony_ci if (ipproto == IPPROTO_MPLS) 23462306a36Sopenharmony_ci tpi = &mplsip_tpi; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci#endif 23762306a36Sopenharmony_ci tpi = &ipip_tpi; 23862306a36Sopenharmony_ci if (iptunnel_pull_header(skb, 0, tpi->proto, false)) 23962306a36Sopenharmony_ci goto drop; 24062306a36Sopenharmony_ci if (tunnel->collect_md) { 24162306a36Sopenharmony_ci tun_dst = ip_tun_rx_dst(skb, 0, 0, 0); 24262306a36Sopenharmony_ci if (!tun_dst) 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci ip_tunnel_md_udp_encap(skb, &tun_dst->u.tun_info); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci skb_reset_mac_header(skb); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return -1; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cidrop: 25462306a36Sopenharmony_ci kfree_skb(skb); 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int ipip_rcv(struct sk_buff *skb) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci return ipip_tunnel_rcv(skb, IPPROTO_IPIP); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 26462306a36Sopenharmony_cistatic int mplsip_rcv(struct sk_buff *skb) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci return ipip_tunnel_rcv(skb, IPPROTO_MPLS); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci#endif 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* 27162306a36Sopenharmony_ci * This function assumes it is being called from dev_queue_xmit() 27262306a36Sopenharmony_ci * and that skb is filled properly by that function. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_cistatic netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, 27562306a36Sopenharmony_ci struct net_device *dev) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 27862306a36Sopenharmony_ci const struct iphdr *tiph = &tunnel->parms.iph; 27962306a36Sopenharmony_ci u8 ipproto; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!pskb_inet_may_pull(skb)) 28262306a36Sopenharmony_ci goto tx_error; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci switch (skb->protocol) { 28562306a36Sopenharmony_ci case htons(ETH_P_IP): 28662306a36Sopenharmony_ci ipproto = IPPROTO_IPIP; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 28962306a36Sopenharmony_ci case htons(ETH_P_MPLS_UC): 29062306a36Sopenharmony_ci ipproto = IPPROTO_MPLS; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci#endif 29362306a36Sopenharmony_ci default: 29462306a36Sopenharmony_ci goto tx_error; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (tiph->protocol != ipproto && tiph->protocol != 0) 29862306a36Sopenharmony_ci goto tx_error; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) 30162306a36Sopenharmony_ci goto tx_error; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci skb_set_inner_ipproto(skb, ipproto); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (tunnel->collect_md) 30662306a36Sopenharmony_ci ip_md_tunnel_xmit(skb, dev, ipproto, 0); 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci ip_tunnel_xmit(skb, dev, tiph, ipproto); 30962306a36Sopenharmony_ci return NETDEV_TX_OK; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_citx_error: 31262306a36Sopenharmony_ci kfree_skb(skb); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_errors); 31562306a36Sopenharmony_ci return NETDEV_TX_OK; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci switch (ipproto) { 32162306a36Sopenharmony_ci case 0: 32262306a36Sopenharmony_ci case IPPROTO_IPIP: 32362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 32462306a36Sopenharmony_ci case IPPROTO_MPLS: 32562306a36Sopenharmony_ci#endif 32662306a36Sopenharmony_ci return true; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return false; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int 33362306a36Sopenharmony_ciipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 33662306a36Sopenharmony_ci if (p->iph.version != 4 || 33762306a36Sopenharmony_ci !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) || 33862306a36Sopenharmony_ci p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF))) 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci p->i_key = p->o_key = 0; 34362306a36Sopenharmony_ci p->i_flags = p->o_flags = 0; 34462306a36Sopenharmony_ci return ip_tunnel_ctl(dev, p, cmd); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic const struct net_device_ops ipip_netdev_ops = { 34862306a36Sopenharmony_ci .ndo_init = ipip_tunnel_init, 34962306a36Sopenharmony_ci .ndo_uninit = ip_tunnel_uninit, 35062306a36Sopenharmony_ci .ndo_start_xmit = ipip_tunnel_xmit, 35162306a36Sopenharmony_ci .ndo_siocdevprivate = ip_tunnel_siocdevprivate, 35262306a36Sopenharmony_ci .ndo_change_mtu = ip_tunnel_change_mtu, 35362306a36Sopenharmony_ci .ndo_get_stats64 = dev_get_tstats64, 35462306a36Sopenharmony_ci .ndo_get_iflink = ip_tunnel_get_iflink, 35562306a36Sopenharmony_ci .ndo_tunnel_ctl = ipip_tunnel_ctl, 35662306a36Sopenharmony_ci}; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci#define IPIP_FEATURES (NETIF_F_SG | \ 35962306a36Sopenharmony_ci NETIF_F_FRAGLIST | \ 36062306a36Sopenharmony_ci NETIF_F_HIGHDMA | \ 36162306a36Sopenharmony_ci NETIF_F_GSO_SOFTWARE | \ 36262306a36Sopenharmony_ci NETIF_F_HW_CSUM) 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void ipip_tunnel_setup(struct net_device *dev) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci dev->netdev_ops = &ipip_netdev_ops; 36762306a36Sopenharmony_ci dev->header_ops = &ip_tunnel_header_ops; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci dev->type = ARPHRD_TUNNEL; 37062306a36Sopenharmony_ci dev->flags = IFF_NOARP; 37162306a36Sopenharmony_ci dev->addr_len = 4; 37262306a36Sopenharmony_ci dev->features |= NETIF_F_LLTX; 37362306a36Sopenharmony_ci netif_keep_dst(dev); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dev->features |= IPIP_FEATURES; 37662306a36Sopenharmony_ci dev->hw_features |= IPIP_FEATURES; 37762306a36Sopenharmony_ci ip_tunnel_setup(dev, ipip_net_id); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int ipip_tunnel_init(struct net_device *dev) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci __dev_addr_set(dev, &tunnel->parms.iph.saddr, 4); 38562306a36Sopenharmony_ci memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci tunnel->tun_hlen = 0; 38862306a36Sopenharmony_ci tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 38962306a36Sopenharmony_ci return ip_tunnel_init(dev); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], 39362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci u8 proto; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (!data || !data[IFLA_IPTUN_PROTO]) 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); 40162306a36Sopenharmony_ci if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0) 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void ipip_netlink_parms(struct nlattr *data[], 40862306a36Sopenharmony_ci struct ip_tunnel_parm *parms, bool *collect_md, 40962306a36Sopenharmony_ci __u32 *fwmark) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci memset(parms, 0, sizeof(*parms)); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci parms->iph.version = 4; 41462306a36Sopenharmony_ci parms->iph.protocol = IPPROTO_IPIP; 41562306a36Sopenharmony_ci parms->iph.ihl = 5; 41662306a36Sopenharmony_ci *collect_md = false; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!data) 41962306a36Sopenharmony_ci return; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ip_tunnel_netlink_parms(data, parms); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (data[IFLA_IPTUN_COLLECT_METADATA]) 42462306a36Sopenharmony_ci *collect_md = true; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (data[IFLA_IPTUN_FWMARK]) 42762306a36Sopenharmony_ci *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int ipip_newlink(struct net *src_net, struct net_device *dev, 43162306a36Sopenharmony_ci struct nlattr *tb[], struct nlattr *data[], 43262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 43562306a36Sopenharmony_ci struct ip_tunnel_parm p; 43662306a36Sopenharmony_ci struct ip_tunnel_encap ipencap; 43762306a36Sopenharmony_ci __u32 fwmark = 0; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 44062306a36Sopenharmony_ci int err = ip_tunnel_encap_setup(t, &ipencap); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (err < 0) 44362306a36Sopenharmony_ci return err; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci ipip_netlink_parms(data, &p, &t->collect_md, &fwmark); 44762306a36Sopenharmony_ci return ip_tunnel_newlink(dev, tb, &p, fwmark); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 45162306a36Sopenharmony_ci struct nlattr *data[], 45262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 45562306a36Sopenharmony_ci struct ip_tunnel_parm p; 45662306a36Sopenharmony_ci struct ip_tunnel_encap ipencap; 45762306a36Sopenharmony_ci bool collect_md; 45862306a36Sopenharmony_ci __u32 fwmark = t->fwmark; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 46162306a36Sopenharmony_ci int err = ip_tunnel_encap_setup(t, &ipencap); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (err < 0) 46462306a36Sopenharmony_ci return err; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ipip_netlink_parms(data, &p, &collect_md, &fwmark); 46862306a36Sopenharmony_ci if (collect_md) 46962306a36Sopenharmony_ci return -EINVAL; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 47262306a36Sopenharmony_ci (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return ip_tunnel_changelink(dev, tb, &p, fwmark); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic size_t ipip_get_size(const struct net_device *dev) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci return 48162306a36Sopenharmony_ci /* IFLA_IPTUN_LINK */ 48262306a36Sopenharmony_ci nla_total_size(4) + 48362306a36Sopenharmony_ci /* IFLA_IPTUN_LOCAL */ 48462306a36Sopenharmony_ci nla_total_size(4) + 48562306a36Sopenharmony_ci /* IFLA_IPTUN_REMOTE */ 48662306a36Sopenharmony_ci nla_total_size(4) + 48762306a36Sopenharmony_ci /* IFLA_IPTUN_TTL */ 48862306a36Sopenharmony_ci nla_total_size(1) + 48962306a36Sopenharmony_ci /* IFLA_IPTUN_TOS */ 49062306a36Sopenharmony_ci nla_total_size(1) + 49162306a36Sopenharmony_ci /* IFLA_IPTUN_PROTO */ 49262306a36Sopenharmony_ci nla_total_size(1) + 49362306a36Sopenharmony_ci /* IFLA_IPTUN_PMTUDISC */ 49462306a36Sopenharmony_ci nla_total_size(1) + 49562306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_TYPE */ 49662306a36Sopenharmony_ci nla_total_size(2) + 49762306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_FLAGS */ 49862306a36Sopenharmony_ci nla_total_size(2) + 49962306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_SPORT */ 50062306a36Sopenharmony_ci nla_total_size(2) + 50162306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_DPORT */ 50262306a36Sopenharmony_ci nla_total_size(2) + 50362306a36Sopenharmony_ci /* IFLA_IPTUN_COLLECT_METADATA */ 50462306a36Sopenharmony_ci nla_total_size(0) + 50562306a36Sopenharmony_ci /* IFLA_IPTUN_FWMARK */ 50662306a36Sopenharmony_ci nla_total_size(4) + 50762306a36Sopenharmony_ci 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 51362306a36Sopenharmony_ci struct ip_tunnel_parm *parm = &tunnel->parms; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 51662306a36Sopenharmony_ci nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 51762306a36Sopenharmony_ci nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 51862306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 51962306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 52062306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || 52162306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 52262306a36Sopenharmony_ci !!(parm->iph.frag_off & htons(IP_DF))) || 52362306a36Sopenharmony_ci nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark)) 52462306a36Sopenharmony_ci goto nla_put_failure; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 52762306a36Sopenharmony_ci tunnel->encap.type) || 52862306a36Sopenharmony_ci nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 52962306a36Sopenharmony_ci tunnel->encap.sport) || 53062306a36Sopenharmony_ci nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 53162306a36Sopenharmony_ci tunnel->encap.dport) || 53262306a36Sopenharmony_ci nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 53362306a36Sopenharmony_ci tunnel->encap.flags)) 53462306a36Sopenharmony_ci goto nla_put_failure; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (tunnel->collect_md) 53762306a36Sopenharmony_ci if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) 53862306a36Sopenharmony_ci goto nla_put_failure; 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cinla_put_failure: 54262306a36Sopenharmony_ci return -EMSGSIZE; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 54662306a36Sopenharmony_ci [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 54762306a36Sopenharmony_ci [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 54862306a36Sopenharmony_ci [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 54962306a36Sopenharmony_ci [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 55062306a36Sopenharmony_ci [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 55162306a36Sopenharmony_ci [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 55262306a36Sopenharmony_ci [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 55362306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 55462306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 55562306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 55662306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 55762306a36Sopenharmony_ci [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, 55862306a36Sopenharmony_ci [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, 55962306a36Sopenharmony_ci}; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic struct rtnl_link_ops ipip_link_ops __read_mostly = { 56262306a36Sopenharmony_ci .kind = "ipip", 56362306a36Sopenharmony_ci .maxtype = IFLA_IPTUN_MAX, 56462306a36Sopenharmony_ci .policy = ipip_policy, 56562306a36Sopenharmony_ci .priv_size = sizeof(struct ip_tunnel), 56662306a36Sopenharmony_ci .setup = ipip_tunnel_setup, 56762306a36Sopenharmony_ci .validate = ipip_tunnel_validate, 56862306a36Sopenharmony_ci .newlink = ipip_newlink, 56962306a36Sopenharmony_ci .changelink = ipip_changelink, 57062306a36Sopenharmony_ci .dellink = ip_tunnel_dellink, 57162306a36Sopenharmony_ci .get_size = ipip_get_size, 57262306a36Sopenharmony_ci .fill_info = ipip_fill_info, 57362306a36Sopenharmony_ci .get_link_net = ip_tunnel_get_link_net, 57462306a36Sopenharmony_ci}; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic struct xfrm_tunnel ipip_handler __read_mostly = { 57762306a36Sopenharmony_ci .handler = ipip_rcv, 57862306a36Sopenharmony_ci .err_handler = ipip_err, 57962306a36Sopenharmony_ci .priority = 1, 58062306a36Sopenharmony_ci}; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 58362306a36Sopenharmony_cistatic struct xfrm_tunnel mplsip_handler __read_mostly = { 58462306a36Sopenharmony_ci .handler = mplsip_rcv, 58562306a36Sopenharmony_ci .err_handler = ipip_err, 58662306a36Sopenharmony_ci .priority = 1, 58762306a36Sopenharmony_ci}; 58862306a36Sopenharmony_ci#endif 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int __net_init ipip_init_net(struct net *net) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void __net_exit ipip_exit_batch_net(struct list_head *list_net) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic struct pernet_operations ipip_net_ops = { 60162306a36Sopenharmony_ci .init = ipip_init_net, 60262306a36Sopenharmony_ci .exit_batch = ipip_exit_batch_net, 60362306a36Sopenharmony_ci .id = &ipip_net_id, 60462306a36Sopenharmony_ci .size = sizeof(struct ip_tunnel_net), 60562306a36Sopenharmony_ci}; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int __init ipip_init(void) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int err; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n"); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci err = register_pernet_device(&ipip_net_ops); 61462306a36Sopenharmony_ci if (err < 0) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 61762306a36Sopenharmony_ci if (err < 0) { 61862306a36Sopenharmony_ci pr_info("%s: can't register tunnel\n", __func__); 61962306a36Sopenharmony_ci goto xfrm_tunnel_ipip_failed; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 62262306a36Sopenharmony_ci err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); 62362306a36Sopenharmony_ci if (err < 0) { 62462306a36Sopenharmony_ci pr_info("%s: can't register tunnel\n", __func__); 62562306a36Sopenharmony_ci goto xfrm_tunnel_mplsip_failed; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci#endif 62862306a36Sopenharmony_ci err = rtnl_link_register(&ipip_link_ops); 62962306a36Sopenharmony_ci if (err < 0) 63062306a36Sopenharmony_ci goto rtnl_link_failed; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ciout: 63362306a36Sopenharmony_ci return err; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cirtnl_link_failed: 63662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 63762306a36Sopenharmony_ci xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); 63862306a36Sopenharmony_cixfrm_tunnel_mplsip_failed: 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 64262306a36Sopenharmony_cixfrm_tunnel_ipip_failed: 64362306a36Sopenharmony_ci unregister_pernet_device(&ipip_net_ops); 64462306a36Sopenharmony_ci goto out; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void __exit ipip_fini(void) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci rtnl_link_unregister(&ipip_link_ops); 65062306a36Sopenharmony_ci if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 65162306a36Sopenharmony_ci pr_info("%s: can't deregister tunnel\n", __func__); 65262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 65362306a36Sopenharmony_ci if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS)) 65462306a36Sopenharmony_ci pr_info("%s: can't deregister tunnel\n", __func__); 65562306a36Sopenharmony_ci#endif 65662306a36Sopenharmony_ci unregister_pernet_device(&ipip_net_ops); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cimodule_init(ipip_init); 66062306a36Sopenharmony_cimodule_exit(ipip_fini); 66162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 66262306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("ipip"); 66362306a36Sopenharmony_ciMODULE_ALIAS_NETDEV("tunl0"); 664