11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Linux NET3: IP/IP protocol decoder. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: 51da177e4SLinus Torvalds * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Fixes: 81da177e4SLinus Torvalds * Alan Cox : Merged and made usable non modular (its so tiny its silly as 91da177e4SLinus Torvalds * a module taking up 2 pages). 101da177e4SLinus Torvalds * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph) 111da177e4SLinus Torvalds * to keep ip_forward happy. 121da177e4SLinus Torvalds * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8). 131da177e4SLinus Torvalds * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL 141da177e4SLinus Torvalds * David Woodhouse : Perform some basic ICMP handling. 151da177e4SLinus Torvalds * IPIP Routing without decapsulation. 161da177e4SLinus Torvalds * Carlos Picoto : GRE over IP support 171da177e4SLinus Torvalds * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c. 181da177e4SLinus Torvalds * I do not want to merge them together. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 211da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 221da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 231da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* tunnel.c: an IP tunnel driver 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds The purpose of this driver is to provide an IP tunnel through 301da177e4SLinus Torvalds which you can tunnel network traffic transparently across subnets. 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds This was written by looking at Nick Holloway's dummy driver 331da177e4SLinus Torvalds Thanks for the great code! 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds Minor tweaks: 381da177e4SLinus Torvalds Cleaned up the code a little and added some pre-1.3.0 tweaks. 391da177e4SLinus Torvalds dev->hard_header/hard_header_len changed to use no headers. 401da177e4SLinus Torvalds Comments/bracketing tweaked. 411da177e4SLinus Torvalds Made the tunnels use dev->name not tunnel: when error reporting. 421da177e4SLinus Torvalds Added tx_dropped stat 431da177e4SLinus Torvalds 44113aa838SAlan Cox -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds Reworked: 471da177e4SLinus Torvalds Changed to tunnel to destination gateway in addition to the 481da177e4SLinus Torvalds tunnel's pointopoint address 491da177e4SLinus Torvalds Almost completely rewritten 501da177e4SLinus Torvalds Note: There is currently no firewall or ICMP handling done. 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* Things I wish I had known when writing the tunnel driver: 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds When the tunnel_xmit() function is called, the skb contains the 591da177e4SLinus Torvalds packet to be sent (plus a great deal of extra info), and dev 601da177e4SLinus Torvalds contains the tunnel device that _we_ are. 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds When we are passed a packet, we are expected to fill in the 631da177e4SLinus Torvalds source address with our source IP address. 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds What is the proper way to allocate, copy and free a buffer? 661da177e4SLinus Torvalds After you allocate it, it is a "0 length" chunk of memory 671da177e4SLinus Torvalds starting at zero. If you want to add headers to the buffer 681da177e4SLinus Torvalds later, you'll have to call "skb_reserve(skb, amount)" with 691da177e4SLinus Torvalds the amount of memory you want reserved. Then, you call 701da177e4SLinus Torvalds "skb_put(skb, amount)" with the amount of space you want in 711da177e4SLinus Torvalds the buffer. skb_put() returns a pointer to the top (#0) of 721da177e4SLinus Torvalds that buffer. skb->len is set to the amount of space you have 731da177e4SLinus Torvalds "allocated" with skb_put(). You can then write up to skb->len 741da177e4SLinus Torvalds bytes to that buffer. If you need more, you can call skb_put() 751da177e4SLinus Torvalds again with the additional amount of space you need. You can 761da177e4SLinus Torvalds find out how much more space you can allocate by calling 771da177e4SLinus Torvalds "skb_tailroom(skb)". 781da177e4SLinus Torvalds Now, to add header space, call "skb_push(skb, header_len)". 791da177e4SLinus Torvalds This creates space at the beginning of the buffer and returns 801da177e4SLinus Torvalds a pointer to this new space. If later you need to strip a 811da177e4SLinus Torvalds header from a buffer, call "skb_pull(skb, header_len)". 821da177e4SLinus Torvalds skb_headroom() will return how much space is left at the top 831da177e4SLinus Torvalds of the buffer (before the main data). Remember, this headroom 841da177e4SLinus Torvalds space must be reserved before the skb_put() function is called. 851da177e4SLinus Torvalds */ 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881da177e4SLinus Torvalds This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds For comments look at net/ipv4/ip_gre.c --ANK 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds 944fc268d2SRandy Dunlap #include <linux/capability.h> 951da177e4SLinus Torvalds #include <linux/module.h> 961da177e4SLinus Torvalds #include <linux/types.h> 971da177e4SLinus Torvalds #include <linux/kernel.h> 985a0e3ad6STejun Heo #include <linux/slab.h> 991da177e4SLinus Torvalds #include <asm/uaccess.h> 1001da177e4SLinus Torvalds #include <linux/skbuff.h> 1011da177e4SLinus Torvalds #include <linux/netdevice.h> 1021da177e4SLinus Torvalds #include <linux/in.h> 1031da177e4SLinus Torvalds #include <linux/tcp.h> 1041da177e4SLinus Torvalds #include <linux/udp.h> 1051da177e4SLinus Torvalds #include <linux/if_arp.h> 1061da177e4SLinus Torvalds #include <linux/mroute.h> 1071da177e4SLinus Torvalds #include <linux/init.h> 1081da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 10946f25dffSKris Katterjohn #include <linux/if_ether.h> 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds #include <net/sock.h> 1121da177e4SLinus Torvalds #include <net/ip.h> 1131da177e4SLinus Torvalds #include <net/icmp.h> 114c5441932SPravin B Shelar #include <net/ip_tunnels.h> 1151da177e4SLinus Torvalds #include <net/inet_ecn.h> 1161da177e4SLinus Torvalds #include <net/xfrm.h> 11710dc4c7bSPavel Emelyanov #include <net/net_namespace.h> 11810dc4c7bSPavel Emelyanov #include <net/netns/generic.h> 1191da177e4SLinus Torvalds 120eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 121eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 122eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 123eccc1bb8Sstephen hemminger 124f99189b1SEric Dumazet static int ipip_net_id __read_mostly; 12510dc4c7bSPavel Emelyanov 1263c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev); 1270974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly; 1281da177e4SLinus Torvalds 129d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds 132071f92d0SRami Rosen /* All the routers (except for Linux) return only 1331da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 1341da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 1351da177e4SLinus Torvalds */ 136fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 137fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 138b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 1391da177e4SLinus Torvalds struct ip_tunnel *t; 140d2acc347SHerbert Xu int err; 141fd58156eSPravin B Shelar const int type = icmp_hdr(skb)->type; 142fd58156eSPravin B Shelar const int code = icmp_hdr(skb)->code; 1431da177e4SLinus Torvalds 144d2acc347SHerbert Xu err = -ENOENT; 145fd58156eSPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 146fd58156eSPravin B Shelar iph->daddr, iph->saddr, 0); 14736393395SDavid S. Miller if (t == NULL) 14836393395SDavid S. Miller goto out; 14936393395SDavid S. Miller 15036393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 15136393395SDavid S. Miller ipv4_update_pmtu(skb, dev_net(skb->dev), info, 1522346829eSDmitry Popov t->parms.link, 0, IPPROTO_IPIP, 0); 15336393395SDavid S. Miller err = 0; 15436393395SDavid S. Miller goto out; 15536393395SDavid S. Miller } 15636393395SDavid S. Miller 15755be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) { 1582346829eSDmitry Popov ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, 15955be7a9cSDavid S. Miller IPPROTO_IPIP, 0); 16055be7a9cSDavid S. Miller err = 0; 16155be7a9cSDavid S. Miller goto out; 16255be7a9cSDavid S. Miller } 16355be7a9cSDavid S. Miller 16436393395SDavid S. Miller if (t->parms.iph.daddr == 0) 1651da177e4SLinus Torvalds goto out; 166d2acc347SHerbert Xu 167d2acc347SHerbert Xu err = 0; 1681da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 1691da177e4SLinus Torvalds goto out; 1701da177e4SLinus Torvalds 17126d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 1721da177e4SLinus Torvalds t->err_count++; 1731da177e4SLinus Torvalds else 1741da177e4SLinus Torvalds t->err_count = 1; 1751da177e4SLinus Torvalds t->err_time = jiffies; 176b0558ef2Sstephen hemminger 177fd58156eSPravin B Shelar out: 178d2acc347SHerbert Xu return err; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 181fd58156eSPravin B Shelar static const struct tnl_ptk_info tpi = { 182fd58156eSPravin B Shelar /* no tunnel info required for ipip. */ 183fd58156eSPravin B Shelar .proto = htons(ETH_P_IP), 184fd58156eSPravin B Shelar }; 185fd58156eSPravin B Shelar 1861da177e4SLinus Torvalds static int ipip_rcv(struct sk_buff *skb) 1871da177e4SLinus Torvalds { 188fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 189fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 1901da177e4SLinus Torvalds struct ip_tunnel *tunnel; 1913d7b46cdSPravin B Shelar const struct iphdr *iph; 1921da177e4SLinus Torvalds 1933d7b46cdSPravin B Shelar iph = ip_hdr(skb); 194fd58156eSPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 195fd58156eSPravin B Shelar iph->saddr, iph->daddr, 0); 196fd58156eSPravin B Shelar if (tunnel) { 197eccc1bb8Sstephen hemminger if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 198eccc1bb8Sstephen hemminger goto drop; 199737e828bSLi Hongjun if (iptunnel_pull_header(skb, 0, tpi.proto)) 200737e828bSLi Hongjun goto drop; 201fd58156eSPravin B Shelar return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error); 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds return -1; 205eccc1bb8Sstephen hemminger 206eccc1bb8Sstephen hemminger drop: 207eccc1bb8Sstephen hemminger kfree_skb(skb); 208eccc1bb8Sstephen hemminger return 0; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit() 2131da177e4SLinus Torvalds * and that skb is filled properly by that function. 2141da177e4SLinus Torvalds */ 2156fef4c0cSStephen Hemminger static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) 2161da177e4SLinus Torvalds { 2172941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 218b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph; 2191da177e4SLinus Torvalds 220fd58156eSPravin B Shelar if (unlikely(skb->protocol != htons(ETH_P_IP))) 2211da177e4SLinus Torvalds goto tx_error; 222cef401deSEric Dumazet 223cb32f511SEric Dumazet skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP); 224cb32f511SEric Dumazet if (IS_ERR(skb)) 225cb32f511SEric Dumazet goto out; 2264f3ed920SPravin B Shelar 227077c5a09STom Herbert skb_set_inner_ipproto(skb, IPPROTO_IPIP); 228077c5a09STom Herbert 229bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); 2306ed10654SPatrick McHardy return NETDEV_TX_OK; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds tx_error: 2333acfa1e7SEric Dumazet kfree_skb(skb); 234cb32f511SEric Dumazet out: 235cb32f511SEric Dumazet dev->stats.tx_errors++; 2366ed10654SPatrick McHardy return NETDEV_TX_OK; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds static int 2401da177e4SLinus Torvalds ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds int err = 0; 2431da177e4SLinus Torvalds struct ip_tunnel_parm p; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 246fd58156eSPravin B Shelar return -EFAULT; 2471da177e4SLinus Torvalds 2483b7b514fSCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 2491da177e4SLinus Torvalds if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || 2501da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) 251fd58156eSPravin B Shelar return -EINVAL; 2523b7b514fSCong Wang } 2533b7b514fSCong Wang 2543b7b514fSCong Wang p.i_key = p.o_key = p.i_flags = p.o_flags = 0; 2551da177e4SLinus Torvalds if (p.iph.ttl) 2561da177e4SLinus Torvalds p.iph.frag_off |= htons(IP_DF); 2571da177e4SLinus Torvalds 258fd58156eSPravin B Shelar err = ip_tunnel_ioctl(dev, &p, cmd); 259fd58156eSPravin B Shelar if (err) 2601da177e4SLinus Torvalds return err; 2611da177e4SLinus Torvalds 262fd58156eSPravin B Shelar if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 263fd58156eSPravin B Shelar return -EFAULT; 264fd58156eSPravin B Shelar 2651da177e4SLinus Torvalds return 0; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 26823a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = { 269fd58156eSPravin B Shelar .ndo_init = ipip_tunnel_init, 270fd58156eSPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 27123a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit, 27223a12b14SStephen Hemminger .ndo_do_ioctl = ipip_tunnel_ioctl, 273fd58156eSPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 274fd58156eSPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 275*1e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 27623a12b14SStephen Hemminger }; 27723a12b14SStephen Hemminger 278c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \ 279c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \ 280c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \ 281cb32f511SEric Dumazet NETIF_F_GSO_SOFTWARE | \ 282c3b89fbbSEric Dumazet NETIF_F_HW_CSUM) 283c3b89fbbSEric Dumazet 2841da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev) 2851da177e4SLinus Torvalds { 28623a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL; 2891da177e4SLinus Torvalds dev->flags = IFF_NOARP; 2901da177e4SLinus Torvalds dev->addr_len = 4; 291153f0943SEric Dumazet dev->features |= NETIF_F_LLTX; 29202875878SEric Dumazet netif_keep_dst(dev); 293c3b89fbbSEric Dumazet 294c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES; 295c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES; 296fd58156eSPravin B Shelar ip_tunnel_setup(dev, ipip_net_id); 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 2993c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev) 3001da177e4SLinus Torvalds { 30123a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 3041da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 3051da177e4SLinus Torvalds 306473ab820STom Herbert tunnel->tun_hlen = 0; 307473ab820STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 308fd58156eSPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_IPIP; 309fd58156eSPravin B Shelar return ip_tunnel_init(dev); 3101da177e4SLinus Torvalds } 3111da177e4SLinus Torvalds 312be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[], 313be42da0eSNicolas Dichtel struct ip_tunnel_parm *parms) 314be42da0eSNicolas Dichtel { 315be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms)); 316be42da0eSNicolas Dichtel 317be42da0eSNicolas Dichtel parms->iph.version = 4; 318be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP; 319be42da0eSNicolas Dichtel parms->iph.ihl = 5; 320be42da0eSNicolas Dichtel 321be42da0eSNicolas Dichtel if (!data) 322be42da0eSNicolas Dichtel return; 323be42da0eSNicolas Dichtel 324be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LINK]) 325be42da0eSNicolas Dichtel parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); 326be42da0eSNicolas Dichtel 327be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LOCAL]) 32867b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]); 329be42da0eSNicolas Dichtel 330be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_REMOTE]) 33167b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]); 332be42da0eSNicolas Dichtel 333be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TTL]) { 334be42da0eSNicolas Dichtel parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); 335be42da0eSNicolas Dichtel if (parms->iph.ttl) 336be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 337be42da0eSNicolas Dichtel } 338be42da0eSNicolas Dichtel 339be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TOS]) 340be42da0eSNicolas Dichtel parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); 341be42da0eSNicolas Dichtel 342be42da0eSNicolas Dichtel if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) 343be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 344be42da0eSNicolas Dichtel } 345be42da0eSNicolas Dichtel 346473ab820STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 347473ab820STom Herbert static bool ipip_netlink_encap_parms(struct nlattr *data[], 348473ab820STom Herbert struct ip_tunnel_encap *ipencap) 349473ab820STom Herbert { 350473ab820STom Herbert bool ret = false; 351473ab820STom Herbert 352473ab820STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 353473ab820STom Herbert 354473ab820STom Herbert if (!data) 355473ab820STom Herbert return ret; 356473ab820STom Herbert 357473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_TYPE]) { 358473ab820STom Herbert ret = true; 359473ab820STom Herbert ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); 360473ab820STom Herbert } 361473ab820STom Herbert 362473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_FLAGS]) { 363473ab820STom Herbert ret = true; 364473ab820STom Herbert ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); 365473ab820STom Herbert } 366473ab820STom Herbert 367473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_SPORT]) { 368473ab820STom Herbert ret = true; 3693e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); 370473ab820STom Herbert } 371473ab820STom Herbert 372473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_DPORT]) { 373473ab820STom Herbert ret = true; 3743e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); 375473ab820STom Herbert } 376473ab820STom Herbert 377473ab820STom Herbert return ret; 378473ab820STom Herbert } 379473ab820STom Herbert 380be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev, 381be42da0eSNicolas Dichtel struct nlattr *tb[], struct nlattr *data[]) 382be42da0eSNicolas Dichtel { 383fd58156eSPravin B Shelar struct ip_tunnel_parm p; 384473ab820STom Herbert struct ip_tunnel_encap ipencap; 385473ab820STom Herbert 386473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 387473ab820STom Herbert struct ip_tunnel *t = netdev_priv(dev); 388473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 389473ab820STom Herbert 390473ab820STom Herbert if (err < 0) 391473ab820STom Herbert return err; 392473ab820STom Herbert } 393be42da0eSNicolas Dichtel 394fd58156eSPravin B Shelar ipip_netlink_parms(data, &p); 395fd58156eSPravin B Shelar return ip_tunnel_newlink(dev, tb, &p); 396be42da0eSNicolas Dichtel } 397be42da0eSNicolas Dichtel 398be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 399be42da0eSNicolas Dichtel struct nlattr *data[]) 400be42da0eSNicolas Dichtel { 401be42da0eSNicolas Dichtel struct ip_tunnel_parm p; 402473ab820STom Herbert struct ip_tunnel_encap ipencap; 403473ab820STom Herbert 404473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 405473ab820STom Herbert struct ip_tunnel *t = netdev_priv(dev); 406473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 407473ab820STom Herbert 408473ab820STom Herbert if (err < 0) 409473ab820STom Herbert return err; 410473ab820STom Herbert } 411be42da0eSNicolas Dichtel 412be42da0eSNicolas Dichtel ipip_netlink_parms(data, &p); 413be42da0eSNicolas Dichtel 414be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 415be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 416be42da0eSNicolas Dichtel return -EINVAL; 417be42da0eSNicolas Dichtel 418fd58156eSPravin B Shelar return ip_tunnel_changelink(dev, tb, &p); 419be42da0eSNicolas Dichtel } 420be42da0eSNicolas Dichtel 4210974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev) 4220974658dSNicolas Dichtel { 4230974658dSNicolas Dichtel return 4240974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */ 4250974658dSNicolas Dichtel nla_total_size(4) + 4260974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */ 4270974658dSNicolas Dichtel nla_total_size(4) + 4280974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */ 4290974658dSNicolas Dichtel nla_total_size(4) + 4300974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */ 4310974658dSNicolas Dichtel nla_total_size(1) + 4320974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */ 4330974658dSNicolas Dichtel nla_total_size(1) + 434befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */ 435befe2aa1SNicolas Dichtel nla_total_size(1) + 436473ab820STom Herbert /* IFLA_IPTUN_ENCAP_TYPE */ 437473ab820STom Herbert nla_total_size(2) + 438473ab820STom Herbert /* IFLA_IPTUN_ENCAP_FLAGS */ 439473ab820STom Herbert nla_total_size(2) + 440473ab820STom Herbert /* IFLA_IPTUN_ENCAP_SPORT */ 441473ab820STom Herbert nla_total_size(2) + 442473ab820STom Herbert /* IFLA_IPTUN_ENCAP_DPORT */ 443473ab820STom Herbert nla_total_size(2) + 4440974658dSNicolas Dichtel 0; 4450974658dSNicolas Dichtel } 4460974658dSNicolas Dichtel 4470974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 4480974658dSNicolas Dichtel { 4490974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev); 4500974658dSNicolas Dichtel struct ip_tunnel_parm *parm = &tunnel->parms; 4510974658dSNicolas Dichtel 4520974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 453930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 454930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 4550974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 456befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 457befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 458befe2aa1SNicolas Dichtel !!(parm->iph.frag_off & htons(IP_DF)))) 4590974658dSNicolas Dichtel goto nla_put_failure; 460473ab820STom Herbert 461473ab820STom Herbert if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 462473ab820STom Herbert tunnel->encap.type) || 4633e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 464473ab820STom Herbert tunnel->encap.sport) || 4653e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 466473ab820STom Herbert tunnel->encap.dport) || 467473ab820STom Herbert nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 468e1b2cb65STom Herbert tunnel->encap.flags)) 469473ab820STom Herbert goto nla_put_failure; 470473ab820STom Herbert 4710974658dSNicolas Dichtel return 0; 4720974658dSNicolas Dichtel 4730974658dSNicolas Dichtel nla_put_failure: 4740974658dSNicolas Dichtel return -EMSGSIZE; 4750974658dSNicolas Dichtel } 4760974658dSNicolas Dichtel 477be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 478be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 479be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 480be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 481be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 482be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 483be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 484473ab820STom Herbert [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 485473ab820STom Herbert [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 486473ab820STom Herbert [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 487473ab820STom Herbert [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 488be42da0eSNicolas Dichtel }; 489be42da0eSNicolas Dichtel 4900974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = { 4910974658dSNicolas Dichtel .kind = "ipip", 4920974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX, 493be42da0eSNicolas Dichtel .policy = ipip_policy, 4940974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel), 495be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup, 496be42da0eSNicolas Dichtel .newlink = ipip_newlink, 497be42da0eSNicolas Dichtel .changelink = ipip_changelink, 498fd58156eSPravin B Shelar .dellink = ip_tunnel_dellink, 4990974658dSNicolas Dichtel .get_size = ipip_get_size, 5000974658dSNicolas Dichtel .fill_info = ipip_fill_info, 5011728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 5020974658dSNicolas Dichtel }; 5030974658dSNicolas Dichtel 5046dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = { 5051da177e4SLinus Torvalds .handler = ipip_rcv, 5061da177e4SLinus Torvalds .err_handler = ipip_err, 507d2acc347SHerbert Xu .priority = 1, 5081da177e4SLinus Torvalds }; 5091da177e4SLinus Torvalds 5102c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net) 51110dc4c7bSPavel Emelyanov { 512fd58156eSPravin B Shelar return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); 51310dc4c7bSPavel Emelyanov } 51410dc4c7bSPavel Emelyanov 5152c8c1e72SAlexey Dobriyan static void __net_exit ipip_exit_net(struct net *net) 51610dc4c7bSPavel Emelyanov { 517fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 5186c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipip_link_ops); 51910dc4c7bSPavel Emelyanov } 52010dc4c7bSPavel Emelyanov 52110dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = { 52210dc4c7bSPavel Emelyanov .init = ipip_init_net, 52310dc4c7bSPavel Emelyanov .exit = ipip_exit_net, 52486de8a63SEric W. Biederman .id = &ipip_net_id, 525fd58156eSPravin B Shelar .size = sizeof(struct ip_tunnel_net), 52610dc4c7bSPavel Emelyanov }; 52710dc4c7bSPavel Emelyanov 5281da177e4SLinus Torvalds static int __init ipip_init(void) 5291da177e4SLinus Torvalds { 5301da177e4SLinus Torvalds int err; 5311da177e4SLinus Torvalds 532fd58156eSPravin B Shelar pr_info("ipip: IPv4 over IPv4 tunneling driver\n"); 5331da177e4SLinus Torvalds 53486de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops); 535d5aa407fSAlexey Dobriyan if (err < 0) 536d5aa407fSAlexey Dobriyan return err; 537d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 538d5aa407fSAlexey Dobriyan if (err < 0) { 539058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__); 5400974658dSNicolas Dichtel goto xfrm_tunnel_failed; 541d5aa407fSAlexey Dobriyan } 5420974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops); 5430974658dSNicolas Dichtel if (err < 0) 5440974658dSNicolas Dichtel goto rtnl_link_failed; 5450974658dSNicolas Dichtel 5460974658dSNicolas Dichtel out: 547b9855c54SPavel Emelyanov return err; 5480974658dSNicolas Dichtel 5490974658dSNicolas Dichtel rtnl_link_failed: 5500974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 5510974658dSNicolas Dichtel xfrm_tunnel_failed: 5520974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops); 5530974658dSNicolas Dichtel goto out; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds static void __exit ipip_fini(void) 5571da177e4SLinus Torvalds { 5580974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops); 559c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 560058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__); 5611da177e4SLinus Torvalds 56286de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops); 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds module_init(ipip_init); 5661da177e4SLinus Torvalds module_exit(ipip_fini); 5671da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 568f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip"); 5698909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0"); 570