162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT) 462306a36Sopenharmony_ci * Linux INET6 implementation 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 862306a36Sopenharmony_ci * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Changes: 1162306a36Sopenharmony_ci * Roger Venning <r.venning@telstra.com>: 6to4 support 1262306a36Sopenharmony_ci * Nate Thompson <nate@thebog.net>: 6to4 support 1362306a36Sopenharmony_ci * Fred Templin <fred.l.templin@boeing.com>: isatap support 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/capability.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/socket.h> 2362306a36Sopenharmony_ci#include <linux/sockios.h> 2462306a36Sopenharmony_ci#include <linux/net.h> 2562306a36Sopenharmony_ci#include <linux/in6.h> 2662306a36Sopenharmony_ci#include <linux/netdevice.h> 2762306a36Sopenharmony_ci#include <linux/if_arp.h> 2862306a36Sopenharmony_ci#include <linux/icmp.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/uaccess.h> 3162306a36Sopenharmony_ci#include <linux/init.h> 3262306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h> 3362306a36Sopenharmony_ci#include <linux/if_ether.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <net/sock.h> 3662306a36Sopenharmony_ci#include <net/snmp.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <net/ipv6.h> 3962306a36Sopenharmony_ci#include <net/protocol.h> 4062306a36Sopenharmony_ci#include <net/transp_v6.h> 4162306a36Sopenharmony_ci#include <net/ip6_fib.h> 4262306a36Sopenharmony_ci#include <net/ip6_route.h> 4362306a36Sopenharmony_ci#include <net/ndisc.h> 4462306a36Sopenharmony_ci#include <net/addrconf.h> 4562306a36Sopenharmony_ci#include <net/ip.h> 4662306a36Sopenharmony_ci#include <net/udp.h> 4762306a36Sopenharmony_ci#include <net/icmp.h> 4862306a36Sopenharmony_ci#include <net/ip_tunnels.h> 4962306a36Sopenharmony_ci#include <net/inet_ecn.h> 5062306a36Sopenharmony_ci#include <net/xfrm.h> 5162306a36Sopenharmony_ci#include <net/dsfield.h> 5262306a36Sopenharmony_ci#include <net/net_namespace.h> 5362306a36Sopenharmony_ci#include <net/netns/generic.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci For comments look at net/ipv4/ip_gre.c --ANK 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define IP6_SIT_HASH_SIZE 16 6262306a36Sopenharmony_ci#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic bool log_ecn_error = true; 6562306a36Sopenharmony_cimodule_param(log_ecn_error, bool, 0644); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int ipip6_tunnel_init(struct net_device *dev); 6962306a36Sopenharmony_cistatic void ipip6_tunnel_setup(struct net_device *dev); 7062306a36Sopenharmony_cistatic void ipip6_dev_free(struct net_device *dev); 7162306a36Sopenharmony_cistatic bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, 7262306a36Sopenharmony_ci __be32 *v4dst); 7362306a36Sopenharmony_cistatic struct rtnl_link_ops sit_link_ops __read_mostly; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic unsigned int sit_net_id __read_mostly; 7662306a36Sopenharmony_cistruct sit_net { 7762306a36Sopenharmony_ci struct ip_tunnel __rcu *tunnels_r_l[IP6_SIT_HASH_SIZE]; 7862306a36Sopenharmony_ci struct ip_tunnel __rcu *tunnels_r[IP6_SIT_HASH_SIZE]; 7962306a36Sopenharmony_ci struct ip_tunnel __rcu *tunnels_l[IP6_SIT_HASH_SIZE]; 8062306a36Sopenharmony_ci struct ip_tunnel __rcu *tunnels_wc[1]; 8162306a36Sopenharmony_ci struct ip_tunnel __rcu **tunnels[4]; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci struct net_device *fb_tunnel_dev; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline struct sit_net *dev_to_sit_net(struct net_device *dev) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return net_generic(t->net, sit_net_id); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * Must be invoked with rcu_read_lock 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistatic struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, 9762306a36Sopenharmony_ci struct net_device *dev, 9862306a36Sopenharmony_ci __be32 remote, __be32 local, 9962306a36Sopenharmony_ci int sifindex) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci unsigned int h0 = HASH(remote); 10262306a36Sopenharmony_ci unsigned int h1 = HASH(local); 10362306a36Sopenharmony_ci struct ip_tunnel *t; 10462306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 10562306a36Sopenharmony_ci int ifindex = dev ? dev->ifindex : 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { 10862306a36Sopenharmony_ci if (local == t->parms.iph.saddr && 10962306a36Sopenharmony_ci remote == t->parms.iph.daddr && 11062306a36Sopenharmony_ci (!dev || !t->parms.link || ifindex == t->parms.link || 11162306a36Sopenharmony_ci sifindex == t->parms.link) && 11262306a36Sopenharmony_ci (t->dev->flags & IFF_UP)) 11362306a36Sopenharmony_ci return t; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { 11662306a36Sopenharmony_ci if (remote == t->parms.iph.daddr && 11762306a36Sopenharmony_ci (!dev || !t->parms.link || ifindex == t->parms.link || 11862306a36Sopenharmony_ci sifindex == t->parms.link) && 11962306a36Sopenharmony_ci (t->dev->flags & IFF_UP)) 12062306a36Sopenharmony_ci return t; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { 12362306a36Sopenharmony_ci if (local == t->parms.iph.saddr && 12462306a36Sopenharmony_ci (!dev || !t->parms.link || ifindex == t->parms.link || 12562306a36Sopenharmony_ci sifindex == t->parms.link) && 12662306a36Sopenharmony_ci (t->dev->flags & IFF_UP)) 12762306a36Sopenharmony_ci return t; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci t = rcu_dereference(sitn->tunnels_wc[0]); 13062306a36Sopenharmony_ci if (t && (t->dev->flags & IFF_UP)) 13162306a36Sopenharmony_ci return t; 13262306a36Sopenharmony_ci return NULL; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, 13662306a36Sopenharmony_ci struct ip_tunnel_parm *parms) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci __be32 remote = parms->iph.daddr; 13962306a36Sopenharmony_ci __be32 local = parms->iph.saddr; 14062306a36Sopenharmony_ci unsigned int h = 0; 14162306a36Sopenharmony_ci int prio = 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (remote) { 14462306a36Sopenharmony_ci prio |= 2; 14562306a36Sopenharmony_ci h ^= HASH(remote); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci if (local) { 14862306a36Sopenharmony_ci prio |= 1; 14962306a36Sopenharmony_ci h ^= HASH(local); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci return &sitn->tunnels[prio][h]; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, 15562306a36Sopenharmony_ci struct ip_tunnel *t) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci return __ipip6_bucket(sitn, &t->parms); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct ip_tunnel __rcu **tp; 16362306a36Sopenharmony_ci struct ip_tunnel *iter; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (tp = ipip6_bucket(sitn, t); 16662306a36Sopenharmony_ci (iter = rtnl_dereference(*tp)) != NULL; 16762306a36Sopenharmony_ci tp = &iter->next) { 16862306a36Sopenharmony_ci if (t == iter) { 16962306a36Sopenharmony_ci rcu_assign_pointer(*tp, t->next); 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci rcu_assign_pointer(t->next, rtnl_dereference(*tp)); 18062306a36Sopenharmony_ci rcu_assign_pointer(*tp, t); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 18662306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (dev == sitn->fb_tunnel_dev || !sitn->fb_tunnel_dev) { 18962306a36Sopenharmony_ci ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0); 19062306a36Sopenharmony_ci t->ip6rd.relay_prefix = 0; 19162306a36Sopenharmony_ci t->ip6rd.prefixlen = 16; 19262306a36Sopenharmony_ci t->ip6rd.relay_prefixlen = 0; 19362306a36Sopenharmony_ci } else { 19462306a36Sopenharmony_ci struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev); 19562306a36Sopenharmony_ci memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd)); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int ipip6_tunnel_create(struct net_device *dev) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 20362306a36Sopenharmony_ci struct net *net = dev_net(dev); 20462306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 20562306a36Sopenharmony_ci int err; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci __dev_addr_set(dev, &t->parms.iph.saddr, 4); 20862306a36Sopenharmony_ci memcpy(dev->broadcast, &t->parms.iph.daddr, 4); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if ((__force u16)t->parms.i_flags & SIT_ISATAP) 21162306a36Sopenharmony_ci dev->priv_flags |= IFF_ISATAP; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci dev->rtnl_link_ops = &sit_link_ops; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci err = register_netdevice(dev); 21662306a36Sopenharmony_ci if (err < 0) 21762306a36Sopenharmony_ci goto out; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ipip6_tunnel_clone_6rd(dev, sitn); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ipip6_tunnel_link(sitn, t); 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ciout: 22562306a36Sopenharmony_ci return err; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic struct ip_tunnel *ipip6_tunnel_locate(struct net *net, 22962306a36Sopenharmony_ci struct ip_tunnel_parm *parms, int create) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci __be32 remote = parms->iph.daddr; 23262306a36Sopenharmony_ci __be32 local = parms->iph.saddr; 23362306a36Sopenharmony_ci struct ip_tunnel *t, *nt; 23462306a36Sopenharmony_ci struct ip_tunnel __rcu **tp; 23562306a36Sopenharmony_ci struct net_device *dev; 23662306a36Sopenharmony_ci char name[IFNAMSIZ]; 23762306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (tp = __ipip6_bucket(sitn, parms); 24062306a36Sopenharmony_ci (t = rtnl_dereference(*tp)) != NULL; 24162306a36Sopenharmony_ci tp = &t->next) { 24262306a36Sopenharmony_ci if (local == t->parms.iph.saddr && 24362306a36Sopenharmony_ci remote == t->parms.iph.daddr && 24462306a36Sopenharmony_ci parms->link == t->parms.link) { 24562306a36Sopenharmony_ci if (create) 24662306a36Sopenharmony_ci return NULL; 24762306a36Sopenharmony_ci else 24862306a36Sopenharmony_ci return t; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci if (!create) 25262306a36Sopenharmony_ci goto failed; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (parms->name[0]) { 25562306a36Sopenharmony_ci if (!dev_valid_name(parms->name)) 25662306a36Sopenharmony_ci goto failed; 25762306a36Sopenharmony_ci strscpy(name, parms->name, IFNAMSIZ); 25862306a36Sopenharmony_ci } else { 25962306a36Sopenharmony_ci strcpy(name, "sit%d"); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, 26262306a36Sopenharmony_ci ipip6_tunnel_setup); 26362306a36Sopenharmony_ci if (!dev) 26462306a36Sopenharmony_ci return NULL; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dev_net_set(dev, net); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci nt = netdev_priv(dev); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci nt->parms = *parms; 27162306a36Sopenharmony_ci if (ipip6_tunnel_create(dev) < 0) 27262306a36Sopenharmony_ci goto failed_free; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!parms->name[0]) 27562306a36Sopenharmony_ci strcpy(parms->name, dev->name); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return nt; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cifailed_free: 28062306a36Sopenharmony_ci free_netdev(dev); 28162306a36Sopenharmony_cifailed: 28262306a36Sopenharmony_ci return NULL; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#define for_each_prl_rcu(start) \ 28662306a36Sopenharmony_ci for (prl = rcu_dereference(start); \ 28762306a36Sopenharmony_ci prl; \ 28862306a36Sopenharmony_ci prl = rcu_dereference(prl->next)) 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic struct ip_tunnel_prl_entry * 29162306a36Sopenharmony_ci__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct ip_tunnel_prl_entry *prl; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci for_each_prl_rcu(t->prl) 29662306a36Sopenharmony_ci if (prl->addr == addr) 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci return prl; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __user *a) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 30562306a36Sopenharmony_ci struct ip_tunnel_prl kprl, *kp; 30662306a36Sopenharmony_ci struct ip_tunnel_prl_entry *prl; 30762306a36Sopenharmony_ci unsigned int cmax, c = 0, ca, len; 30862306a36Sopenharmony_ci int ret = 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) 31162306a36Sopenharmony_ci return -EINVAL; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (copy_from_user(&kprl, a, sizeof(kprl))) 31462306a36Sopenharmony_ci return -EFAULT; 31562306a36Sopenharmony_ci cmax = kprl.datalen / sizeof(kprl); 31662306a36Sopenharmony_ci if (cmax > 1 && kprl.addr != htonl(INADDR_ANY)) 31762306a36Sopenharmony_ci cmax = 1; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* For simple GET or for root users, 32062306a36Sopenharmony_ci * we try harder to allocate. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ? 32362306a36Sopenharmony_ci kcalloc(cmax, sizeof(*kp), GFP_KERNEL_ACCOUNT | __GFP_NOWARN) : 32462306a36Sopenharmony_ci NULL; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ca = min(t->prl_count, cmax); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!kp) { 32962306a36Sopenharmony_ci /* We don't try hard to allocate much memory for 33062306a36Sopenharmony_ci * non-root users. 33162306a36Sopenharmony_ci * For root users, retry allocating enough memory for 33262306a36Sopenharmony_ci * the answer. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC | __GFP_ACCOUNT | 33562306a36Sopenharmony_ci __GFP_NOWARN); 33662306a36Sopenharmony_ci if (!kp) { 33762306a36Sopenharmony_ci ret = -ENOMEM; 33862306a36Sopenharmony_ci goto out; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci rcu_read_lock(); 34362306a36Sopenharmony_ci for_each_prl_rcu(t->prl) { 34462306a36Sopenharmony_ci if (c >= cmax) 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) 34762306a36Sopenharmony_ci continue; 34862306a36Sopenharmony_ci kp[c].addr = prl->addr; 34962306a36Sopenharmony_ci kp[c].flags = prl->flags; 35062306a36Sopenharmony_ci c++; 35162306a36Sopenharmony_ci if (kprl.addr != htonl(INADDR_ANY)) 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci rcu_read_unlock(); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci len = sizeof(*kp) * c; 35862306a36Sopenharmony_ci ret = 0; 35962306a36Sopenharmony_ci if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen)) 36062306a36Sopenharmony_ci ret = -EFAULT; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci kfree(kp); 36362306a36Sopenharmony_ciout: 36462306a36Sopenharmony_ci return ret; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int 36862306a36Sopenharmony_ciipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct ip_tunnel_prl_entry *p; 37162306a36Sopenharmony_ci int err = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (a->addr == htonl(INADDR_ANY)) 37462306a36Sopenharmony_ci return -EINVAL; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ASSERT_RTNL(); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { 37962306a36Sopenharmony_ci if (p->addr == a->addr) { 38062306a36Sopenharmony_ci if (chg) { 38162306a36Sopenharmony_ci p->flags = a->flags; 38262306a36Sopenharmony_ci goto out; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci err = -EEXIST; 38562306a36Sopenharmony_ci goto out; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (chg) { 39062306a36Sopenharmony_ci err = -ENXIO; 39162306a36Sopenharmony_ci goto out; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); 39562306a36Sopenharmony_ci if (!p) { 39662306a36Sopenharmony_ci err = -ENOBUFS; 39762306a36Sopenharmony_ci goto out; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci p->next = t->prl; 40162306a36Sopenharmony_ci p->addr = a->addr; 40262306a36Sopenharmony_ci p->flags = a->flags; 40362306a36Sopenharmony_ci t->prl_count++; 40462306a36Sopenharmony_ci rcu_assign_pointer(t->prl, p); 40562306a36Sopenharmony_ciout: 40662306a36Sopenharmony_ci return err; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void prl_list_destroy_rcu(struct rcu_head *head) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct ip_tunnel_prl_entry *p, *n; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); 41462306a36Sopenharmony_ci do { 41562306a36Sopenharmony_ci n = rcu_dereference_protected(p->next, 1); 41662306a36Sopenharmony_ci kfree(p); 41762306a36Sopenharmony_ci p = n; 41862306a36Sopenharmony_ci } while (p); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int 42262306a36Sopenharmony_ciipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct ip_tunnel_prl_entry *x; 42562306a36Sopenharmony_ci struct ip_tunnel_prl_entry __rcu **p; 42662306a36Sopenharmony_ci int err = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ASSERT_RTNL(); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (a && a->addr != htonl(INADDR_ANY)) { 43162306a36Sopenharmony_ci for (p = &t->prl; 43262306a36Sopenharmony_ci (x = rtnl_dereference(*p)) != NULL; 43362306a36Sopenharmony_ci p = &x->next) { 43462306a36Sopenharmony_ci if (x->addr == a->addr) { 43562306a36Sopenharmony_ci *p = x->next; 43662306a36Sopenharmony_ci kfree_rcu(x, rcu_head); 43762306a36Sopenharmony_ci t->prl_count--; 43862306a36Sopenharmony_ci goto out; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci err = -ENXIO; 44262306a36Sopenharmony_ci } else { 44362306a36Sopenharmony_ci x = rtnl_dereference(t->prl); 44462306a36Sopenharmony_ci if (x) { 44562306a36Sopenharmony_ci t->prl_count = 0; 44662306a36Sopenharmony_ci call_rcu(&x->rcu_head, prl_list_destroy_rcu); 44762306a36Sopenharmony_ci t->prl = NULL; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ciout: 45162306a36Sopenharmony_ci return err; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int ipip6_tunnel_prl_ctl(struct net_device *dev, 45562306a36Sopenharmony_ci struct ip_tunnel_prl __user *data, int cmd) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 45862306a36Sopenharmony_ci struct ip_tunnel_prl prl; 45962306a36Sopenharmony_ci int err; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) 46262306a36Sopenharmony_ci return -EPERM; 46362306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) 46462306a36Sopenharmony_ci return -EINVAL; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (copy_from_user(&prl, data, sizeof(prl))) 46762306a36Sopenharmony_ci return -EFAULT; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci switch (cmd) { 47062306a36Sopenharmony_ci case SIOCDELPRL: 47162306a36Sopenharmony_ci err = ipip6_tunnel_del_prl(t, &prl); 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci case SIOCADDPRL: 47462306a36Sopenharmony_ci case SIOCCHGPRL: 47562306a36Sopenharmony_ci err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci dst_cache_reset(&t->dst_cache); 47962306a36Sopenharmony_ci netdev_state_change(dev); 48062306a36Sopenharmony_ci return err; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int 48462306a36Sopenharmony_ciisatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct ip_tunnel_prl_entry *p; 48762306a36Sopenharmony_ci int ok = 1; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci rcu_read_lock(); 49062306a36Sopenharmony_ci p = __ipip6_tunnel_locate_prl(t, iph->saddr); 49162306a36Sopenharmony_ci if (p) { 49262306a36Sopenharmony_ci if (p->flags & PRL_DEFAULT) 49362306a36Sopenharmony_ci skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; 49462306a36Sopenharmony_ci else 49562306a36Sopenharmony_ci skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; 49662306a36Sopenharmony_ci } else { 49762306a36Sopenharmony_ci const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (ipv6_addr_is_isatap(addr6) && 50062306a36Sopenharmony_ci (addr6->s6_addr32[3] == iph->saddr) && 50162306a36Sopenharmony_ci ipv6_chk_prefix(addr6, t->dev)) 50262306a36Sopenharmony_ci skb->ndisc_nodetype = NDISC_NODETYPE_HOST; 50362306a36Sopenharmony_ci else 50462306a36Sopenharmony_ci ok = 0; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci rcu_read_unlock(); 50762306a36Sopenharmony_ci return ok; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void ipip6_tunnel_uninit(struct net_device *dev) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 51362306a36Sopenharmony_ci struct sit_net *sitn = net_generic(tunnel->net, sit_net_id); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (dev == sitn->fb_tunnel_dev) { 51662306a36Sopenharmony_ci RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL); 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci ipip6_tunnel_unlink(sitn, tunnel); 51962306a36Sopenharmony_ci ipip6_tunnel_del_prl(tunnel, NULL); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci dst_cache_reset(&tunnel->dst_cache); 52262306a36Sopenharmony_ci netdev_put(dev, &tunnel->dev_tracker); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int ipip6_err(struct sk_buff *skb, u32 info) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 52862306a36Sopenharmony_ci const int type = icmp_hdr(skb)->type; 52962306a36Sopenharmony_ci const int code = icmp_hdr(skb)->code; 53062306a36Sopenharmony_ci unsigned int data_len = 0; 53162306a36Sopenharmony_ci struct ip_tunnel *t; 53262306a36Sopenharmony_ci int sifindex; 53362306a36Sopenharmony_ci int err; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci switch (type) { 53662306a36Sopenharmony_ci default: 53762306a36Sopenharmony_ci case ICMP_PARAMETERPROB: 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci case ICMP_DEST_UNREACH: 54162306a36Sopenharmony_ci switch (code) { 54262306a36Sopenharmony_ci case ICMP_SR_FAILED: 54362306a36Sopenharmony_ci /* Impossible event. */ 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci default: 54662306a36Sopenharmony_ci /* All others are translated to HOST_UNREACH. 54762306a36Sopenharmony_ci rfc2003 contains "deep thoughts" about NET_UNREACH, 54862306a36Sopenharmony_ci I believe they are just ether pollution. --ANK 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case ICMP_TIME_EXCEEDED: 55462306a36Sopenharmony_ci if (code != ICMP_EXC_TTL) 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci case ICMP_REDIRECT: 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci err = -ENOENT; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0; 56562306a36Sopenharmony_ci t = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, 56662306a36Sopenharmony_ci iph->daddr, iph->saddr, sifindex); 56762306a36Sopenharmony_ci if (!t) 56862306a36Sopenharmony_ci goto out; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 57162306a36Sopenharmony_ci ipv4_update_pmtu(skb, dev_net(skb->dev), info, 57262306a36Sopenharmony_ci t->parms.link, iph->protocol); 57362306a36Sopenharmony_ci err = 0; 57462306a36Sopenharmony_ci goto out; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci if (type == ICMP_REDIRECT) { 57762306a36Sopenharmony_ci ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 57862306a36Sopenharmony_ci iph->protocol); 57962306a36Sopenharmony_ci err = 0; 58062306a36Sopenharmony_ci goto out; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci err = 0; 58462306a36Sopenharmony_ci if (__in6_dev_get(skb->dev) && 58562306a36Sopenharmony_ci !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) 58662306a36Sopenharmony_ci goto out; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (t->parms.iph.daddr == 0) 58962306a36Sopenharmony_ci goto out; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 59262306a36Sopenharmony_ci goto out; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 59562306a36Sopenharmony_ci t->err_count++; 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci t->err_count = 1; 59862306a36Sopenharmony_ci t->err_time = jiffies; 59962306a36Sopenharmony_ciout: 60062306a36Sopenharmony_ci return err; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr, 60462306a36Sopenharmony_ci const struct in6_addr *v6addr) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci __be32 v4embed = 0; 60762306a36Sopenharmony_ci if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed) 60862306a36Sopenharmony_ci return true; 60962306a36Sopenharmony_ci return false; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* Checks if an address matches an address on the tunnel interface. 61362306a36Sopenharmony_ci * Used to detect the NAT of proto 41 packets and let them pass spoofing test. 61462306a36Sopenharmony_ci * Long story: 61562306a36Sopenharmony_ci * This function is called after we considered the packet as spoofed 61662306a36Sopenharmony_ci * in is_spoofed_6rd. 61762306a36Sopenharmony_ci * We may have a router that is doing NAT for proto 41 packets 61862306a36Sopenharmony_ci * for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb 61962306a36Sopenharmony_ci * will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd 62062306a36Sopenharmony_ci * function will return true, dropping the packet. 62162306a36Sopenharmony_ci * But, we can still check if is spoofed against the IP 62262306a36Sopenharmony_ci * addresses associated with the interface. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_cistatic bool only_dnatted(const struct ip_tunnel *tunnel, 62562306a36Sopenharmony_ci const struct in6_addr *v6dst) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci int prefix_len; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 63062306a36Sopenharmony_ci prefix_len = tunnel->ip6rd.prefixlen + 32 63162306a36Sopenharmony_ci - tunnel->ip6rd.relay_prefixlen; 63262306a36Sopenharmony_ci#else 63362306a36Sopenharmony_ci prefix_len = 48; 63462306a36Sopenharmony_ci#endif 63562306a36Sopenharmony_ci return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/* Returns true if a packet is spoofed */ 63962306a36Sopenharmony_cistatic bool packet_is_spoofed(struct sk_buff *skb, 64062306a36Sopenharmony_ci const struct iphdr *iph, 64162306a36Sopenharmony_ci struct ip_tunnel *tunnel) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci const struct ipv6hdr *ipv6h; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (tunnel->dev->priv_flags & IFF_ISATAP) { 64662306a36Sopenharmony_ci if (!isatap_chksrc(skb, iph, tunnel)) 64762306a36Sopenharmony_ci return true; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return false; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (tunnel->dev->flags & IFF_POINTOPOINT) 65362306a36Sopenharmony_ci return false; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ipv6h = ipv6_hdr(skb); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) { 65862306a36Sopenharmony_ci net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n", 65962306a36Sopenharmony_ci &iph->saddr, &ipv6h->saddr, 66062306a36Sopenharmony_ci &iph->daddr, &ipv6h->daddr); 66162306a36Sopenharmony_ci return true; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr))) 66562306a36Sopenharmony_ci return false; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (only_dnatted(tunnel, &ipv6h->daddr)) 66862306a36Sopenharmony_ci return false; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n", 67162306a36Sopenharmony_ci &iph->saddr, &ipv6h->saddr, 67262306a36Sopenharmony_ci &iph->daddr, &ipv6h->daddr); 67362306a36Sopenharmony_ci return true; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int ipip6_rcv(struct sk_buff *skb) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci const struct iphdr *iph = ip_hdr(skb); 67962306a36Sopenharmony_ci struct ip_tunnel *tunnel; 68062306a36Sopenharmony_ci int sifindex; 68162306a36Sopenharmony_ci int err; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0; 68462306a36Sopenharmony_ci tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, 68562306a36Sopenharmony_ci iph->saddr, iph->daddr, sifindex); 68662306a36Sopenharmony_ci if (tunnel) { 68762306a36Sopenharmony_ci if (tunnel->parms.iph.protocol != IPPROTO_IPV6 && 68862306a36Sopenharmony_ci tunnel->parms.iph.protocol != 0) 68962306a36Sopenharmony_ci goto out; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci skb->mac_header = skb->network_header; 69262306a36Sopenharmony_ci skb_reset_network_header(skb); 69362306a36Sopenharmony_ci IPCB(skb)->flags = 0; 69462306a36Sopenharmony_ci skb->dev = tunnel->dev; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (packet_is_spoofed(skb, iph, tunnel)) { 69762306a36Sopenharmony_ci DEV_STATS_INC(tunnel->dev, rx_errors); 69862306a36Sopenharmony_ci goto out; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6), 70262306a36Sopenharmony_ci !net_eq(tunnel->net, dev_net(tunnel->dev)))) 70362306a36Sopenharmony_ci goto out; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* skb can be uncloned in iptunnel_pull_header, so 70662306a36Sopenharmony_ci * old iph is no longer valid 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci iph = (const struct iphdr *)skb_mac_header(skb); 70962306a36Sopenharmony_ci skb_reset_mac_header(skb); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci err = IP_ECN_decapsulate(iph, skb); 71262306a36Sopenharmony_ci if (unlikely(err)) { 71362306a36Sopenharmony_ci if (log_ecn_error) 71462306a36Sopenharmony_ci net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", 71562306a36Sopenharmony_ci &iph->saddr, iph->tos); 71662306a36Sopenharmony_ci if (err > 1) { 71762306a36Sopenharmony_ci DEV_STATS_INC(tunnel->dev, rx_frame_errors); 71862306a36Sopenharmony_ci DEV_STATS_INC(tunnel->dev, rx_errors); 71962306a36Sopenharmony_ci goto out; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci dev_sw_netstats_rx_add(tunnel->dev, skb->len); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci netif_rx(skb); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* no tunnel matched, let upstream know, ipsec may handle it */ 73162306a36Sopenharmony_ci return 1; 73262306a36Sopenharmony_ciout: 73362306a36Sopenharmony_ci kfree_skb(skb); 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic const struct tnl_ptk_info ipip_tpi = { 73862306a36Sopenharmony_ci /* no tunnel info required for ipip. */ 73962306a36Sopenharmony_ci .proto = htons(ETH_P_IP), 74062306a36Sopenharmony_ci}; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 74362306a36Sopenharmony_cistatic const struct tnl_ptk_info mplsip_tpi = { 74462306a36Sopenharmony_ci /* no tunnel info required for mplsip. */ 74562306a36Sopenharmony_ci .proto = htons(ETH_P_MPLS_UC), 74662306a36Sopenharmony_ci}; 74762306a36Sopenharmony_ci#endif 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci const struct iphdr *iph; 75262306a36Sopenharmony_ci struct ip_tunnel *tunnel; 75362306a36Sopenharmony_ci int sifindex; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci iph = ip_hdr(skb); 75862306a36Sopenharmony_ci tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, 75962306a36Sopenharmony_ci iph->saddr, iph->daddr, sifindex); 76062306a36Sopenharmony_ci if (tunnel) { 76162306a36Sopenharmony_ci const struct tnl_ptk_info *tpi; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (tunnel->parms.iph.protocol != ipproto && 76462306a36Sopenharmony_ci tunnel->parms.iph.protocol != 0) 76562306a36Sopenharmony_ci goto drop; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 76862306a36Sopenharmony_ci goto drop; 76962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 77062306a36Sopenharmony_ci if (ipproto == IPPROTO_MPLS) 77162306a36Sopenharmony_ci tpi = &mplsip_tpi; 77262306a36Sopenharmony_ci else 77362306a36Sopenharmony_ci#endif 77462306a36Sopenharmony_ci tpi = &ipip_tpi; 77562306a36Sopenharmony_ci if (iptunnel_pull_header(skb, 0, tpi->proto, false)) 77662306a36Sopenharmony_ci goto drop; 77762306a36Sopenharmony_ci skb_reset_mac_header(skb); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 1; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cidrop: 78562306a36Sopenharmony_ci kfree_skb(skb); 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int ipip_rcv(struct sk_buff *skb) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci return sit_tunnel_rcv(skb, IPPROTO_IPIP); 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 79562306a36Sopenharmony_cistatic int mplsip_rcv(struct sk_buff *skb) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci return sit_tunnel_rcv(skb, IPPROTO_MPLS); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci#endif 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/* 80262306a36Sopenharmony_ci * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function 80362306a36Sopenharmony_ci * stores the embedded IPv4 address in v4dst and returns true. 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_cistatic bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, 80662306a36Sopenharmony_ci __be32 *v4dst) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 80962306a36Sopenharmony_ci if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, 81062306a36Sopenharmony_ci tunnel->ip6rd.prefixlen)) { 81162306a36Sopenharmony_ci unsigned int pbw0, pbi0; 81262306a36Sopenharmony_ci int pbi1; 81362306a36Sopenharmony_ci u32 d; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci pbw0 = tunnel->ip6rd.prefixlen >> 5; 81662306a36Sopenharmony_ci pbi0 = tunnel->ip6rd.prefixlen & 0x1f; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci d = tunnel->ip6rd.relay_prefixlen < 32 ? 81962306a36Sopenharmony_ci (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >> 82062306a36Sopenharmony_ci tunnel->ip6rd.relay_prefixlen : 0; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen; 82362306a36Sopenharmony_ci if (pbi1 > 0) 82462306a36Sopenharmony_ci d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> 82562306a36Sopenharmony_ci (32 - pbi1); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci *v4dst = tunnel->ip6rd.relay_prefix | htonl(d); 82862306a36Sopenharmony_ci return true; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci#else 83162306a36Sopenharmony_ci if (v6dst->s6_addr16[0] == htons(0x2002)) { 83262306a36Sopenharmony_ci /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ 83362306a36Sopenharmony_ci memcpy(v4dst, &v6dst->s6_addr16[1], 4); 83462306a36Sopenharmony_ci return true; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci#endif 83762306a36Sopenharmony_ci return false; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic inline __be32 try_6rd(struct ip_tunnel *tunnel, 84162306a36Sopenharmony_ci const struct in6_addr *v6dst) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci __be32 dst = 0; 84462306a36Sopenharmony_ci check_6rd(tunnel, v6dst, &dst); 84562306a36Sopenharmony_ci return dst; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci/* 84962306a36Sopenharmony_ci * This function assumes it is being called from dev_queue_xmit() 85062306a36Sopenharmony_ci * and that skb is filled properly by that function. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, 85462306a36Sopenharmony_ci struct net_device *dev) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 85762306a36Sopenharmony_ci const struct iphdr *tiph = &tunnel->parms.iph; 85862306a36Sopenharmony_ci const struct ipv6hdr *iph6 = ipv6_hdr(skb); 85962306a36Sopenharmony_ci u8 tos = tunnel->parms.iph.tos; 86062306a36Sopenharmony_ci __be16 df = tiph->frag_off; 86162306a36Sopenharmony_ci struct rtable *rt; /* Route to the other host */ 86262306a36Sopenharmony_ci struct net_device *tdev; /* Device to other host */ 86362306a36Sopenharmony_ci unsigned int max_headroom; /* The extra header space needed */ 86462306a36Sopenharmony_ci __be32 dst = tiph->daddr; 86562306a36Sopenharmony_ci struct flowi4 fl4; 86662306a36Sopenharmony_ci int mtu; 86762306a36Sopenharmony_ci const struct in6_addr *addr6; 86862306a36Sopenharmony_ci int addr_type; 86962306a36Sopenharmony_ci u8 ttl; 87062306a36Sopenharmony_ci u8 protocol = IPPROTO_IPV6; 87162306a36Sopenharmony_ci int t_hlen = tunnel->hlen + sizeof(struct iphdr); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (tos == 1) 87462306a36Sopenharmony_ci tos = ipv6_get_dsfield(iph6); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* ISATAP (RFC4214) - must come before 6to4 */ 87762306a36Sopenharmony_ci if (dev->priv_flags & IFF_ISATAP) { 87862306a36Sopenharmony_ci struct neighbour *neigh = NULL; 87962306a36Sopenharmony_ci bool do_tx_error = false; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (skb_dst(skb)) 88262306a36Sopenharmony_ci neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (!neigh) { 88562306a36Sopenharmony_ci net_dbg_ratelimited("nexthop == NULL\n"); 88662306a36Sopenharmony_ci goto tx_error; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci addr6 = (const struct in6_addr *)&neigh->primary_key; 89062306a36Sopenharmony_ci addr_type = ipv6_addr_type(addr6); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if ((addr_type & IPV6_ADDR_UNICAST) && 89362306a36Sopenharmony_ci ipv6_addr_is_isatap(addr6)) 89462306a36Sopenharmony_ci dst = addr6->s6_addr32[3]; 89562306a36Sopenharmony_ci else 89662306a36Sopenharmony_ci do_tx_error = true; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci neigh_release(neigh); 89962306a36Sopenharmony_ci if (do_tx_error) 90062306a36Sopenharmony_ci goto tx_error; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!dst) 90462306a36Sopenharmony_ci dst = try_6rd(tunnel, &iph6->daddr); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (!dst) { 90762306a36Sopenharmony_ci struct neighbour *neigh = NULL; 90862306a36Sopenharmony_ci bool do_tx_error = false; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (skb_dst(skb)) 91162306a36Sopenharmony_ci neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (!neigh) { 91462306a36Sopenharmony_ci net_dbg_ratelimited("nexthop == NULL\n"); 91562306a36Sopenharmony_ci goto tx_error; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci addr6 = (const struct in6_addr *)&neigh->primary_key; 91962306a36Sopenharmony_ci addr_type = ipv6_addr_type(addr6); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (addr_type == IPV6_ADDR_ANY) { 92262306a36Sopenharmony_ci addr6 = &ipv6_hdr(skb)->daddr; 92362306a36Sopenharmony_ci addr_type = ipv6_addr_type(addr6); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if ((addr_type & IPV6_ADDR_COMPATv4) != 0) 92762306a36Sopenharmony_ci dst = addr6->s6_addr32[3]; 92862306a36Sopenharmony_ci else 92962306a36Sopenharmony_ci do_tx_error = true; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci neigh_release(neigh); 93262306a36Sopenharmony_ci if (do_tx_error) 93362306a36Sopenharmony_ci goto tx_error; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci flowi4_init_output(&fl4, tunnel->parms.link, tunnel->fwmark, 93762306a36Sopenharmony_ci RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6, 93862306a36Sopenharmony_ci 0, dst, tiph->saddr, 0, 0, 93962306a36Sopenharmony_ci sock_net_uid(tunnel->net, NULL)); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr); 94262306a36Sopenharmony_ci if (!rt) { 94362306a36Sopenharmony_ci rt = ip_route_output_flow(tunnel->net, &fl4, NULL); 94462306a36Sopenharmony_ci if (IS_ERR(rt)) { 94562306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_carrier_errors); 94662306a36Sopenharmony_ci goto tx_error_icmp; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) { 95262306a36Sopenharmony_ci ip_rt_put(rt); 95362306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_carrier_errors); 95462306a36Sopenharmony_ci goto tx_error_icmp; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci tdev = rt->dst.dev; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (tdev == dev) { 95962306a36Sopenharmony_ci ip_rt_put(rt); 96062306a36Sopenharmony_ci DEV_STATS_INC(dev, collisions); 96162306a36Sopenharmony_ci goto tx_error; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) { 96562306a36Sopenharmony_ci ip_rt_put(rt); 96662306a36Sopenharmony_ci goto tx_error; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (df) { 97062306a36Sopenharmony_ci mtu = dst_mtu(&rt->dst) - t_hlen; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (mtu < IPV4_MIN_MTU) { 97362306a36Sopenharmony_ci DEV_STATS_INC(dev, collisions); 97462306a36Sopenharmony_ci ip_rt_put(rt); 97562306a36Sopenharmony_ci goto tx_error; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (mtu < IPV6_MIN_MTU) { 97962306a36Sopenharmony_ci mtu = IPV6_MIN_MTU; 98062306a36Sopenharmony_ci df = 0; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (tunnel->parms.iph.daddr) 98462306a36Sopenharmony_ci skb_dst_update_pmtu_no_confirm(skb, mtu); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (skb->len > mtu && !skb_is_gso(skb)) { 98762306a36Sopenharmony_ci icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 98862306a36Sopenharmony_ci ip_rt_put(rt); 98962306a36Sopenharmony_ci goto tx_error; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (tunnel->err_count > 0) { 99462306a36Sopenharmony_ci if (time_before(jiffies, 99562306a36Sopenharmony_ci tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { 99662306a36Sopenharmony_ci tunnel->err_count--; 99762306a36Sopenharmony_ci dst_link_failure(skb); 99862306a36Sopenharmony_ci } else 99962306a36Sopenharmony_ci tunnel->err_count = 0; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* 100362306a36Sopenharmony_ci * Okay, now see if we can stuff it in the buffer as-is. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci max_headroom = LL_RESERVED_SPACE(tdev) + t_hlen; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (skb_headroom(skb) < max_headroom || skb_shared(skb) || 100862306a36Sopenharmony_ci (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { 100962306a36Sopenharmony_ci struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); 101062306a36Sopenharmony_ci if (!new_skb) { 101162306a36Sopenharmony_ci ip_rt_put(rt); 101262306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_dropped); 101362306a36Sopenharmony_ci kfree_skb(skb); 101462306a36Sopenharmony_ci return NETDEV_TX_OK; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci if (skb->sk) 101762306a36Sopenharmony_ci skb_set_owner_w(new_skb, skb->sk); 101862306a36Sopenharmony_ci dev_kfree_skb(skb); 101962306a36Sopenharmony_ci skb = new_skb; 102062306a36Sopenharmony_ci iph6 = ipv6_hdr(skb); 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci ttl = tiph->ttl; 102362306a36Sopenharmony_ci if (ttl == 0) 102462306a36Sopenharmony_ci ttl = iph6->hop_limit; 102562306a36Sopenharmony_ci tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0) { 102862306a36Sopenharmony_ci ip_rt_put(rt); 102962306a36Sopenharmony_ci goto tx_error; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci skb_set_inner_ipproto(skb, IPPROTO_IPV6); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, 103562306a36Sopenharmony_ci df, !net_eq(tunnel->net, dev_net(dev))); 103662306a36Sopenharmony_ci return NETDEV_TX_OK; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_citx_error_icmp: 103962306a36Sopenharmony_ci dst_link_failure(skb); 104062306a36Sopenharmony_citx_error: 104162306a36Sopenharmony_ci kfree_skb(skb); 104262306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_errors); 104362306a36Sopenharmony_ci return NETDEV_TX_OK; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb, 104762306a36Sopenharmony_ci struct net_device *dev, u8 ipproto) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 105062306a36Sopenharmony_ci const struct iphdr *tiph = &tunnel->parms.iph; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) 105362306a36Sopenharmony_ci goto tx_error; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci skb_set_inner_ipproto(skb, ipproto); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ip_tunnel_xmit(skb, dev, tiph, ipproto); 105862306a36Sopenharmony_ci return NETDEV_TX_OK; 105962306a36Sopenharmony_citx_error: 106062306a36Sopenharmony_ci kfree_skb(skb); 106162306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_errors); 106262306a36Sopenharmony_ci return NETDEV_TX_OK; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, 106662306a36Sopenharmony_ci struct net_device *dev) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci if (!pskb_inet_may_pull(skb)) 106962306a36Sopenharmony_ci goto tx_err; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci switch (skb->protocol) { 107262306a36Sopenharmony_ci case htons(ETH_P_IP): 107362306a36Sopenharmony_ci sit_tunnel_xmit__(skb, dev, IPPROTO_IPIP); 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case htons(ETH_P_IPV6): 107662306a36Sopenharmony_ci ipip6_tunnel_xmit(skb, dev); 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 107962306a36Sopenharmony_ci case htons(ETH_P_MPLS_UC): 108062306a36Sopenharmony_ci sit_tunnel_xmit__(skb, dev, IPPROTO_MPLS); 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci#endif 108362306a36Sopenharmony_ci default: 108462306a36Sopenharmony_ci goto tx_err; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return NETDEV_TX_OK; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_citx_err: 109062306a36Sopenharmony_ci DEV_STATS_INC(dev, tx_errors); 109162306a36Sopenharmony_ci kfree_skb(skb); 109262306a36Sopenharmony_ci return NETDEV_TX_OK; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic void ipip6_tunnel_bind_dev(struct net_device *dev) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 109962306a36Sopenharmony_ci int t_hlen = tunnel->hlen + sizeof(struct iphdr); 110062306a36Sopenharmony_ci struct net_device *tdev = NULL; 110162306a36Sopenharmony_ci int hlen = LL_MAX_HEADER; 110262306a36Sopenharmony_ci const struct iphdr *iph; 110362306a36Sopenharmony_ci struct flowi4 fl4; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci iph = &tunnel->parms.iph; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (iph->daddr) { 110862306a36Sopenharmony_ci struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4, 110962306a36Sopenharmony_ci NULL, 111062306a36Sopenharmony_ci iph->daddr, iph->saddr, 111162306a36Sopenharmony_ci 0, 0, 111262306a36Sopenharmony_ci IPPROTO_IPV6, 111362306a36Sopenharmony_ci RT_TOS(iph->tos), 111462306a36Sopenharmony_ci tunnel->parms.link); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (!IS_ERR(rt)) { 111762306a36Sopenharmony_ci tdev = rt->dst.dev; 111862306a36Sopenharmony_ci ip_rt_put(rt); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci dev->flags |= IFF_POINTOPOINT; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (!tdev && tunnel->parms.link) 112462306a36Sopenharmony_ci tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci if (tdev && !netif_is_l3_master(tdev)) { 112762306a36Sopenharmony_ci int mtu; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci mtu = tdev->mtu - t_hlen; 113062306a36Sopenharmony_ci if (mtu < IPV6_MIN_MTU) 113162306a36Sopenharmony_ci mtu = IPV6_MIN_MTU; 113262306a36Sopenharmony_ci WRITE_ONCE(dev->mtu, mtu); 113362306a36Sopenharmony_ci hlen = tdev->hard_header_len + tdev->needed_headroom; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci dev->needed_headroom = t_hlen + hlen; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p, 113962306a36Sopenharmony_ci __u32 fwmark) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct net *net = t->net; 114262306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci ipip6_tunnel_unlink(sitn, t); 114562306a36Sopenharmony_ci synchronize_net(); 114662306a36Sopenharmony_ci t->parms.iph.saddr = p->iph.saddr; 114762306a36Sopenharmony_ci t->parms.iph.daddr = p->iph.daddr; 114862306a36Sopenharmony_ci __dev_addr_set(t->dev, &p->iph.saddr, 4); 114962306a36Sopenharmony_ci memcpy(t->dev->broadcast, &p->iph.daddr, 4); 115062306a36Sopenharmony_ci ipip6_tunnel_link(sitn, t); 115162306a36Sopenharmony_ci t->parms.iph.ttl = p->iph.ttl; 115262306a36Sopenharmony_ci t->parms.iph.tos = p->iph.tos; 115362306a36Sopenharmony_ci t->parms.iph.frag_off = p->iph.frag_off; 115462306a36Sopenharmony_ci if (t->parms.link != p->link || t->fwmark != fwmark) { 115562306a36Sopenharmony_ci t->parms.link = p->link; 115662306a36Sopenharmony_ci t->fwmark = fwmark; 115762306a36Sopenharmony_ci ipip6_tunnel_bind_dev(t->dev); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci dst_cache_reset(&t->dst_cache); 116062306a36Sopenharmony_ci netdev_state_change(t->dev); 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 116462306a36Sopenharmony_cistatic int ipip6_tunnel_update_6rd(struct ip_tunnel *t, 116562306a36Sopenharmony_ci struct ip_tunnel_6rd *ip6rd) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci struct in6_addr prefix; 116862306a36Sopenharmony_ci __be32 relay_prefix; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (ip6rd->relay_prefixlen > 32 || 117162306a36Sopenharmony_ci ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64) 117262306a36Sopenharmony_ci return -EINVAL; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen); 117562306a36Sopenharmony_ci if (!ipv6_addr_equal(&prefix, &ip6rd->prefix)) 117662306a36Sopenharmony_ci return -EINVAL; 117762306a36Sopenharmony_ci if (ip6rd->relay_prefixlen) 117862306a36Sopenharmony_ci relay_prefix = ip6rd->relay_prefix & 117962306a36Sopenharmony_ci htonl(0xffffffffUL << 118062306a36Sopenharmony_ci (32 - ip6rd->relay_prefixlen)); 118162306a36Sopenharmony_ci else 118262306a36Sopenharmony_ci relay_prefix = 0; 118362306a36Sopenharmony_ci if (relay_prefix != ip6rd->relay_prefix) 118462306a36Sopenharmony_ci return -EINVAL; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci t->ip6rd.prefix = prefix; 118762306a36Sopenharmony_ci t->ip6rd.relay_prefix = relay_prefix; 118862306a36Sopenharmony_ci t->ip6rd.prefixlen = ip6rd->prefixlen; 118962306a36Sopenharmony_ci t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen; 119062306a36Sopenharmony_ci dst_cache_reset(&t->dst_cache); 119162306a36Sopenharmony_ci netdev_state_change(t->dev); 119262306a36Sopenharmony_ci return 0; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int 119662306a36Sopenharmony_ciipip6_tunnel_get6rd(struct net_device *dev, struct ip_tunnel_parm __user *data) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 119962306a36Sopenharmony_ci struct ip_tunnel_6rd ip6rd; 120062306a36Sopenharmony_ci struct ip_tunnel_parm p; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { 120362306a36Sopenharmony_ci if (copy_from_user(&p, data, sizeof(p))) 120462306a36Sopenharmony_ci return -EFAULT; 120562306a36Sopenharmony_ci t = ipip6_tunnel_locate(t->net, &p, 0); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci if (!t) 120862306a36Sopenharmony_ci t = netdev_priv(dev); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci ip6rd.prefix = t->ip6rd.prefix; 121162306a36Sopenharmony_ci ip6rd.relay_prefix = t->ip6rd.relay_prefix; 121262306a36Sopenharmony_ci ip6rd.prefixlen = t->ip6rd.prefixlen; 121362306a36Sopenharmony_ci ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; 121462306a36Sopenharmony_ci if (copy_to_user(data, &ip6rd, sizeof(ip6rd))) 121562306a36Sopenharmony_ci return -EFAULT; 121662306a36Sopenharmony_ci return 0; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic int 122062306a36Sopenharmony_ciipip6_tunnel_6rdctl(struct net_device *dev, struct ip_tunnel_6rd __user *data, 122162306a36Sopenharmony_ci int cmd) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 122462306a36Sopenharmony_ci struct ip_tunnel_6rd ip6rd; 122562306a36Sopenharmony_ci int err; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) 122862306a36Sopenharmony_ci return -EPERM; 122962306a36Sopenharmony_ci if (copy_from_user(&ip6rd, data, sizeof(ip6rd))) 123062306a36Sopenharmony_ci return -EFAULT; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (cmd != SIOCDEL6RD) { 123362306a36Sopenharmony_ci err = ipip6_tunnel_update_6rd(t, &ip6rd); 123462306a36Sopenharmony_ci if (err < 0) 123562306a36Sopenharmony_ci return err; 123662306a36Sopenharmony_ci } else 123762306a36Sopenharmony_ci ipip6_tunnel_clone_6rd(dev, dev_to_sit_net(dev)); 123862306a36Sopenharmony_ci return 0; 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci#endif /* CONFIG_IPV6_SIT_6RD */ 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic bool ipip6_valid_ip_proto(u8 ipproto) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci return ipproto == IPPROTO_IPV6 || 124662306a36Sopenharmony_ci ipproto == IPPROTO_IPIP || 124762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 124862306a36Sopenharmony_ci ipproto == IPPROTO_MPLS || 124962306a36Sopenharmony_ci#endif 125062306a36Sopenharmony_ci ipproto == 0; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic int 125462306a36Sopenharmony_ci__ipip6_tunnel_ioctl_validate(struct net *net, struct ip_tunnel_parm *p) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 125762306a36Sopenharmony_ci return -EPERM; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (!ipip6_valid_ip_proto(p->iph.protocol)) 126062306a36Sopenharmony_ci return -EINVAL; 126162306a36Sopenharmony_ci if (p->iph.version != 4 || 126262306a36Sopenharmony_ci p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF))) 126362306a36Sopenharmony_ci return -EINVAL; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (p->iph.ttl) 126662306a36Sopenharmony_ci p->iph.frag_off |= htons(IP_DF); 126762306a36Sopenharmony_ci return 0; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic int 127162306a36Sopenharmony_ciipip6_tunnel_get(struct net_device *dev, struct ip_tunnel_parm *p) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) 127662306a36Sopenharmony_ci t = ipip6_tunnel_locate(t->net, p, 0); 127762306a36Sopenharmony_ci if (!t) 127862306a36Sopenharmony_ci t = netdev_priv(dev); 127962306a36Sopenharmony_ci memcpy(p, &t->parms, sizeof(*p)); 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int 128462306a36Sopenharmony_ciipip6_tunnel_add(struct net_device *dev, struct ip_tunnel_parm *p) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 128762306a36Sopenharmony_ci int err; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci err = __ipip6_tunnel_ioctl_validate(t->net, p); 129062306a36Sopenharmony_ci if (err) 129162306a36Sopenharmony_ci return err; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci t = ipip6_tunnel_locate(t->net, p, 1); 129462306a36Sopenharmony_ci if (!t) 129562306a36Sopenharmony_ci return -ENOBUFS; 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int 130062306a36Sopenharmony_ciipip6_tunnel_change(struct net_device *dev, struct ip_tunnel_parm *p) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 130362306a36Sopenharmony_ci int err; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci err = __ipip6_tunnel_ioctl_validate(t->net, p); 130662306a36Sopenharmony_ci if (err) 130762306a36Sopenharmony_ci return err; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci t = ipip6_tunnel_locate(t->net, p, 0); 131062306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { 131162306a36Sopenharmony_ci if (!t) 131262306a36Sopenharmony_ci return -ENOENT; 131362306a36Sopenharmony_ci } else { 131462306a36Sopenharmony_ci if (t) { 131562306a36Sopenharmony_ci if (t->dev != dev) 131662306a36Sopenharmony_ci return -EEXIST; 131762306a36Sopenharmony_ci } else { 131862306a36Sopenharmony_ci if (((dev->flags & IFF_POINTOPOINT) && !p->iph.daddr) || 131962306a36Sopenharmony_ci (!(dev->flags & IFF_POINTOPOINT) && p->iph.daddr)) 132062306a36Sopenharmony_ci return -EINVAL; 132162306a36Sopenharmony_ci t = netdev_priv(dev); 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci ipip6_tunnel_update(t, p, t->fwmark); 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci return 0; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic int 133162306a36Sopenharmony_ciipip6_tunnel_del(struct net_device *dev, struct ip_tunnel_parm *p) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN)) 133662306a36Sopenharmony_ci return -EPERM; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) { 133962306a36Sopenharmony_ci t = ipip6_tunnel_locate(t->net, p, 0); 134062306a36Sopenharmony_ci if (!t) 134162306a36Sopenharmony_ci return -ENOENT; 134262306a36Sopenharmony_ci if (t == netdev_priv(dev_to_sit_net(dev)->fb_tunnel_dev)) 134362306a36Sopenharmony_ci return -EPERM; 134462306a36Sopenharmony_ci dev = t->dev; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci unregister_netdevice(dev); 134762306a36Sopenharmony_ci return 0; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int 135162306a36Sopenharmony_ciipip6_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci switch (cmd) { 135462306a36Sopenharmony_ci case SIOCGETTUNNEL: 135562306a36Sopenharmony_ci return ipip6_tunnel_get(dev, p); 135662306a36Sopenharmony_ci case SIOCADDTUNNEL: 135762306a36Sopenharmony_ci return ipip6_tunnel_add(dev, p); 135862306a36Sopenharmony_ci case SIOCCHGTUNNEL: 135962306a36Sopenharmony_ci return ipip6_tunnel_change(dev, p); 136062306a36Sopenharmony_ci case SIOCDELTUNNEL: 136162306a36Sopenharmony_ci return ipip6_tunnel_del(dev, p); 136262306a36Sopenharmony_ci default: 136362306a36Sopenharmony_ci return -EINVAL; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic int 136862306a36Sopenharmony_ciipip6_tunnel_siocdevprivate(struct net_device *dev, struct ifreq *ifr, 136962306a36Sopenharmony_ci void __user *data, int cmd) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci switch (cmd) { 137262306a36Sopenharmony_ci case SIOCGETTUNNEL: 137362306a36Sopenharmony_ci case SIOCADDTUNNEL: 137462306a36Sopenharmony_ci case SIOCCHGTUNNEL: 137562306a36Sopenharmony_ci case SIOCDELTUNNEL: 137662306a36Sopenharmony_ci return ip_tunnel_siocdevprivate(dev, ifr, data, cmd); 137762306a36Sopenharmony_ci case SIOCGETPRL: 137862306a36Sopenharmony_ci return ipip6_tunnel_get_prl(dev, data); 137962306a36Sopenharmony_ci case SIOCADDPRL: 138062306a36Sopenharmony_ci case SIOCDELPRL: 138162306a36Sopenharmony_ci case SIOCCHGPRL: 138262306a36Sopenharmony_ci return ipip6_tunnel_prl_ctl(dev, data, cmd); 138362306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 138462306a36Sopenharmony_ci case SIOCGET6RD: 138562306a36Sopenharmony_ci return ipip6_tunnel_get6rd(dev, data); 138662306a36Sopenharmony_ci case SIOCADD6RD: 138762306a36Sopenharmony_ci case SIOCCHG6RD: 138862306a36Sopenharmony_ci case SIOCDEL6RD: 138962306a36Sopenharmony_ci return ipip6_tunnel_6rdctl(dev, data, cmd); 139062306a36Sopenharmony_ci#endif 139162306a36Sopenharmony_ci default: 139262306a36Sopenharmony_ci return -EINVAL; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic const struct net_device_ops ipip6_netdev_ops = { 139762306a36Sopenharmony_ci .ndo_init = ipip6_tunnel_init, 139862306a36Sopenharmony_ci .ndo_uninit = ipip6_tunnel_uninit, 139962306a36Sopenharmony_ci .ndo_start_xmit = sit_tunnel_xmit, 140062306a36Sopenharmony_ci .ndo_siocdevprivate = ipip6_tunnel_siocdevprivate, 140162306a36Sopenharmony_ci .ndo_get_stats64 = dev_get_tstats64, 140262306a36Sopenharmony_ci .ndo_get_iflink = ip_tunnel_get_iflink, 140362306a36Sopenharmony_ci .ndo_tunnel_ctl = ipip6_tunnel_ctl, 140462306a36Sopenharmony_ci}; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic void ipip6_dev_free(struct net_device *dev) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci dst_cache_destroy(&tunnel->dst_cache); 141162306a36Sopenharmony_ci free_percpu(dev->tstats); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci#define SIT_FEATURES (NETIF_F_SG | \ 141562306a36Sopenharmony_ci NETIF_F_FRAGLIST | \ 141662306a36Sopenharmony_ci NETIF_F_HIGHDMA | \ 141762306a36Sopenharmony_ci NETIF_F_GSO_SOFTWARE | \ 141862306a36Sopenharmony_ci NETIF_F_HW_CSUM) 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic void ipip6_tunnel_setup(struct net_device *dev) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 142362306a36Sopenharmony_ci int t_hlen = tunnel->hlen + sizeof(struct iphdr); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci dev->netdev_ops = &ipip6_netdev_ops; 142662306a36Sopenharmony_ci dev->header_ops = &ip_tunnel_header_ops; 142762306a36Sopenharmony_ci dev->needs_free_netdev = true; 142862306a36Sopenharmony_ci dev->priv_destructor = ipip6_dev_free; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci dev->type = ARPHRD_SIT; 143162306a36Sopenharmony_ci dev->mtu = ETH_DATA_LEN - t_hlen; 143262306a36Sopenharmony_ci dev->min_mtu = IPV6_MIN_MTU; 143362306a36Sopenharmony_ci dev->max_mtu = IP6_MAX_MTU - t_hlen; 143462306a36Sopenharmony_ci dev->flags = IFF_NOARP; 143562306a36Sopenharmony_ci netif_keep_dst(dev); 143662306a36Sopenharmony_ci dev->addr_len = 4; 143762306a36Sopenharmony_ci dev->features |= NETIF_F_LLTX; 143862306a36Sopenharmony_ci dev->features |= SIT_FEATURES; 143962306a36Sopenharmony_ci dev->hw_features |= SIT_FEATURES; 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int ipip6_tunnel_init(struct net_device *dev) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 144562306a36Sopenharmony_ci int err; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci tunnel->dev = dev; 144862306a36Sopenharmony_ci tunnel->net = dev_net(dev); 144962306a36Sopenharmony_ci strcpy(tunnel->parms.name, dev->name); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ipip6_tunnel_bind_dev(dev); 145262306a36Sopenharmony_ci dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 145362306a36Sopenharmony_ci if (!dev->tstats) 145462306a36Sopenharmony_ci return -ENOMEM; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); 145762306a36Sopenharmony_ci if (err) { 145862306a36Sopenharmony_ci free_percpu(dev->tstats); 145962306a36Sopenharmony_ci dev->tstats = NULL; 146062306a36Sopenharmony_ci return err; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); 146362306a36Sopenharmony_ci return 0; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic void __net_init ipip6_fb_tunnel_init(struct net_device *dev) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 146962306a36Sopenharmony_ci struct iphdr *iph = &tunnel->parms.iph; 147062306a36Sopenharmony_ci struct net *net = dev_net(dev); 147162306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci iph->version = 4; 147462306a36Sopenharmony_ci iph->protocol = IPPROTO_IPV6; 147562306a36Sopenharmony_ci iph->ihl = 5; 147662306a36Sopenharmony_ci iph->ttl = 64; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic int ipip6_validate(struct nlattr *tb[], struct nlattr *data[], 148262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci u8 proto; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (!data || !data[IFLA_IPTUN_PROTO]) 148762306a36Sopenharmony_ci return 0; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); 149062306a36Sopenharmony_ci if (!ipip6_valid_ip_proto(proto)) 149162306a36Sopenharmony_ci return -EINVAL; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return 0; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic void ipip6_netlink_parms(struct nlattr *data[], 149762306a36Sopenharmony_ci struct ip_tunnel_parm *parms, 149862306a36Sopenharmony_ci __u32 *fwmark) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci memset(parms, 0, sizeof(*parms)); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci parms->iph.version = 4; 150362306a36Sopenharmony_ci parms->iph.protocol = IPPROTO_IPV6; 150462306a36Sopenharmony_ci parms->iph.ihl = 5; 150562306a36Sopenharmony_ci parms->iph.ttl = 64; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (!data) 150862306a36Sopenharmony_ci return; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci ip_tunnel_netlink_parms(data, parms); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci if (data[IFLA_IPTUN_FWMARK]) 151362306a36Sopenharmony_ci *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 151762306a36Sopenharmony_ci/* This function returns true when 6RD attributes are present in the nl msg */ 151862306a36Sopenharmony_cistatic bool ipip6_netlink_6rd_parms(struct nlattr *data[], 151962306a36Sopenharmony_ci struct ip_tunnel_6rd *ip6rd) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci bool ret = false; 152262306a36Sopenharmony_ci memset(ip6rd, 0, sizeof(*ip6rd)); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (!data) 152562306a36Sopenharmony_ci return ret; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (data[IFLA_IPTUN_6RD_PREFIX]) { 152862306a36Sopenharmony_ci ret = true; 152962306a36Sopenharmony_ci ip6rd->prefix = nla_get_in6_addr(data[IFLA_IPTUN_6RD_PREFIX]); 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) { 153362306a36Sopenharmony_ci ret = true; 153462306a36Sopenharmony_ci ip6rd->relay_prefix = 153562306a36Sopenharmony_ci nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (data[IFLA_IPTUN_6RD_PREFIXLEN]) { 153962306a36Sopenharmony_ci ret = true; 154062306a36Sopenharmony_ci ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]); 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) { 154462306a36Sopenharmony_ci ret = true; 154562306a36Sopenharmony_ci ip6rd->relay_prefixlen = 154662306a36Sopenharmony_ci nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci return ret; 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci#endif 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic int ipip6_newlink(struct net *src_net, struct net_device *dev, 155462306a36Sopenharmony_ci struct nlattr *tb[], struct nlattr *data[], 155562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct net *net = dev_net(dev); 155862306a36Sopenharmony_ci struct ip_tunnel *nt; 155962306a36Sopenharmony_ci struct ip_tunnel_encap ipencap; 156062306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 156162306a36Sopenharmony_ci struct ip_tunnel_6rd ip6rd; 156262306a36Sopenharmony_ci#endif 156362306a36Sopenharmony_ci int err; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci nt = netdev_priv(dev); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 156862306a36Sopenharmony_ci err = ip_tunnel_encap_setup(nt, &ipencap); 156962306a36Sopenharmony_ci if (err < 0) 157062306a36Sopenharmony_ci return err; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci ipip6_netlink_parms(data, &nt->parms, &nt->fwmark); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (ipip6_tunnel_locate(net, &nt->parms, 0)) 157662306a36Sopenharmony_ci return -EEXIST; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci err = ipip6_tunnel_create(dev); 157962306a36Sopenharmony_ci if (err < 0) 158062306a36Sopenharmony_ci return err; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (tb[IFLA_MTU]) { 158362306a36Sopenharmony_ci u32 mtu = nla_get_u32(tb[IFLA_MTU]); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (mtu >= IPV6_MIN_MTU && 158662306a36Sopenharmony_ci mtu <= IP6_MAX_MTU - dev->hard_header_len) 158762306a36Sopenharmony_ci dev->mtu = mtu; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 159162306a36Sopenharmony_ci if (ipip6_netlink_6rd_parms(data, &ip6rd)) { 159262306a36Sopenharmony_ci err = ipip6_tunnel_update_6rd(nt, &ip6rd); 159362306a36Sopenharmony_ci if (err < 0) 159462306a36Sopenharmony_ci unregister_netdevice_queue(dev, NULL); 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci#endif 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return err; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], 160262306a36Sopenharmony_ci struct nlattr *data[], 160362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct ip_tunnel *t = netdev_priv(dev); 160662306a36Sopenharmony_ci struct ip_tunnel_parm p; 160762306a36Sopenharmony_ci struct ip_tunnel_encap ipencap; 160862306a36Sopenharmony_ci struct net *net = t->net; 160962306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 161062306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 161162306a36Sopenharmony_ci struct ip_tunnel_6rd ip6rd; 161262306a36Sopenharmony_ci#endif 161362306a36Sopenharmony_ci __u32 fwmark = t->fwmark; 161462306a36Sopenharmony_ci int err; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (dev == sitn->fb_tunnel_dev) 161762306a36Sopenharmony_ci return -EINVAL; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 162062306a36Sopenharmony_ci err = ip_tunnel_encap_setup(t, &ipencap); 162162306a36Sopenharmony_ci if (err < 0) 162262306a36Sopenharmony_ci return err; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci ipip6_netlink_parms(data, &p, &fwmark); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 162862306a36Sopenharmony_ci (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 162962306a36Sopenharmony_ci return -EINVAL; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci t = ipip6_tunnel_locate(net, &p, 0); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (t) { 163462306a36Sopenharmony_ci if (t->dev != dev) 163562306a36Sopenharmony_ci return -EEXIST; 163662306a36Sopenharmony_ci } else 163762306a36Sopenharmony_ci t = netdev_priv(dev); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci ipip6_tunnel_update(t, &p, fwmark); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 164262306a36Sopenharmony_ci if (ipip6_netlink_6rd_parms(data, &ip6rd)) 164362306a36Sopenharmony_ci return ipip6_tunnel_update_6rd(t, &ip6rd); 164462306a36Sopenharmony_ci#endif 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci return 0; 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic size_t ipip6_get_size(const struct net_device *dev) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci return 165262306a36Sopenharmony_ci /* IFLA_IPTUN_LINK */ 165362306a36Sopenharmony_ci nla_total_size(4) + 165462306a36Sopenharmony_ci /* IFLA_IPTUN_LOCAL */ 165562306a36Sopenharmony_ci nla_total_size(4) + 165662306a36Sopenharmony_ci /* IFLA_IPTUN_REMOTE */ 165762306a36Sopenharmony_ci nla_total_size(4) + 165862306a36Sopenharmony_ci /* IFLA_IPTUN_TTL */ 165962306a36Sopenharmony_ci nla_total_size(1) + 166062306a36Sopenharmony_ci /* IFLA_IPTUN_TOS */ 166162306a36Sopenharmony_ci nla_total_size(1) + 166262306a36Sopenharmony_ci /* IFLA_IPTUN_PMTUDISC */ 166362306a36Sopenharmony_ci nla_total_size(1) + 166462306a36Sopenharmony_ci /* IFLA_IPTUN_FLAGS */ 166562306a36Sopenharmony_ci nla_total_size(2) + 166662306a36Sopenharmony_ci /* IFLA_IPTUN_PROTO */ 166762306a36Sopenharmony_ci nla_total_size(1) + 166862306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 166962306a36Sopenharmony_ci /* IFLA_IPTUN_6RD_PREFIX */ 167062306a36Sopenharmony_ci nla_total_size(sizeof(struct in6_addr)) + 167162306a36Sopenharmony_ci /* IFLA_IPTUN_6RD_RELAY_PREFIX */ 167262306a36Sopenharmony_ci nla_total_size(4) + 167362306a36Sopenharmony_ci /* IFLA_IPTUN_6RD_PREFIXLEN */ 167462306a36Sopenharmony_ci nla_total_size(2) + 167562306a36Sopenharmony_ci /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ 167662306a36Sopenharmony_ci nla_total_size(2) + 167762306a36Sopenharmony_ci#endif 167862306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_TYPE */ 167962306a36Sopenharmony_ci nla_total_size(2) + 168062306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_FLAGS */ 168162306a36Sopenharmony_ci nla_total_size(2) + 168262306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_SPORT */ 168362306a36Sopenharmony_ci nla_total_size(2) + 168462306a36Sopenharmony_ci /* IFLA_IPTUN_ENCAP_DPORT */ 168562306a36Sopenharmony_ci nla_total_size(2) + 168662306a36Sopenharmony_ci /* IFLA_IPTUN_FWMARK */ 168762306a36Sopenharmony_ci nla_total_size(4) + 168862306a36Sopenharmony_ci 0; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) 169262306a36Sopenharmony_ci{ 169362306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(dev); 169462306a36Sopenharmony_ci struct ip_tunnel_parm *parm = &tunnel->parms; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 169762306a36Sopenharmony_ci nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 169862306a36Sopenharmony_ci nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 169962306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 170062306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 170162306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 170262306a36Sopenharmony_ci !!(parm->iph.frag_off & htons(IP_DF))) || 170362306a36Sopenharmony_ci nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || 170462306a36Sopenharmony_ci nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags) || 170562306a36Sopenharmony_ci nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark)) 170662306a36Sopenharmony_ci goto nla_put_failure; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 170962306a36Sopenharmony_ci if (nla_put_in6_addr(skb, IFLA_IPTUN_6RD_PREFIX, 171062306a36Sopenharmony_ci &tunnel->ip6rd.prefix) || 171162306a36Sopenharmony_ci nla_put_in_addr(skb, IFLA_IPTUN_6RD_RELAY_PREFIX, 171262306a36Sopenharmony_ci tunnel->ip6rd.relay_prefix) || 171362306a36Sopenharmony_ci nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN, 171462306a36Sopenharmony_ci tunnel->ip6rd.prefixlen) || 171562306a36Sopenharmony_ci nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, 171662306a36Sopenharmony_ci tunnel->ip6rd.relay_prefixlen)) 171762306a36Sopenharmony_ci goto nla_put_failure; 171862306a36Sopenharmony_ci#endif 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 172162306a36Sopenharmony_ci tunnel->encap.type) || 172262306a36Sopenharmony_ci nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 172362306a36Sopenharmony_ci tunnel->encap.sport) || 172462306a36Sopenharmony_ci nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 172562306a36Sopenharmony_ci tunnel->encap.dport) || 172662306a36Sopenharmony_ci nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 172762306a36Sopenharmony_ci tunnel->encap.flags)) 172862306a36Sopenharmony_ci goto nla_put_failure; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci return 0; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_cinla_put_failure: 173362306a36Sopenharmony_ci return -EMSGSIZE; 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { 173762306a36Sopenharmony_ci [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 173862306a36Sopenharmony_ci [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 173962306a36Sopenharmony_ci [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 174062306a36Sopenharmony_ci [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 174162306a36Sopenharmony_ci [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 174262306a36Sopenharmony_ci [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 174362306a36Sopenharmony_ci [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, 174462306a36Sopenharmony_ci [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 174562306a36Sopenharmony_ci#ifdef CONFIG_IPV6_SIT_6RD 174662306a36Sopenharmony_ci [IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) }, 174762306a36Sopenharmony_ci [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 }, 174862306a36Sopenharmony_ci [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, 174962306a36Sopenharmony_ci [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, 175062306a36Sopenharmony_ci#endif 175162306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 175262306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 175362306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 175462306a36Sopenharmony_ci [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 175562306a36Sopenharmony_ci [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, 175662306a36Sopenharmony_ci}; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_cistatic void ipip6_dellink(struct net_device *dev, struct list_head *head) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci struct net *net = dev_net(dev); 176162306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci if (dev != sitn->fb_tunnel_dev) 176462306a36Sopenharmony_ci unregister_netdevice_queue(dev, head); 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic struct rtnl_link_ops sit_link_ops __read_mostly = { 176862306a36Sopenharmony_ci .kind = "sit", 176962306a36Sopenharmony_ci .maxtype = IFLA_IPTUN_MAX, 177062306a36Sopenharmony_ci .policy = ipip6_policy, 177162306a36Sopenharmony_ci .priv_size = sizeof(struct ip_tunnel), 177262306a36Sopenharmony_ci .setup = ipip6_tunnel_setup, 177362306a36Sopenharmony_ci .validate = ipip6_validate, 177462306a36Sopenharmony_ci .newlink = ipip6_newlink, 177562306a36Sopenharmony_ci .changelink = ipip6_changelink, 177662306a36Sopenharmony_ci .get_size = ipip6_get_size, 177762306a36Sopenharmony_ci .fill_info = ipip6_fill_info, 177862306a36Sopenharmony_ci .dellink = ipip6_dellink, 177962306a36Sopenharmony_ci .get_link_net = ip_tunnel_get_link_net, 178062306a36Sopenharmony_ci}; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic struct xfrm_tunnel sit_handler __read_mostly = { 178362306a36Sopenharmony_ci .handler = ipip6_rcv, 178462306a36Sopenharmony_ci .err_handler = ipip6_err, 178562306a36Sopenharmony_ci .priority = 1, 178662306a36Sopenharmony_ci}; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_cistatic struct xfrm_tunnel ipip_handler __read_mostly = { 178962306a36Sopenharmony_ci .handler = ipip_rcv, 179062306a36Sopenharmony_ci .err_handler = ipip6_err, 179162306a36Sopenharmony_ci .priority = 2, 179262306a36Sopenharmony_ci}; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 179562306a36Sopenharmony_cistatic struct xfrm_tunnel mplsip_handler __read_mostly = { 179662306a36Sopenharmony_ci .handler = mplsip_rcv, 179762306a36Sopenharmony_ci .err_handler = ipip6_err, 179862306a36Sopenharmony_ci .priority = 2, 179962306a36Sopenharmony_ci}; 180062306a36Sopenharmony_ci#endif 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_cistatic void __net_exit sit_destroy_tunnels(struct net *net, 180362306a36Sopenharmony_ci struct list_head *head) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 180662306a36Sopenharmony_ci struct net_device *dev, *aux; 180762306a36Sopenharmony_ci int prio; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci for_each_netdev_safe(net, dev, aux) 181062306a36Sopenharmony_ci if (dev->rtnl_link_ops == &sit_link_ops) 181162306a36Sopenharmony_ci unregister_netdevice_queue(dev, head); 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci for (prio = 0; prio < 4; prio++) { 181462306a36Sopenharmony_ci int h; 181562306a36Sopenharmony_ci for (h = 0; h < (prio ? IP6_SIT_HASH_SIZE : 1); h++) { 181662306a36Sopenharmony_ci struct ip_tunnel *t; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci t = rtnl_dereference(sitn->tunnels[prio][h]); 181962306a36Sopenharmony_ci while (t) { 182062306a36Sopenharmony_ci /* If dev is in the same netns, it has already 182162306a36Sopenharmony_ci * been added to the list by the previous loop. 182262306a36Sopenharmony_ci */ 182362306a36Sopenharmony_ci if (!net_eq(dev_net(t->dev), net)) 182462306a36Sopenharmony_ci unregister_netdevice_queue(t->dev, 182562306a36Sopenharmony_ci head); 182662306a36Sopenharmony_ci t = rtnl_dereference(t->next); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cistatic int __net_init sit_init_net(struct net *net) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci struct sit_net *sitn = net_generic(net, sit_net_id); 183562306a36Sopenharmony_ci struct ip_tunnel *t; 183662306a36Sopenharmony_ci int err; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci sitn->tunnels[0] = sitn->tunnels_wc; 183962306a36Sopenharmony_ci sitn->tunnels[1] = sitn->tunnels_l; 184062306a36Sopenharmony_ci sitn->tunnels[2] = sitn->tunnels_r; 184162306a36Sopenharmony_ci sitn->tunnels[3] = sitn->tunnels_r_l; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci if (!net_has_fallback_tunnels(net)) 184462306a36Sopenharmony_ci return 0; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", 184762306a36Sopenharmony_ci NET_NAME_UNKNOWN, 184862306a36Sopenharmony_ci ipip6_tunnel_setup); 184962306a36Sopenharmony_ci if (!sitn->fb_tunnel_dev) { 185062306a36Sopenharmony_ci err = -ENOMEM; 185162306a36Sopenharmony_ci goto err_alloc_dev; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci dev_net_set(sitn->fb_tunnel_dev, net); 185462306a36Sopenharmony_ci sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops; 185562306a36Sopenharmony_ci /* FB netdevice is special: we have one, and only one per netns. 185662306a36Sopenharmony_ci * Allowing to move it to another netns is clearly unsafe. 185762306a36Sopenharmony_ci */ 185862306a36Sopenharmony_ci sitn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci err = register_netdev(sitn->fb_tunnel_dev); 186162306a36Sopenharmony_ci if (err) 186262306a36Sopenharmony_ci goto err_reg_dev; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); 186562306a36Sopenharmony_ci ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci t = netdev_priv(sitn->fb_tunnel_dev); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci strcpy(t->parms.name, sitn->fb_tunnel_dev->name); 187062306a36Sopenharmony_ci return 0; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_cierr_reg_dev: 187362306a36Sopenharmony_ci free_netdev(sitn->fb_tunnel_dev); 187462306a36Sopenharmony_cierr_alloc_dev: 187562306a36Sopenharmony_ci return err; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic void __net_exit sit_exit_batch_net(struct list_head *net_list) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci LIST_HEAD(list); 188162306a36Sopenharmony_ci struct net *net; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci rtnl_lock(); 188462306a36Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) 188562306a36Sopenharmony_ci sit_destroy_tunnels(net, &list); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci unregister_netdevice_many(&list); 188862306a36Sopenharmony_ci rtnl_unlock(); 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_cistatic struct pernet_operations sit_net_ops = { 189262306a36Sopenharmony_ci .init = sit_init_net, 189362306a36Sopenharmony_ci .exit_batch = sit_exit_batch_net, 189462306a36Sopenharmony_ci .id = &sit_net_id, 189562306a36Sopenharmony_ci .size = sizeof(struct sit_net), 189662306a36Sopenharmony_ci}; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_cistatic void __exit sit_cleanup(void) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci rtnl_link_unregister(&sit_link_ops); 190162306a36Sopenharmony_ci xfrm4_tunnel_deregister(&sit_handler, AF_INET6); 190262306a36Sopenharmony_ci xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 190362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 190462306a36Sopenharmony_ci xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); 190562306a36Sopenharmony_ci#endif 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci unregister_pernet_device(&sit_net_ops); 190862306a36Sopenharmony_ci rcu_barrier(); /* Wait for completion of call_rcu()'s */ 190962306a36Sopenharmony_ci} 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_cistatic int __init sit_init(void) 191262306a36Sopenharmony_ci{ 191362306a36Sopenharmony_ci int err; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci pr_info("IPv6, IPv4 and MPLS over IPv4 tunneling driver\n"); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci err = register_pernet_device(&sit_net_ops); 191862306a36Sopenharmony_ci if (err < 0) 191962306a36Sopenharmony_ci return err; 192062306a36Sopenharmony_ci err = xfrm4_tunnel_register(&sit_handler, AF_INET6); 192162306a36Sopenharmony_ci if (err < 0) { 192262306a36Sopenharmony_ci pr_info("%s: can't register ip6ip4\n", __func__); 192362306a36Sopenharmony_ci goto xfrm_tunnel_failed; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 192662306a36Sopenharmony_ci if (err < 0) { 192762306a36Sopenharmony_ci pr_info("%s: can't register ip4ip4\n", __func__); 192862306a36Sopenharmony_ci goto xfrm_tunnel4_failed; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 193162306a36Sopenharmony_ci err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); 193262306a36Sopenharmony_ci if (err < 0) { 193362306a36Sopenharmony_ci pr_info("%s: can't register mplsip\n", __func__); 193462306a36Sopenharmony_ci goto xfrm_tunnel_mpls_failed; 193562306a36Sopenharmony_ci } 193662306a36Sopenharmony_ci#endif 193762306a36Sopenharmony_ci err = rtnl_link_register(&sit_link_ops); 193862306a36Sopenharmony_ci if (err < 0) 193962306a36Sopenharmony_ci goto rtnl_link_failed; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ciout: 194262306a36Sopenharmony_ci return err; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_cirtnl_link_failed: 194562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS) 194662306a36Sopenharmony_ci xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); 194762306a36Sopenharmony_cixfrm_tunnel_mpls_failed: 194862306a36Sopenharmony_ci#endif 194962306a36Sopenharmony_ci xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 195062306a36Sopenharmony_cixfrm_tunnel4_failed: 195162306a36Sopenharmony_ci xfrm4_tunnel_deregister(&sit_handler, AF_INET6); 195262306a36Sopenharmony_cixfrm_tunnel_failed: 195362306a36Sopenharmony_ci unregister_pernet_device(&sit_net_ops); 195462306a36Sopenharmony_ci goto out; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_cimodule_init(sit_init); 195862306a36Sopenharmony_cimodule_exit(sit_cleanup); 195962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 196062306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("sit"); 196162306a36Sopenharmony_ciMODULE_ALIAS_NETDEV("sit0"); 1962