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> 1141da177e4SLinus Torvalds #include <net/ipip.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 1201da177e4SLinus Torvalds #define HASH_SIZE 16 121d5a0a1e3SAl Viro #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) 1221da177e4SLinus Torvalds 123eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 124eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 125eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 126eccc1bb8Sstephen hemminger 127f99189b1SEric Dumazet static int ipip_net_id __read_mostly; 12810dc4c7bSPavel Emelyanov struct ipip_net { 129b7285b79SEric Dumazet struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; 130b7285b79SEric Dumazet struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; 131b7285b79SEric Dumazet struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; 132b7285b79SEric Dumazet struct ip_tunnel __rcu *tunnels_wc[1]; 133b7285b79SEric Dumazet struct ip_tunnel __rcu **tunnels[4]; 13444d3c299SPavel Emelyanov 135b9855c54SPavel Emelyanov struct net_device *fb_tunnel_dev; 13610dc4c7bSPavel Emelyanov }; 13710dc4c7bSPavel Emelyanov 1383c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev); 1391da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev); 1403c97af99SEric Dumazet static void ipip_dev_free(struct net_device *dev); 1410974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly; 1421da177e4SLinus Torvalds 14387b6d218Sstephen hemminger static struct rtnl_link_stats64 *ipip_get_stats64(struct net_device *dev, 14487b6d218Sstephen hemminger struct rtnl_link_stats64 *tot) 1453c97af99SEric Dumazet { 1463c97af99SEric Dumazet int i; 1473c97af99SEric Dumazet 1483c97af99SEric Dumazet for_each_possible_cpu(i) { 1493c97af99SEric Dumazet const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); 15087b6d218Sstephen hemminger u64 rx_packets, rx_bytes, tx_packets, tx_bytes; 15187b6d218Sstephen hemminger unsigned int start; 1523c97af99SEric Dumazet 15387b6d218Sstephen hemminger do { 15487b6d218Sstephen hemminger start = u64_stats_fetch_begin_bh(&tstats->syncp); 15587b6d218Sstephen hemminger rx_packets = tstats->rx_packets; 15687b6d218Sstephen hemminger tx_packets = tstats->tx_packets; 15787b6d218Sstephen hemminger rx_bytes = tstats->rx_bytes; 15887b6d218Sstephen hemminger tx_bytes = tstats->tx_bytes; 15987b6d218Sstephen hemminger } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); 16087b6d218Sstephen hemminger 16187b6d218Sstephen hemminger tot->rx_packets += rx_packets; 16287b6d218Sstephen hemminger tot->tx_packets += tx_packets; 16387b6d218Sstephen hemminger tot->rx_bytes += rx_bytes; 16487b6d218Sstephen hemminger tot->tx_bytes += tx_bytes; 1653c97af99SEric Dumazet } 16687b6d218Sstephen hemminger 16787b6d218Sstephen hemminger tot->tx_fifo_errors = dev->stats.tx_fifo_errors; 16887b6d218Sstephen hemminger tot->tx_carrier_errors = dev->stats.tx_carrier_errors; 16987b6d218Sstephen hemminger tot->tx_dropped = dev->stats.tx_dropped; 17087b6d218Sstephen hemminger tot->tx_aborted_errors = dev->stats.tx_aborted_errors; 17187b6d218Sstephen hemminger tot->tx_errors = dev->stats.tx_errors; 17287b6d218Sstephen hemminger tot->collisions = dev->stats.collisions; 17387b6d218Sstephen hemminger 17487b6d218Sstephen hemminger return tot; 1753c97af99SEric Dumazet } 1763c97af99SEric Dumazet 177b9fae5c9SPavel Emelyanov static struct ip_tunnel *ipip_tunnel_lookup(struct net *net, 178b9fae5c9SPavel Emelyanov __be32 remote, __be32 local) 1791da177e4SLinus Torvalds { 180b7285b79SEric Dumazet unsigned int h0 = HASH(remote); 181b7285b79SEric Dumazet unsigned int h1 = HASH(local); 1821da177e4SLinus Torvalds struct ip_tunnel *t; 18344d3c299SPavel Emelyanov struct ipip_net *ipn = net_generic(net, ipip_net_id); 1841da177e4SLinus Torvalds 185e086cadcSAmerigo Wang for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1]) 1861da177e4SLinus Torvalds if (local == t->parms.iph.saddr && 1871da177e4SLinus Torvalds remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 1881da177e4SLinus Torvalds return t; 1898f95dd63SEric Dumazet 190e086cadcSAmerigo Wang for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0]) 1911da177e4SLinus Torvalds if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 1921da177e4SLinus Torvalds return t; 1938f95dd63SEric Dumazet 194e086cadcSAmerigo Wang for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1]) 1951da177e4SLinus Torvalds if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) 1961da177e4SLinus Torvalds return t; 1978f95dd63SEric Dumazet 1988f95dd63SEric Dumazet t = rcu_dereference(ipn->tunnels_wc[0]); 1998f95dd63SEric Dumazet if (t && (t->dev->flags&IFF_UP)) 2001da177e4SLinus Torvalds return t; 2011da177e4SLinus Torvalds return NULL; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 204b7285b79SEric Dumazet static struct ip_tunnel __rcu **__ipip_bucket(struct ipip_net *ipn, 205b9fae5c9SPavel Emelyanov struct ip_tunnel_parm *parms) 2061da177e4SLinus Torvalds { 20787d1a164SYOSHIFUJI Hideaki __be32 remote = parms->iph.daddr; 20887d1a164SYOSHIFUJI Hideaki __be32 local = parms->iph.saddr; 209b7285b79SEric Dumazet unsigned int h = 0; 2101da177e4SLinus Torvalds int prio = 0; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (remote) { 2131da177e4SLinus Torvalds prio |= 2; 2141da177e4SLinus Torvalds h ^= HASH(remote); 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds if (local) { 2171da177e4SLinus Torvalds prio |= 1; 2181da177e4SLinus Torvalds h ^= HASH(local); 2191da177e4SLinus Torvalds } 22044d3c299SPavel Emelyanov return &ipn->tunnels[prio][h]; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 223b7285b79SEric Dumazet static inline struct ip_tunnel __rcu **ipip_bucket(struct ipip_net *ipn, 224b9fae5c9SPavel Emelyanov struct ip_tunnel *t) 22587d1a164SYOSHIFUJI Hideaki { 226b9fae5c9SPavel Emelyanov return __ipip_bucket(ipn, &t->parms); 22787d1a164SYOSHIFUJI Hideaki } 2281da177e4SLinus Torvalds 229b9fae5c9SPavel Emelyanov static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t) 2301da177e4SLinus Torvalds { 231b7285b79SEric Dumazet struct ip_tunnel __rcu **tp; 232b7285b79SEric Dumazet struct ip_tunnel *iter; 2331da177e4SLinus Torvalds 234b7285b79SEric Dumazet for (tp = ipip_bucket(ipn, t); 235b7285b79SEric Dumazet (iter = rtnl_dereference(*tp)) != NULL; 236b7285b79SEric Dumazet tp = &iter->next) { 237b7285b79SEric Dumazet if (t == iter) { 238cf778b00SEric Dumazet rcu_assign_pointer(*tp, t->next); 2391da177e4SLinus Torvalds break; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 244b9fae5c9SPavel Emelyanov static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) 2451da177e4SLinus Torvalds { 246b7285b79SEric Dumazet struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t); 2471da177e4SLinus Torvalds 248cf778b00SEric Dumazet rcu_assign_pointer(t->next, rtnl_dereference(*tp)); 249cf778b00SEric Dumazet rcu_assign_pointer(*tp, t); 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 252be42da0eSNicolas Dichtel static int ipip_tunnel_create(struct net_device *dev) 253be42da0eSNicolas Dichtel { 254be42da0eSNicolas Dichtel struct ip_tunnel *t = netdev_priv(dev); 255be42da0eSNicolas Dichtel struct net *net = dev_net(dev); 256be42da0eSNicolas Dichtel struct ipip_net *ipn = net_generic(net, ipip_net_id); 257be42da0eSNicolas Dichtel int err; 258be42da0eSNicolas Dichtel 259be42da0eSNicolas Dichtel err = ipip_tunnel_init(dev); 260be42da0eSNicolas Dichtel if (err < 0) 261be42da0eSNicolas Dichtel goto out; 262be42da0eSNicolas Dichtel 263be42da0eSNicolas Dichtel err = register_netdevice(dev); 264be42da0eSNicolas Dichtel if (err < 0) 265be42da0eSNicolas Dichtel goto out; 266be42da0eSNicolas Dichtel 267be42da0eSNicolas Dichtel strcpy(t->parms.name, dev->name); 268be42da0eSNicolas Dichtel dev->rtnl_link_ops = &ipip_link_ops; 269be42da0eSNicolas Dichtel 270be42da0eSNicolas Dichtel dev_hold(dev); 271be42da0eSNicolas Dichtel ipip_tunnel_link(ipn, t); 272be42da0eSNicolas Dichtel return 0; 273be42da0eSNicolas Dichtel 274be42da0eSNicolas Dichtel out: 275be42da0eSNicolas Dichtel return err; 276be42da0eSNicolas Dichtel } 277be42da0eSNicolas Dichtel 278b9fae5c9SPavel Emelyanov static struct ip_tunnel *ipip_tunnel_locate(struct net *net, 279b9fae5c9SPavel Emelyanov struct ip_tunnel_parm *parms, int create) 2801da177e4SLinus Torvalds { 281d5a0a1e3SAl Viro __be32 remote = parms->iph.daddr; 282d5a0a1e3SAl Viro __be32 local = parms->iph.saddr; 283b7285b79SEric Dumazet struct ip_tunnel *t, *nt; 284b7285b79SEric Dumazet struct ip_tunnel __rcu **tp; 2851da177e4SLinus Torvalds struct net_device *dev; 2861da177e4SLinus Torvalds char name[IFNAMSIZ]; 287b9fae5c9SPavel Emelyanov struct ipip_net *ipn = net_generic(net, ipip_net_id); 2881da177e4SLinus Torvalds 289b7285b79SEric Dumazet for (tp = __ipip_bucket(ipn, parms); 290b7285b79SEric Dumazet (t = rtnl_dereference(*tp)) != NULL; 291b7285b79SEric Dumazet tp = &t->next) { 2921da177e4SLinus Torvalds if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) 2931da177e4SLinus Torvalds return t; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds if (!create) 2961da177e4SLinus Torvalds return NULL; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (parms->name[0]) 2991da177e4SLinus Torvalds strlcpy(name, parms->name, IFNAMSIZ); 30034cc7ba6SPavel Emelyanov else 3013c97af99SEric Dumazet strcpy(name, "tunl%d"); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup); 3041da177e4SLinus Torvalds if (dev == NULL) 3051da177e4SLinus Torvalds return NULL; 3061da177e4SLinus Torvalds 3070a826406SPavel Emelyanov dev_net_set(dev, net); 3080a826406SPavel Emelyanov 3092941a486SPatrick McHardy nt = netdev_priv(dev); 3101da177e4SLinus Torvalds nt->parms = *parms; 3111da177e4SLinus Torvalds 312be42da0eSNicolas Dichtel if (ipip_tunnel_create(dev) < 0) 3133c97af99SEric Dumazet goto failed_free; 31423a12b14SStephen Hemminger 3151da177e4SLinus Torvalds return nt; 3161da177e4SLinus Torvalds 317b37d428bSPavel Emelyanov failed_free: 3183c97af99SEric Dumazet ipip_dev_free(dev); 3191da177e4SLinus Torvalds return NULL; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 322b7285b79SEric Dumazet /* called with RTNL */ 3231da177e4SLinus Torvalds static void ipip_tunnel_uninit(struct net_device *dev) 3241da177e4SLinus Torvalds { 325b9855c54SPavel Emelyanov struct net *net = dev_net(dev); 326b9855c54SPavel Emelyanov struct ipip_net *ipn = net_generic(net, ipip_net_id); 327b9855c54SPavel Emelyanov 328b7285b79SEric Dumazet if (dev == ipn->fb_tunnel_dev) 329a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(ipn->tunnels_wc[0], NULL); 330b7285b79SEric Dumazet else 331b9fae5c9SPavel Emelyanov ipip_tunnel_unlink(ipn, netdev_priv(dev)); 3321da177e4SLinus Torvalds dev_put(dev); 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 335d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds 338071f92d0SRami Rosen /* All the routers (except for Linux) return only 3391da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 3401da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 3411da177e4SLinus Torvalds */ 342b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 34388c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type; 34488c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code; 3451da177e4SLinus Torvalds struct ip_tunnel *t; 346d2acc347SHerbert Xu int err; 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds switch (type) { 3491da177e4SLinus Torvalds default: 3501da177e4SLinus Torvalds case ICMP_PARAMETERPROB: 351d2acc347SHerbert Xu return 0; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds case ICMP_DEST_UNREACH: 3541da177e4SLinus Torvalds switch (code) { 3551da177e4SLinus Torvalds case ICMP_SR_FAILED: 3561da177e4SLinus Torvalds case ICMP_PORT_UNREACH: 3571da177e4SLinus Torvalds /* Impossible event. */ 358d2acc347SHerbert Xu return 0; 3591da177e4SLinus Torvalds default: 3601da177e4SLinus Torvalds /* All others are translated to HOST_UNREACH. 3611da177e4SLinus Torvalds rfc2003 contains "deep thoughts" about NET_UNREACH, 3621da177e4SLinus Torvalds I believe they are just ether pollution. --ANK 3631da177e4SLinus Torvalds */ 3641da177e4SLinus Torvalds break; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds break; 3671da177e4SLinus Torvalds case ICMP_TIME_EXCEEDED: 3681da177e4SLinus Torvalds if (code != ICMP_EXC_TTL) 369d2acc347SHerbert Xu return 0; 3701da177e4SLinus Torvalds break; 37155be7a9cSDavid S. Miller case ICMP_REDIRECT: 37255be7a9cSDavid S. Miller break; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 375d2acc347SHerbert Xu err = -ENOENT; 376cec3ffaeSPavel Emelyanov t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); 37736393395SDavid S. Miller if (t == NULL) 37836393395SDavid S. Miller goto out; 37936393395SDavid S. Miller 38036393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 38136393395SDavid S. Miller ipv4_update_pmtu(skb, dev_net(skb->dev), info, 38236393395SDavid S. Miller t->dev->ifindex, 0, IPPROTO_IPIP, 0); 38336393395SDavid S. Miller err = 0; 38436393395SDavid S. Miller goto out; 38536393395SDavid S. Miller } 38636393395SDavid S. Miller 38755be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) { 38855be7a9cSDavid S. Miller ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0, 38955be7a9cSDavid S. Miller IPPROTO_IPIP, 0); 39055be7a9cSDavid S. Miller err = 0; 39155be7a9cSDavid S. Miller goto out; 39255be7a9cSDavid S. Miller } 39355be7a9cSDavid S. Miller 39436393395SDavid S. Miller if (t->parms.iph.daddr == 0) 3951da177e4SLinus Torvalds goto out; 396d2acc347SHerbert Xu 397d2acc347SHerbert Xu err = 0; 3981da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 3991da177e4SLinus Torvalds goto out; 4001da177e4SLinus Torvalds 40126d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 4021da177e4SLinus Torvalds t->err_count++; 4031da177e4SLinus Torvalds else 4041da177e4SLinus Torvalds t->err_count = 1; 4051da177e4SLinus Torvalds t->err_time = jiffies; 4061da177e4SLinus Torvalds out: 407b0558ef2Sstephen hemminger 408d2acc347SHerbert Xu return err; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds static int ipip_rcv(struct sk_buff *skb) 4121da177e4SLinus Torvalds { 4131da177e4SLinus Torvalds struct ip_tunnel *tunnel; 414eddc9ec5SArnaldo Carvalho de Melo const struct iphdr *iph = ip_hdr(skb); 415eccc1bb8Sstephen hemminger int err; 4161da177e4SLinus Torvalds 4173c97af99SEric Dumazet tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr); 4183c97af99SEric Dumazet if (tunnel != NULL) { 4193c97af99SEric Dumazet struct pcpu_tstats *tstats; 4203c97af99SEric Dumazet 421eccc1bb8Sstephen hemminger if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 422eccc1bb8Sstephen hemminger goto drop; 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds secpath_reset(skb); 4251da177e4SLinus Torvalds 426b0e380b1SArnaldo Carvalho de Melo skb->mac_header = skb->network_header; 427c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 4281da177e4SLinus Torvalds skb->protocol = htons(ETH_P_IP); 4291da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 4301da177e4SLinus Torvalds 431eccc1bb8Sstephen hemminger __skb_tunnel_rx(skb, tunnel->dev); 432eccc1bb8Sstephen hemminger 433eccc1bb8Sstephen hemminger err = IP_ECN_decapsulate(iph, skb); 434eccc1bb8Sstephen hemminger if (unlikely(err)) { 435eccc1bb8Sstephen hemminger if (log_ecn_error) 436eccc1bb8Sstephen hemminger net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", 437eccc1bb8Sstephen hemminger &iph->saddr, iph->tos); 438eccc1bb8Sstephen hemminger if (err > 1) { 439eccc1bb8Sstephen hemminger ++tunnel->dev->stats.rx_frame_errors; 440eccc1bb8Sstephen hemminger ++tunnel->dev->stats.rx_errors; 441eccc1bb8Sstephen hemminger goto drop; 442eccc1bb8Sstephen hemminger } 443eccc1bb8Sstephen hemminger } 444eccc1bb8Sstephen hemminger 4453c97af99SEric Dumazet tstats = this_cpu_ptr(tunnel->dev->tstats); 44687b6d218Sstephen hemminger u64_stats_update_begin(&tstats->syncp); 4473c97af99SEric Dumazet tstats->rx_packets++; 4483c97af99SEric Dumazet tstats->rx_bytes += skb->len; 44987b6d218Sstephen hemminger u64_stats_update_end(&tstats->syncp); 4503c97af99SEric Dumazet 451caf586e5SEric Dumazet netif_rx(skb); 4521da177e4SLinus Torvalds return 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds return -1; 456eccc1bb8Sstephen hemminger 457eccc1bb8Sstephen hemminger drop: 458eccc1bb8Sstephen hemminger kfree_skb(skb); 459eccc1bb8Sstephen hemminger return 0; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds /* 4631da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit() 4641da177e4SLinus Torvalds * and that skb is filled properly by that function. 4651da177e4SLinus Torvalds */ 4661da177e4SLinus Torvalds 4676fef4c0cSStephen Hemminger static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) 4681da177e4SLinus Torvalds { 4692941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 470b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph; 4711da177e4SLinus Torvalds u8 tos = tunnel->parms.iph.tos; 472d5a0a1e3SAl Viro __be16 df = tiph->frag_off; 4731da177e4SLinus Torvalds struct rtable *rt; /* Route to the other host */ 4741da177e4SLinus Torvalds struct net_device *tdev; /* Device to other host */ 475cef401deSEric Dumazet const struct iphdr *old_iph; 4761da177e4SLinus Torvalds struct iphdr *iph; /* Our new IP header */ 477c2636b4dSChuck Lever unsigned int max_headroom; /* The extra header space needed */ 478d5a0a1e3SAl Viro __be32 dst = tiph->daddr; 47931e4543dSDavid S. Miller struct flowi4 fl4; 4801da177e4SLinus Torvalds int mtu; 4818344bfc6SPravin B Shelar int err; 4828344bfc6SPravin B Shelar int pkt_len; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds if (skb->protocol != htons(ETH_P_IP)) 4851da177e4SLinus Torvalds goto tx_error; 486cef401deSEric Dumazet old_iph = ip_hdr(skb); 487cef401deSEric Dumazet 4881da177e4SLinus Torvalds if (tos & 1) 4891da177e4SLinus Torvalds tos = old_iph->tos; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds if (!dst) { 4921da177e4SLinus Torvalds /* NBMA tunnel */ 493511c3f92SEric Dumazet if ((rt = skb_rtable(skb)) == NULL) { 4943c97af99SEric Dumazet dev->stats.tx_fifo_errors++; 4951da177e4SLinus Torvalds goto tx_error; 4961da177e4SLinus Torvalds } 497f8126f1dSDavid S. Miller dst = rt_nexthop(rt, old_iph->daddr); 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 50031e4543dSDavid S. Miller rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, 50178fbfd8aSDavid S. Miller dst, tiph->saddr, 50278fbfd8aSDavid S. Miller 0, 0, 50378fbfd8aSDavid S. Miller IPPROTO_IPIP, RT_TOS(tos), 50478fbfd8aSDavid S. Miller tunnel->parms.link); 505b23dd4feSDavid S. Miller if (IS_ERR(rt)) { 5063c97af99SEric Dumazet dev->stats.tx_carrier_errors++; 5071da177e4SLinus Torvalds goto tx_error_icmp; 5081da177e4SLinus Torvalds } 509d8d1f30bSChangli Gao tdev = rt->dst.dev; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds if (tdev == dev) { 5121da177e4SLinus Torvalds ip_rt_put(rt); 5133c97af99SEric Dumazet dev->stats.collisions++; 5141da177e4SLinus Torvalds goto tx_error; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 51723ca0c98SHerbert Xu df |= old_iph->frag_off & htons(IP_DF); 51823ca0c98SHerbert Xu 51923ca0c98SHerbert Xu if (df) { 520d8d1f30bSChangli Gao mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds if (mtu < 68) { 5233c97af99SEric Dumazet dev->stats.collisions++; 5241da177e4SLinus Torvalds ip_rt_put(rt); 5251da177e4SLinus Torvalds goto tx_error; 5261da177e4SLinus Torvalds } 52723ca0c98SHerbert Xu 528adf30907SEric Dumazet if (skb_dst(skb)) 5296700c270SDavid S. Miller skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); 5301da177e4SLinus Torvalds 53123ca0c98SHerbert Xu if ((old_iph->frag_off & htons(IP_DF)) && 53223ca0c98SHerbert Xu mtu < ntohs(old_iph->tot_len)) { 53323ca0c98SHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 53423ca0c98SHerbert Xu htonl(mtu)); 5351da177e4SLinus Torvalds ip_rt_put(rt); 5361da177e4SLinus Torvalds goto tx_error; 5371da177e4SLinus Torvalds } 53823ca0c98SHerbert Xu } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds if (tunnel->err_count > 0) { 54126d94b46SWei Yongjun if (time_before(jiffies, 54226d94b46SWei Yongjun tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { 5431da177e4SLinus Torvalds tunnel->err_count--; 5441da177e4SLinus Torvalds dst_link_failure(skb); 5451da177e4SLinus Torvalds } else 5461da177e4SLinus Torvalds tunnel->err_count = 0; 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds /* 5501da177e4SLinus Torvalds * Okay, now see if we can stuff it in the buffer as-is. 5511da177e4SLinus Torvalds */ 5521da177e4SLinus Torvalds max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr)); 5531da177e4SLinus Torvalds 554cfbba49dSPatrick McHardy if (skb_headroom(skb) < max_headroom || skb_shared(skb) || 555cfbba49dSPatrick McHardy (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { 5561da177e4SLinus Torvalds struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); 5571da177e4SLinus Torvalds if (!new_skb) { 5581da177e4SLinus Torvalds ip_rt_put(rt); 5593c97af99SEric Dumazet dev->stats.tx_dropped++; 5601da177e4SLinus Torvalds dev_kfree_skb(skb); 5616ed10654SPatrick McHardy return NETDEV_TX_OK; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds if (skb->sk) 5641da177e4SLinus Torvalds skb_set_owner_w(new_skb, skb->sk); 5651da177e4SLinus Torvalds dev_kfree_skb(skb); 5661da177e4SLinus Torvalds skb = new_skb; 567eddc9ec5SArnaldo Carvalho de Melo old_iph = ip_hdr(skb); 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 570*4f3ed920SPravin B Shelar if (!skb->encapsulation) { 571*4f3ed920SPravin B Shelar skb_reset_inner_headers(skb); 572*4f3ed920SPravin B Shelar skb->encapsulation = 1; 573*4f3ed920SPravin B Shelar } 574*4f3ed920SPravin B Shelar if (skb->ip_summed != CHECKSUM_PARTIAL) 575*4f3ed920SPravin B Shelar skb->ip_summed = CHECKSUM_NONE; 576*4f3ed920SPravin B Shelar 577b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header; 578e2d1bca7SArnaldo Carvalho de Melo skb_push(skb, sizeof(struct iphdr)); 579e2d1bca7SArnaldo Carvalho de Melo skb_reset_network_header(skb); 5801da177e4SLinus Torvalds memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 58148d5cad8SPatrick McHardy IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | 58248d5cad8SPatrick McHardy IPSKB_REROUTED); 583adf30907SEric Dumazet skb_dst_drop(skb); 584d8d1f30bSChangli Gao skb_dst_set(skb, &rt->dst); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* 5871da177e4SLinus Torvalds * Push down and install the IPIP header. 5881da177e4SLinus Torvalds */ 5891da177e4SLinus Torvalds 590eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 5911da177e4SLinus Torvalds iph->version = 4; 5921da177e4SLinus Torvalds iph->ihl = sizeof(struct iphdr)>>2; 5931da177e4SLinus Torvalds iph->frag_off = df; 5941da177e4SLinus Torvalds iph->protocol = IPPROTO_IPIP; 5951da177e4SLinus Torvalds iph->tos = INET_ECN_encapsulate(tos, old_iph->tos); 59669458cb1SDavid S. Miller iph->daddr = fl4.daddr; 59769458cb1SDavid S. Miller iph->saddr = fl4.saddr; 5988344bfc6SPravin B Shelar tunnel_ip_select_ident(skb, old_iph, &rt->dst); 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds if ((iph->ttl = tiph->ttl) == 0) 6011da177e4SLinus Torvalds iph->ttl = old_iph->ttl; 6021da177e4SLinus Torvalds 6038344bfc6SPravin B Shelar nf_reset(skb); 6048344bfc6SPravin B Shelar 6058344bfc6SPravin B Shelar pkt_len = skb->len - skb_transport_offset(skb); 6068344bfc6SPravin B Shelar err = ip_local_out(skb); 6078344bfc6SPravin B Shelar if (likely(net_xmit_eval(err) == 0)) { 6088344bfc6SPravin B Shelar struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats); 6098344bfc6SPravin B Shelar 6108344bfc6SPravin B Shelar u64_stats_update_begin(&tstats->syncp); 6118344bfc6SPravin B Shelar tstats->tx_bytes += pkt_len; 6128344bfc6SPravin B Shelar tstats->tx_packets++; 6138344bfc6SPravin B Shelar u64_stats_update_end(&tstats->syncp); 6148344bfc6SPravin B Shelar } else { 6158344bfc6SPravin B Shelar dev->stats.tx_errors++; 6168344bfc6SPravin B Shelar dev->stats.tx_aborted_errors++; 6178344bfc6SPravin B Shelar } 6188344bfc6SPravin B Shelar 6196ed10654SPatrick McHardy return NETDEV_TX_OK; 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds tx_error_icmp: 6221da177e4SLinus Torvalds dst_link_failure(skb); 6231da177e4SLinus Torvalds tx_error: 6243c97af99SEric Dumazet dev->stats.tx_errors++; 6251da177e4SLinus Torvalds dev_kfree_skb(skb); 6266ed10654SPatrick McHardy return NETDEV_TX_OK; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6295533995bSMichal Schmidt static void ipip_tunnel_bind_dev(struct net_device *dev) 6305533995bSMichal Schmidt { 6315533995bSMichal Schmidt struct net_device *tdev = NULL; 6325533995bSMichal Schmidt struct ip_tunnel *tunnel; 633b71d1d42SEric Dumazet const struct iphdr *iph; 6345533995bSMichal Schmidt 6355533995bSMichal Schmidt tunnel = netdev_priv(dev); 6365533995bSMichal Schmidt iph = &tunnel->parms.iph; 6375533995bSMichal Schmidt 6385533995bSMichal Schmidt if (iph->daddr) { 63931e4543dSDavid S. Miller struct rtable *rt; 64031e4543dSDavid S. Miller struct flowi4 fl4; 64131e4543dSDavid S. Miller 64231e4543dSDavid S. Miller rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, 64378fbfd8aSDavid S. Miller iph->daddr, iph->saddr, 64478fbfd8aSDavid S. Miller 0, 0, 64578fbfd8aSDavid S. Miller IPPROTO_IPIP, 64678fbfd8aSDavid S. Miller RT_TOS(iph->tos), 64778fbfd8aSDavid S. Miller tunnel->parms.link); 648b23dd4feSDavid S. Miller if (!IS_ERR(rt)) { 649d8d1f30bSChangli Gao tdev = rt->dst.dev; 6505533995bSMichal Schmidt ip_rt_put(rt); 6515533995bSMichal Schmidt } 6525533995bSMichal Schmidt dev->flags |= IFF_POINTOPOINT; 6535533995bSMichal Schmidt } 6545533995bSMichal Schmidt 6555533995bSMichal Schmidt if (!tdev && tunnel->parms.link) 656b99f0152SPavel Emelyanov tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); 6575533995bSMichal Schmidt 6585533995bSMichal Schmidt if (tdev) { 6595533995bSMichal Schmidt dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); 6605533995bSMichal Schmidt dev->mtu = tdev->mtu - sizeof(struct iphdr); 6615533995bSMichal Schmidt } 6625533995bSMichal Schmidt dev->iflink = tunnel->parms.link; 6635533995bSMichal Schmidt } 6645533995bSMichal Schmidt 665be42da0eSNicolas Dichtel static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) 666be42da0eSNicolas Dichtel { 667be42da0eSNicolas Dichtel struct net *net = dev_net(t->dev); 668be42da0eSNicolas Dichtel struct ipip_net *ipn = net_generic(net, ipip_net_id); 669be42da0eSNicolas Dichtel 670be42da0eSNicolas Dichtel ipip_tunnel_unlink(ipn, t); 671be42da0eSNicolas Dichtel synchronize_net(); 672be42da0eSNicolas Dichtel t->parms.iph.saddr = p->iph.saddr; 673be42da0eSNicolas Dichtel t->parms.iph.daddr = p->iph.daddr; 674be42da0eSNicolas Dichtel memcpy(t->dev->dev_addr, &p->iph.saddr, 4); 675be42da0eSNicolas Dichtel memcpy(t->dev->broadcast, &p->iph.daddr, 4); 676be42da0eSNicolas Dichtel ipip_tunnel_link(ipn, t); 677be42da0eSNicolas Dichtel t->parms.iph.ttl = p->iph.ttl; 678be42da0eSNicolas Dichtel t->parms.iph.tos = p->iph.tos; 679be42da0eSNicolas Dichtel t->parms.iph.frag_off = p->iph.frag_off; 680be42da0eSNicolas Dichtel if (t->parms.link != p->link) { 681be42da0eSNicolas Dichtel t->parms.link = p->link; 682be42da0eSNicolas Dichtel ipip_tunnel_bind_dev(t->dev); 683be42da0eSNicolas Dichtel } 684be42da0eSNicolas Dichtel netdev_state_change(t->dev); 685be42da0eSNicolas Dichtel } 686be42da0eSNicolas Dichtel 6871da177e4SLinus Torvalds static int 6881da177e4SLinus Torvalds ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) 6891da177e4SLinus Torvalds { 6901da177e4SLinus Torvalds int err = 0; 6911da177e4SLinus Torvalds struct ip_tunnel_parm p; 6921da177e4SLinus Torvalds struct ip_tunnel *t; 693b9855c54SPavel Emelyanov struct net *net = dev_net(dev); 694b9855c54SPavel Emelyanov struct ipip_net *ipn = net_generic(net, ipip_net_id); 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds switch (cmd) { 6971da177e4SLinus Torvalds case SIOCGETTUNNEL: 6981da177e4SLinus Torvalds t = NULL; 699b9855c54SPavel Emelyanov if (dev == ipn->fb_tunnel_dev) { 7001da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { 7011da177e4SLinus Torvalds err = -EFAULT; 7021da177e4SLinus Torvalds break; 7031da177e4SLinus Torvalds } 704b9fae5c9SPavel Emelyanov t = ipip_tunnel_locate(net, &p, 0); 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds if (t == NULL) 7072941a486SPatrick McHardy t = netdev_priv(dev); 7081da177e4SLinus Torvalds memcpy(&p, &t->parms, sizeof(p)); 7091da177e4SLinus Torvalds if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 7101da177e4SLinus Torvalds err = -EFAULT; 7111da177e4SLinus Torvalds break; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds case SIOCADDTUNNEL: 7141da177e4SLinus Torvalds case SIOCCHGTUNNEL: 7151da177e4SLinus Torvalds err = -EPERM; 71652e804c6SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 7171da177e4SLinus Torvalds goto done; 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds err = -EFAULT; 7201da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 7211da177e4SLinus Torvalds goto done; 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds err = -EINVAL; 7241da177e4SLinus Torvalds if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || 7251da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) 7261da177e4SLinus Torvalds goto done; 7271da177e4SLinus Torvalds if (p.iph.ttl) 7281da177e4SLinus Torvalds p.iph.frag_off |= htons(IP_DF); 7291da177e4SLinus Torvalds 730b9fae5c9SPavel Emelyanov t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); 7311da177e4SLinus Torvalds 732b9855c54SPavel Emelyanov if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { 7331da177e4SLinus Torvalds if (t != NULL) { 7341da177e4SLinus Torvalds if (t->dev != dev) { 7351da177e4SLinus Torvalds err = -EEXIST; 7361da177e4SLinus Torvalds break; 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds } else { 7391da177e4SLinus Torvalds if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) || 7401da177e4SLinus Torvalds (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) { 7411da177e4SLinus Torvalds err = -EINVAL; 7421da177e4SLinus Torvalds break; 7431da177e4SLinus Torvalds } 7442941a486SPatrick McHardy t = netdev_priv(dev); 745c38cc4b5SNicolas Dichtel } 746c38cc4b5SNicolas Dichtel 747be42da0eSNicolas Dichtel ipip_tunnel_update(t, &p); 7485533995bSMichal Schmidt } 749c38cc4b5SNicolas Dichtel 750c38cc4b5SNicolas Dichtel if (t) { 751c38cc4b5SNicolas Dichtel err = 0; 7521da177e4SLinus Torvalds if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) 7531da177e4SLinus Torvalds err = -EFAULT; 7541da177e4SLinus Torvalds } else 7551da177e4SLinus Torvalds err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); 7561da177e4SLinus Torvalds break; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds case SIOCDELTUNNEL: 7591da177e4SLinus Torvalds err = -EPERM; 76052e804c6SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 7611da177e4SLinus Torvalds goto done; 7621da177e4SLinus Torvalds 763b9855c54SPavel Emelyanov if (dev == ipn->fb_tunnel_dev) { 7641da177e4SLinus Torvalds err = -EFAULT; 7651da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 7661da177e4SLinus Torvalds goto done; 7671da177e4SLinus Torvalds err = -ENOENT; 768b9fae5c9SPavel Emelyanov if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL) 7691da177e4SLinus Torvalds goto done; 7701da177e4SLinus Torvalds err = -EPERM; 771b9855c54SPavel Emelyanov if (t->dev == ipn->fb_tunnel_dev) 7721da177e4SLinus Torvalds goto done; 7731da177e4SLinus Torvalds dev = t->dev; 7741da177e4SLinus Torvalds } 77522f8cde5SStephen Hemminger unregister_netdevice(dev); 77622f8cde5SStephen Hemminger err = 0; 7771da177e4SLinus Torvalds break; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds default: 7801da177e4SLinus Torvalds err = -EINVAL; 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds done: 7841da177e4SLinus Torvalds return err; 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) 7881da177e4SLinus Torvalds { 7891da177e4SLinus Torvalds if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr)) 7901da177e4SLinus Torvalds return -EINVAL; 7911da177e4SLinus Torvalds dev->mtu = new_mtu; 7921da177e4SLinus Torvalds return 0; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds 79523a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = { 79623a12b14SStephen Hemminger .ndo_uninit = ipip_tunnel_uninit, 79723a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit, 79823a12b14SStephen Hemminger .ndo_do_ioctl = ipip_tunnel_ioctl, 79923a12b14SStephen Hemminger .ndo_change_mtu = ipip_tunnel_change_mtu, 80087b6d218Sstephen hemminger .ndo_get_stats64 = ipip_get_stats64, 80123a12b14SStephen Hemminger }; 80223a12b14SStephen Hemminger 8033c97af99SEric Dumazet static void ipip_dev_free(struct net_device *dev) 8043c97af99SEric Dumazet { 8053c97af99SEric Dumazet free_percpu(dev->tstats); 8063c97af99SEric Dumazet free_netdev(dev); 8073c97af99SEric Dumazet } 8083c97af99SEric Dumazet 809c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \ 810c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \ 811c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \ 812c3b89fbbSEric Dumazet NETIF_F_HW_CSUM) 813c3b89fbbSEric Dumazet 8141da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev) 8151da177e4SLinus Torvalds { 81623a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops; 8173c97af99SEric Dumazet dev->destructor = ipip_dev_free; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL; 8201da177e4SLinus Torvalds dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); 82146f25dffSKris Katterjohn dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); 8221da177e4SLinus Torvalds dev->flags = IFF_NOARP; 8231da177e4SLinus Torvalds dev->iflink = 0; 8241da177e4SLinus Torvalds dev->addr_len = 4; 8250a826406SPavel Emelyanov dev->features |= NETIF_F_NETNS_LOCAL; 826153f0943SEric Dumazet dev->features |= NETIF_F_LLTX; 82728e72216SEric Dumazet dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 828c3b89fbbSEric Dumazet 829c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES; 830c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES; 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds 8333c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev) 8341da177e4SLinus Torvalds { 83523a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev); 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds tunnel->dev = dev; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 8401da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 8411da177e4SLinus Torvalds 8425533995bSMichal Schmidt ipip_tunnel_bind_dev(dev); 8433c97af99SEric Dumazet 8443c97af99SEric Dumazet dev->tstats = alloc_percpu(struct pcpu_tstats); 8453c97af99SEric Dumazet if (!dev->tstats) 8463c97af99SEric Dumazet return -ENOMEM; 8473c97af99SEric Dumazet 8483c97af99SEric Dumazet return 0; 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds 851fada5636SEric Dumazet static int __net_init ipip_fb_tunnel_init(struct net_device *dev) 8521da177e4SLinus Torvalds { 8532941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 8541da177e4SLinus Torvalds struct iphdr *iph = &tunnel->parms.iph; 85544d3c299SPavel Emelyanov struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id); 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds tunnel->dev = dev; 8581da177e4SLinus Torvalds strcpy(tunnel->parms.name, dev->name); 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds iph->version = 4; 8611da177e4SLinus Torvalds iph->protocol = IPPROTO_IPIP; 8621da177e4SLinus Torvalds iph->ihl = 5; 8631da177e4SLinus Torvalds 864fada5636SEric Dumazet dev->tstats = alloc_percpu(struct pcpu_tstats); 865fada5636SEric Dumazet if (!dev->tstats) 866fada5636SEric Dumazet return -ENOMEM; 867fada5636SEric Dumazet 8681da177e4SLinus Torvalds dev_hold(dev); 869cf778b00SEric Dumazet rcu_assign_pointer(ipn->tunnels_wc[0], tunnel); 870fada5636SEric Dumazet return 0; 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds 873be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[], 874be42da0eSNicolas Dichtel struct ip_tunnel_parm *parms) 875be42da0eSNicolas Dichtel { 876be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms)); 877be42da0eSNicolas Dichtel 878be42da0eSNicolas Dichtel parms->iph.version = 4; 879be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP; 880be42da0eSNicolas Dichtel parms->iph.ihl = 5; 881be42da0eSNicolas Dichtel 882be42da0eSNicolas Dichtel if (!data) 883be42da0eSNicolas Dichtel return; 884be42da0eSNicolas Dichtel 885be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LINK]) 886be42da0eSNicolas Dichtel parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); 887be42da0eSNicolas Dichtel 888be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LOCAL]) 889fea379b2SNicolas Dichtel parms->iph.saddr = nla_get_be32(data[IFLA_IPTUN_LOCAL]); 890be42da0eSNicolas Dichtel 891be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_REMOTE]) 892fea379b2SNicolas Dichtel parms->iph.daddr = nla_get_be32(data[IFLA_IPTUN_REMOTE]); 893be42da0eSNicolas Dichtel 894be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TTL]) { 895be42da0eSNicolas Dichtel parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); 896be42da0eSNicolas Dichtel if (parms->iph.ttl) 897be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 898be42da0eSNicolas Dichtel } 899be42da0eSNicolas Dichtel 900be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TOS]) 901be42da0eSNicolas Dichtel parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); 902be42da0eSNicolas Dichtel 903be42da0eSNicolas Dichtel if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) 904be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 905be42da0eSNicolas Dichtel } 906be42da0eSNicolas Dichtel 907be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev, 908be42da0eSNicolas Dichtel struct nlattr *tb[], struct nlattr *data[]) 909be42da0eSNicolas Dichtel { 910be42da0eSNicolas Dichtel struct net *net = dev_net(dev); 911be42da0eSNicolas Dichtel struct ip_tunnel *nt; 912be42da0eSNicolas Dichtel 913be42da0eSNicolas Dichtel nt = netdev_priv(dev); 914be42da0eSNicolas Dichtel ipip_netlink_parms(data, &nt->parms); 915be42da0eSNicolas Dichtel 916be42da0eSNicolas Dichtel if (ipip_tunnel_locate(net, &nt->parms, 0)) 917be42da0eSNicolas Dichtel return -EEXIST; 918be42da0eSNicolas Dichtel 919be42da0eSNicolas Dichtel return ipip_tunnel_create(dev); 920be42da0eSNicolas Dichtel } 921be42da0eSNicolas Dichtel 922be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 923be42da0eSNicolas Dichtel struct nlattr *data[]) 924be42da0eSNicolas Dichtel { 925be42da0eSNicolas Dichtel struct ip_tunnel *t; 926be42da0eSNicolas Dichtel struct ip_tunnel_parm p; 927be42da0eSNicolas Dichtel struct net *net = dev_net(dev); 928be42da0eSNicolas Dichtel struct ipip_net *ipn = net_generic(net, ipip_net_id); 929be42da0eSNicolas Dichtel 930be42da0eSNicolas Dichtel if (dev == ipn->fb_tunnel_dev) 931be42da0eSNicolas Dichtel return -EINVAL; 932be42da0eSNicolas Dichtel 933be42da0eSNicolas Dichtel ipip_netlink_parms(data, &p); 934be42da0eSNicolas Dichtel 935be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 936be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 937be42da0eSNicolas Dichtel return -EINVAL; 938be42da0eSNicolas Dichtel 939be42da0eSNicolas Dichtel t = ipip_tunnel_locate(net, &p, 0); 940be42da0eSNicolas Dichtel 941be42da0eSNicolas Dichtel if (t) { 942be42da0eSNicolas Dichtel if (t->dev != dev) 943be42da0eSNicolas Dichtel return -EEXIST; 944be42da0eSNicolas Dichtel } else 945be42da0eSNicolas Dichtel t = netdev_priv(dev); 946be42da0eSNicolas Dichtel 947be42da0eSNicolas Dichtel ipip_tunnel_update(t, &p); 948be42da0eSNicolas Dichtel return 0; 949be42da0eSNicolas Dichtel } 950be42da0eSNicolas Dichtel 9510974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev) 9520974658dSNicolas Dichtel { 9530974658dSNicolas Dichtel return 9540974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */ 9550974658dSNicolas Dichtel nla_total_size(4) + 9560974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */ 9570974658dSNicolas Dichtel nla_total_size(4) + 9580974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */ 9590974658dSNicolas Dichtel nla_total_size(4) + 9600974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */ 9610974658dSNicolas Dichtel nla_total_size(1) + 9620974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */ 9630974658dSNicolas Dichtel nla_total_size(1) + 964befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */ 965befe2aa1SNicolas Dichtel nla_total_size(1) + 9660974658dSNicolas Dichtel 0; 9670974658dSNicolas Dichtel } 9680974658dSNicolas Dichtel 9690974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 9700974658dSNicolas Dichtel { 9710974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev); 9720974658dSNicolas Dichtel struct ip_tunnel_parm *parm = &tunnel->parms; 9730974658dSNicolas Dichtel 9740974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 9750974658dSNicolas Dichtel nla_put_be32(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 9760974658dSNicolas Dichtel nla_put_be32(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 9770974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 978befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 979befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 980befe2aa1SNicolas Dichtel !!(parm->iph.frag_off & htons(IP_DF)))) 9810974658dSNicolas Dichtel goto nla_put_failure; 9820974658dSNicolas Dichtel return 0; 9830974658dSNicolas Dichtel 9840974658dSNicolas Dichtel nla_put_failure: 9850974658dSNicolas Dichtel return -EMSGSIZE; 9860974658dSNicolas Dichtel } 9870974658dSNicolas Dichtel 988be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 989be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 990be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 991be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 992be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 993be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 994be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 995be42da0eSNicolas Dichtel }; 996be42da0eSNicolas Dichtel 9970974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = { 9980974658dSNicolas Dichtel .kind = "ipip", 9990974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX, 1000be42da0eSNicolas Dichtel .policy = ipip_policy, 10010974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel), 1002be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup, 1003be42da0eSNicolas Dichtel .newlink = ipip_newlink, 1004be42da0eSNicolas Dichtel .changelink = ipip_changelink, 10050974658dSNicolas Dichtel .get_size = ipip_get_size, 10060974658dSNicolas Dichtel .fill_info = ipip_fill_info, 10070974658dSNicolas Dichtel }; 10080974658dSNicolas Dichtel 10096dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = { 10101da177e4SLinus Torvalds .handler = ipip_rcv, 10111da177e4SLinus Torvalds .err_handler = ipip_err, 1012d2acc347SHerbert Xu .priority = 1, 10131da177e4SLinus Torvalds }; 10141da177e4SLinus Torvalds 10155747a1aaSStephen Hemminger static const char banner[] __initconst = 10161da177e4SLinus Torvalds KERN_INFO "IPv4 over IPv4 tunneling driver\n"; 10171da177e4SLinus Torvalds 10180694c4c0SEric Dumazet static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) 101944d3c299SPavel Emelyanov { 102044d3c299SPavel Emelyanov int prio; 102144d3c299SPavel Emelyanov 102244d3c299SPavel Emelyanov for (prio = 1; prio < 4; prio++) { 102344d3c299SPavel Emelyanov int h; 102444d3c299SPavel Emelyanov for (h = 0; h < HASH_SIZE; h++) { 1025b7285b79SEric Dumazet struct ip_tunnel *t; 10260694c4c0SEric Dumazet 1027b7285b79SEric Dumazet t = rtnl_dereference(ipn->tunnels[prio][h]); 10280694c4c0SEric Dumazet while (t != NULL) { 10290694c4c0SEric Dumazet unregister_netdevice_queue(t->dev, head); 1030b7285b79SEric Dumazet t = rtnl_dereference(t->next); 10310694c4c0SEric Dumazet } 103244d3c299SPavel Emelyanov } 103344d3c299SPavel Emelyanov } 103444d3c299SPavel Emelyanov } 103544d3c299SPavel Emelyanov 10362c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net) 103710dc4c7bSPavel Emelyanov { 103886de8a63SEric W. Biederman struct ipip_net *ipn = net_generic(net, ipip_net_id); 103972b36015STed Feng struct ip_tunnel *t; 104010dc4c7bSPavel Emelyanov int err; 104110dc4c7bSPavel Emelyanov 104244d3c299SPavel Emelyanov ipn->tunnels[0] = ipn->tunnels_wc; 104344d3c299SPavel Emelyanov ipn->tunnels[1] = ipn->tunnels_l; 104444d3c299SPavel Emelyanov ipn->tunnels[2] = ipn->tunnels_r; 104544d3c299SPavel Emelyanov ipn->tunnels[3] = ipn->tunnels_r_l; 104644d3c299SPavel Emelyanov 1047b9855c54SPavel Emelyanov ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), 1048b9855c54SPavel Emelyanov "tunl0", 1049b9855c54SPavel Emelyanov ipip_tunnel_setup); 1050b9855c54SPavel Emelyanov if (!ipn->fb_tunnel_dev) { 1051b9855c54SPavel Emelyanov err = -ENOMEM; 1052b9855c54SPavel Emelyanov goto err_alloc_dev; 1053b9855c54SPavel Emelyanov } 1054be77e593SAlexey Dobriyan dev_net_set(ipn->fb_tunnel_dev, net); 1055b9855c54SPavel Emelyanov 1056fada5636SEric Dumazet err = ipip_fb_tunnel_init(ipn->fb_tunnel_dev); 1057fada5636SEric Dumazet if (err) 1058fada5636SEric Dumazet goto err_reg_dev; 1059b9855c54SPavel Emelyanov 1060b9855c54SPavel Emelyanov if ((err = register_netdev(ipn->fb_tunnel_dev))) 1061b9855c54SPavel Emelyanov goto err_reg_dev; 1062b9855c54SPavel Emelyanov 106372b36015STed Feng t = netdev_priv(ipn->fb_tunnel_dev); 106472b36015STed Feng 106572b36015STed Feng strcpy(t->parms.name, ipn->fb_tunnel_dev->name); 106610dc4c7bSPavel Emelyanov return 0; 106710dc4c7bSPavel Emelyanov 1068b9855c54SPavel Emelyanov err_reg_dev: 1069fada5636SEric Dumazet ipip_dev_free(ipn->fb_tunnel_dev); 1070b9855c54SPavel Emelyanov err_alloc_dev: 1071b9855c54SPavel Emelyanov /* nothing */ 107210dc4c7bSPavel Emelyanov return err; 107310dc4c7bSPavel Emelyanov } 107410dc4c7bSPavel Emelyanov 10752c8c1e72SAlexey Dobriyan static void __net_exit ipip_exit_net(struct net *net) 107610dc4c7bSPavel Emelyanov { 107786de8a63SEric W. Biederman struct ipip_net *ipn = net_generic(net, ipip_net_id); 10780694c4c0SEric Dumazet LIST_HEAD(list); 107910dc4c7bSPavel Emelyanov 1080b9855c54SPavel Emelyanov rtnl_lock(); 10810694c4c0SEric Dumazet ipip_destroy_tunnels(ipn, &list); 10820694c4c0SEric Dumazet unregister_netdevice_queue(ipn->fb_tunnel_dev, &list); 10830694c4c0SEric Dumazet unregister_netdevice_many(&list); 1084b9855c54SPavel Emelyanov rtnl_unlock(); 108510dc4c7bSPavel Emelyanov } 108610dc4c7bSPavel Emelyanov 108710dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = { 108810dc4c7bSPavel Emelyanov .init = ipip_init_net, 108910dc4c7bSPavel Emelyanov .exit = ipip_exit_net, 109086de8a63SEric W. Biederman .id = &ipip_net_id, 109186de8a63SEric W. Biederman .size = sizeof(struct ipip_net), 109210dc4c7bSPavel Emelyanov }; 109310dc4c7bSPavel Emelyanov 10941da177e4SLinus Torvalds static int __init ipip_init(void) 10951da177e4SLinus Torvalds { 10961da177e4SLinus Torvalds int err; 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds printk(banner); 10991da177e4SLinus Torvalds 110086de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops); 1101d5aa407fSAlexey Dobriyan if (err < 0) 1102d5aa407fSAlexey Dobriyan return err; 1103d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 1104d5aa407fSAlexey Dobriyan if (err < 0) { 1105058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__); 11060974658dSNicolas Dichtel goto xfrm_tunnel_failed; 1107d5aa407fSAlexey Dobriyan } 11080974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops); 11090974658dSNicolas Dichtel if (err < 0) 11100974658dSNicolas Dichtel goto rtnl_link_failed; 11110974658dSNicolas Dichtel 11120974658dSNicolas Dichtel out: 1113b9855c54SPavel Emelyanov return err; 11140974658dSNicolas Dichtel 11150974658dSNicolas Dichtel rtnl_link_failed: 11160974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 11170974658dSNicolas Dichtel xfrm_tunnel_failed: 11180974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops); 11190974658dSNicolas Dichtel goto out; 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds static void __exit ipip_fini(void) 11231da177e4SLinus Torvalds { 11240974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops); 1125c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 1126058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__); 11271da177e4SLinus Torvalds 112886de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops); 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds module_init(ipip_init); 11321da177e4SLinus Torvalds module_exit(ipip_fini); 11331da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 11348909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0"); 1135