162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* L2TP core. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008,2009,2010 Katalix Systems Ltd 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file contains some code of the original L2TPv2 pppol2tp 762306a36Sopenharmony_ci * driver, which has the following copyright: 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Authors: Martijn van Oosterhout <kleptog@svana.org> 1062306a36Sopenharmony_ci * James Chapman (jchapman@katalix.com) 1162306a36Sopenharmony_ci * Contributors: 1262306a36Sopenharmony_ci * Michal Ostrowski <mostrows@speakeasy.net> 1362306a36Sopenharmony_ci * Arnaldo Carvalho de Melo <acme@xconectiva.com.br> 1462306a36Sopenharmony_ci * David S. Miller (davem@redhat.com) 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/string.h> 2162306a36Sopenharmony_ci#include <linux/list.h> 2262306a36Sopenharmony_ci#include <linux/rculist.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/spinlock.h> 2762306a36Sopenharmony_ci#include <linux/kthread.h> 2862306a36Sopenharmony_ci#include <linux/sched.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/errno.h> 3162306a36Sopenharmony_ci#include <linux/jiffies.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/netdevice.h> 3462306a36Sopenharmony_ci#include <linux/net.h> 3562306a36Sopenharmony_ci#include <linux/inetdevice.h> 3662306a36Sopenharmony_ci#include <linux/skbuff.h> 3762306a36Sopenharmony_ci#include <linux/init.h> 3862306a36Sopenharmony_ci#include <linux/in.h> 3962306a36Sopenharmony_ci#include <linux/ip.h> 4062306a36Sopenharmony_ci#include <linux/udp.h> 4162306a36Sopenharmony_ci#include <linux/l2tp.h> 4262306a36Sopenharmony_ci#include <linux/hash.h> 4362306a36Sopenharmony_ci#include <linux/sort.h> 4462306a36Sopenharmony_ci#include <linux/file.h> 4562306a36Sopenharmony_ci#include <linux/nsproxy.h> 4662306a36Sopenharmony_ci#include <net/net_namespace.h> 4762306a36Sopenharmony_ci#include <net/netns/generic.h> 4862306a36Sopenharmony_ci#include <net/dst.h> 4962306a36Sopenharmony_ci#include <net/ip.h> 5062306a36Sopenharmony_ci#include <net/udp.h> 5162306a36Sopenharmony_ci#include <net/udp_tunnel.h> 5262306a36Sopenharmony_ci#include <net/inet_common.h> 5362306a36Sopenharmony_ci#include <net/xfrm.h> 5462306a36Sopenharmony_ci#include <net/protocol.h> 5562306a36Sopenharmony_ci#include <net/inet6_connection_sock.h> 5662306a36Sopenharmony_ci#include <net/inet_ecn.h> 5762306a36Sopenharmony_ci#include <net/ip6_route.h> 5862306a36Sopenharmony_ci#include <net/ip6_checksum.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include <asm/byteorder.h> 6162306a36Sopenharmony_ci#include <linux/atomic.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include "l2tp_core.h" 6462306a36Sopenharmony_ci#include "trace.h" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 6762306a36Sopenharmony_ci#include "trace.h" 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define L2TP_DRV_VERSION "V2.0" 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* L2TP header constants */ 7262306a36Sopenharmony_ci#define L2TP_HDRFLAG_T 0x8000 7362306a36Sopenharmony_ci#define L2TP_HDRFLAG_L 0x4000 7462306a36Sopenharmony_ci#define L2TP_HDRFLAG_S 0x0800 7562306a36Sopenharmony_ci#define L2TP_HDRFLAG_O 0x0200 7662306a36Sopenharmony_ci#define L2TP_HDRFLAG_P 0x0100 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define L2TP_HDR_VER_MASK 0x000F 7962306a36Sopenharmony_ci#define L2TP_HDR_VER_2 0x0002 8062306a36Sopenharmony_ci#define L2TP_HDR_VER_3 0x0003 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* L2TPv3 default L2-specific sublayer */ 8362306a36Sopenharmony_ci#define L2TP_SLFLAG_S 0x40000000 8462306a36Sopenharmony_ci#define L2TP_SL_SEQ_MASK 0x00ffffff 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define L2TP_HDR_SIZE_MAX 14 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Default trace flags */ 8962306a36Sopenharmony_ci#define L2TP_DEFAULT_DEBUG_FLAGS 0 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Private data stored for received packets in the skb. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistruct l2tp_skb_cb { 9462306a36Sopenharmony_ci u32 ns; 9562306a36Sopenharmony_ci u16 has_seq; 9662306a36Sopenharmony_ci u16 length; 9762306a36Sopenharmony_ci unsigned long expires; 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define L2TP_SKB_CB(skb) ((struct l2tp_skb_cb *)&(skb)->cb[sizeof(struct inet_skb_parm)]) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct workqueue_struct *l2tp_wq; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* per-net private data for this module */ 10562306a36Sopenharmony_cistatic unsigned int l2tp_net_id; 10662306a36Sopenharmony_cistruct l2tp_net { 10762306a36Sopenharmony_ci /* Lock for write access to l2tp_tunnel_idr */ 10862306a36Sopenharmony_ci spinlock_t l2tp_tunnel_idr_lock; 10962306a36Sopenharmony_ci struct idr l2tp_tunnel_idr; 11062306a36Sopenharmony_ci struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; 11162306a36Sopenharmony_ci /* Lock for write access to l2tp_session_hlist */ 11262306a36Sopenharmony_ci spinlock_t l2tp_session_hlist_lock; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 11662306a36Sopenharmony_cistatic bool l2tp_sk_is_v6(struct sock *sk) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci return sk->sk_family == PF_INET6 && 11962306a36Sopenharmony_ci !ipv6_addr_v4mapped(&sk->sk_v6_daddr); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci#endif 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline struct l2tp_net *l2tp_pernet(const struct net *net) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return net_generic(net, l2tp_net_id); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* Session hash global list for L2TPv3. 12962306a36Sopenharmony_ci * The session_id SHOULD be random according to RFC3931, but several 13062306a36Sopenharmony_ci * L2TP implementations use incrementing session_ids. So we do a real 13162306a36Sopenharmony_ci * hash on the session_id, rather than a simple bitmask. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic inline struct hlist_head * 13462306a36Sopenharmony_cil2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Session hash list. 14062306a36Sopenharmony_ci * The session_id SHOULD be random according to RFC2661, but several 14162306a36Sopenharmony_ci * L2TP implementations (Cisco and Microsoft) use incrementing 14262306a36Sopenharmony_ci * session_ids. So we do a real hash on the session_id, rather than a 14362306a36Sopenharmony_ci * simple bitmask. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic inline struct hlist_head * 14662306a36Sopenharmony_cil2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci trace_free_tunnel(tunnel); 15462306a36Sopenharmony_ci sock_put(tunnel->sock); 15562306a36Sopenharmony_ci /* the tunnel is freed in the socket destructor */ 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void l2tp_session_free(struct l2tp_session *session) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci trace_free_session(session); 16162306a36Sopenharmony_ci if (session->tunnel) 16262306a36Sopenharmony_ci l2tp_tunnel_dec_refcount(session->tunnel); 16362306a36Sopenharmony_ci kfree(session); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct l2tp_tunnel *l2tp_sk_to_tunnel(struct sock *sk) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = sk->sk_user_data; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (tunnel) 17162306a36Sopenharmony_ci if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC)) 17262306a36Sopenharmony_ci return NULL; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return tunnel; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_sk_to_tunnel); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_civoid l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci refcount_inc(&tunnel->ref_count); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_inc_refcount); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_civoid l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci if (refcount_dec_and_test(&tunnel->ref_count)) 18762306a36Sopenharmony_ci l2tp_tunnel_free(tunnel); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_dec_refcount); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_civoid l2tp_session_inc_refcount(struct l2tp_session *session) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci refcount_inc(&session->ref_count); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_inc_refcount); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid l2tp_session_dec_refcount(struct l2tp_session *session) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (refcount_dec_and_test(&session->ref_count)) 20062306a36Sopenharmony_ci l2tp_session_free(session); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_dec_refcount); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* Lookup a tunnel. A new reference is held on the returned tunnel. */ 20562306a36Sopenharmony_cistruct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci const struct l2tp_net *pn = l2tp_pernet(net); 20862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci rcu_read_lock_bh(); 21162306a36Sopenharmony_ci tunnel = idr_find(&pn->l2tp_tunnel_idr, tunnel_id); 21262306a36Sopenharmony_ci if (tunnel && refcount_inc_not_zero(&tunnel->ref_count)) { 21362306a36Sopenharmony_ci rcu_read_unlock_bh(); 21462306a36Sopenharmony_ci return tunnel; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci rcu_read_unlock_bh(); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return NULL; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistruct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 22562306a36Sopenharmony_ci unsigned long tunnel_id, tmp; 22662306a36Sopenharmony_ci struct l2tp_tunnel *tunnel; 22762306a36Sopenharmony_ci int count = 0; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci rcu_read_lock_bh(); 23062306a36Sopenharmony_ci idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) { 23162306a36Sopenharmony_ci if (tunnel && ++count > nth && 23262306a36Sopenharmony_ci refcount_inc_not_zero(&tunnel->ref_count)) { 23362306a36Sopenharmony_ci rcu_read_unlock_bh(); 23462306a36Sopenharmony_ci return tunnel; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci rcu_read_unlock_bh(); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return NULL; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistruct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel, 24462306a36Sopenharmony_ci u32 session_id) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct hlist_head *session_list; 24762306a36Sopenharmony_ci struct l2tp_session *session; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci session_list = l2tp_session_id_hash(tunnel, session_id); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci rcu_read_lock_bh(); 25262306a36Sopenharmony_ci hlist_for_each_entry_rcu(session, session_list, hlist) 25362306a36Sopenharmony_ci if (session->session_id == session_id) { 25462306a36Sopenharmony_ci l2tp_session_inc_refcount(session); 25562306a36Sopenharmony_ci rcu_read_unlock_bh(); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return session; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci rcu_read_unlock_bh(); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return NULL; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get_session); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistruct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct hlist_head *session_list; 26862306a36Sopenharmony_ci struct l2tp_session *session; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci session_list = l2tp_session_id_hash_2(l2tp_pernet(net), session_id); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci rcu_read_lock_bh(); 27362306a36Sopenharmony_ci hlist_for_each_entry_rcu(session, session_list, global_hlist) 27462306a36Sopenharmony_ci if (session->session_id == session_id) { 27562306a36Sopenharmony_ci l2tp_session_inc_refcount(session); 27662306a36Sopenharmony_ci rcu_read_unlock_bh(); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return session; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci rcu_read_unlock_bh(); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return NULL; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistruct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci int hash; 28962306a36Sopenharmony_ci struct l2tp_session *session; 29062306a36Sopenharmony_ci int count = 0; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci rcu_read_lock_bh(); 29362306a36Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 29462306a36Sopenharmony_ci hlist_for_each_entry_rcu(session, &tunnel->session_hlist[hash], hlist) { 29562306a36Sopenharmony_ci if (++count > nth) { 29662306a36Sopenharmony_ci l2tp_session_inc_refcount(session); 29762306a36Sopenharmony_ci rcu_read_unlock_bh(); 29862306a36Sopenharmony_ci return session; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci rcu_read_unlock_bh(); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return NULL; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get_nth); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* Lookup a session by interface name. 31062306a36Sopenharmony_ci * This is very inefficient but is only used by management interfaces. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_cistruct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, 31362306a36Sopenharmony_ci const char *ifname) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 31662306a36Sopenharmony_ci int hash; 31762306a36Sopenharmony_ci struct l2tp_session *session; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci rcu_read_lock_bh(); 32062306a36Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { 32162306a36Sopenharmony_ci hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { 32262306a36Sopenharmony_ci if (!strcmp(session->ifname, ifname)) { 32362306a36Sopenharmony_ci l2tp_session_inc_refcount(session); 32462306a36Sopenharmony_ci rcu_read_unlock_bh(); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return session; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci rcu_read_unlock_bh(); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return NULL; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ciint l2tp_session_register(struct l2tp_session *session, 33862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct l2tp_session *session_walk; 34162306a36Sopenharmony_ci struct hlist_head *g_head; 34262306a36Sopenharmony_ci struct hlist_head *head; 34362306a36Sopenharmony_ci struct l2tp_net *pn; 34462306a36Sopenharmony_ci int err; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci head = l2tp_session_id_hash(tunnel, session->session_id); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci spin_lock_bh(&tunnel->hlist_lock); 34962306a36Sopenharmony_ci if (!tunnel->acpt_newsess) { 35062306a36Sopenharmony_ci err = -ENODEV; 35162306a36Sopenharmony_ci goto err_tlock; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci hlist_for_each_entry(session_walk, head, hlist) 35562306a36Sopenharmony_ci if (session_walk->session_id == session->session_id) { 35662306a36Sopenharmony_ci err = -EEXIST; 35762306a36Sopenharmony_ci goto err_tlock; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_3) { 36162306a36Sopenharmony_ci pn = l2tp_pernet(tunnel->l2tp_net); 36262306a36Sopenharmony_ci g_head = l2tp_session_id_hash_2(pn, session->session_id); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci spin_lock_bh(&pn->l2tp_session_hlist_lock); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* IP encap expects session IDs to be globally unique, while 36762306a36Sopenharmony_ci * UDP encap doesn't. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci hlist_for_each_entry(session_walk, g_head, global_hlist) 37062306a36Sopenharmony_ci if (session_walk->session_id == session->session_id && 37162306a36Sopenharmony_ci (session_walk->tunnel->encap == L2TP_ENCAPTYPE_IP || 37262306a36Sopenharmony_ci tunnel->encap == L2TP_ENCAPTYPE_IP)) { 37362306a36Sopenharmony_ci err = -EEXIST; 37462306a36Sopenharmony_ci goto err_tlock_pnlock; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 37862306a36Sopenharmony_ci hlist_add_head_rcu(&session->global_hlist, g_head); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 38162306a36Sopenharmony_ci } else { 38262306a36Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci hlist_add_head_rcu(&session->hlist, head); 38662306a36Sopenharmony_ci spin_unlock_bh(&tunnel->hlist_lock); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci trace_register_session(session); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cierr_tlock_pnlock: 39362306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 39462306a36Sopenharmony_cierr_tlock: 39562306a36Sopenharmony_ci spin_unlock_bh(&tunnel->hlist_lock); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return err; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_register); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/***************************************************************************** 40262306a36Sopenharmony_ci * Receive data handling 40362306a36Sopenharmony_ci *****************************************************************************/ 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* Queue a skb in order. We come here only if the skb has an L2TP sequence 40662306a36Sopenharmony_ci * number. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *skb) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct sk_buff *skbp; 41162306a36Sopenharmony_ci struct sk_buff *tmp; 41262306a36Sopenharmony_ci u32 ns = L2TP_SKB_CB(skb)->ns; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci spin_lock_bh(&session->reorder_q.lock); 41562306a36Sopenharmony_ci skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { 41662306a36Sopenharmony_ci if (L2TP_SKB_CB(skbp)->ns > ns) { 41762306a36Sopenharmony_ci __skb_queue_before(&session->reorder_q, skbp, skb); 41862306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_oos_packets); 41962306a36Sopenharmony_ci goto out; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci __skb_queue_tail(&session->reorder_q, skb); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciout: 42662306a36Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* Dequeue a single skb. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_cistatic void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *skb) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 43462306a36Sopenharmony_ci int length = L2TP_SKB_CB(skb)->length; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* We're about to requeue the skb, so return resources 43762306a36Sopenharmony_ci * to its current owner (a socket receive buffer). 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ci skb_orphan(skb); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci atomic_long_inc(&tunnel->stats.rx_packets); 44262306a36Sopenharmony_ci atomic_long_add(length, &tunnel->stats.rx_bytes); 44362306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_packets); 44462306a36Sopenharmony_ci atomic_long_add(length, &session->stats.rx_bytes); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 44762306a36Sopenharmony_ci /* Bump our Nr */ 44862306a36Sopenharmony_ci session->nr++; 44962306a36Sopenharmony_ci session->nr &= session->nr_max; 45062306a36Sopenharmony_ci trace_session_seqnum_update(session); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* call private receive handler */ 45462306a36Sopenharmony_ci if (session->recv_skb) 45562306a36Sopenharmony_ci (*session->recv_skb)(session, skb, L2TP_SKB_CB(skb)->length); 45662306a36Sopenharmony_ci else 45762306a36Sopenharmony_ci kfree_skb(skb); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* Dequeue skbs from the session's reorder_q, subject to packet order. 46162306a36Sopenharmony_ci * Skbs that have been in the queue for too long are simply discarded. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistatic void l2tp_recv_dequeue(struct l2tp_session *session) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct sk_buff *skb; 46662306a36Sopenharmony_ci struct sk_buff *tmp; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* If the pkt at the head of the queue has the nr that we 46962306a36Sopenharmony_ci * expect to send up next, dequeue it and any other 47062306a36Sopenharmony_ci * in-sequence packets behind it. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistart: 47362306a36Sopenharmony_ci spin_lock_bh(&session->reorder_q.lock); 47462306a36Sopenharmony_ci skb_queue_walk_safe(&session->reorder_q, skb, tmp) { 47562306a36Sopenharmony_ci struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* If the packet has been pending on the queue for too long, discard it */ 47862306a36Sopenharmony_ci if (time_after(jiffies, cb->expires)) { 47962306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 48062306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 48162306a36Sopenharmony_ci trace_session_pkt_expired(session, cb->ns); 48262306a36Sopenharmony_ci session->reorder_skip = 1; 48362306a36Sopenharmony_ci __skb_unlink(skb, &session->reorder_q); 48462306a36Sopenharmony_ci kfree_skb(skb); 48562306a36Sopenharmony_ci continue; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (cb->has_seq) { 48962306a36Sopenharmony_ci if (session->reorder_skip) { 49062306a36Sopenharmony_ci session->reorder_skip = 0; 49162306a36Sopenharmony_ci session->nr = cb->ns; 49262306a36Sopenharmony_ci trace_session_seqnum_reset(session); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci if (cb->ns != session->nr) 49562306a36Sopenharmony_ci goto out; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci __skb_unlink(skb, &session->reorder_q); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Process the skb. We release the queue lock while we 50062306a36Sopenharmony_ci * do so to let other contexts process the queue. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 50362306a36Sopenharmony_ci l2tp_recv_dequeue_skb(session, skb); 50462306a36Sopenharmony_ci goto start; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ciout: 50862306a36Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci u32 nws; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (nr >= session->nr) 51662306a36Sopenharmony_ci nws = nr - session->nr; 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci nws = (session->nr_max + 1) - (session->nr - nr); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return nws < session->nr_window_size; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* If packet has sequence numbers, queue it if acceptable. Returns 0 if 52462306a36Sopenharmony_ci * acceptable, else non-zero. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cistatic int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (!l2tp_seq_check_rx_window(session, cb->ns)) { 53162306a36Sopenharmony_ci /* Packet sequence number is outside allowed window. 53262306a36Sopenharmony_ci * Discard it. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci trace_session_pkt_outside_rx_window(session, cb->ns); 53562306a36Sopenharmony_ci goto discard; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (session->reorder_timeout != 0) { 53962306a36Sopenharmony_ci /* Packet reordering enabled. Add skb to session's 54062306a36Sopenharmony_ci * reorder queue, in order of ns. 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci l2tp_recv_queue_skb(session, skb); 54362306a36Sopenharmony_ci goto out; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Packet reordering disabled. Discard out-of-sequence packets, while 54762306a36Sopenharmony_ci * tracking the number if in-sequence packets after the first OOS packet 54862306a36Sopenharmony_ci * is seen. After nr_oos_count_max in-sequence packets, reset the 54962306a36Sopenharmony_ci * sequence number to re-enable packet reception. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci if (cb->ns == session->nr) { 55262306a36Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 55362306a36Sopenharmony_ci } else { 55462306a36Sopenharmony_ci u32 nr_oos = cb->ns; 55562306a36Sopenharmony_ci u32 nr_next = (session->nr_oos + 1) & session->nr_max; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (nr_oos == nr_next) 55862306a36Sopenharmony_ci session->nr_oos_count++; 55962306a36Sopenharmony_ci else 56062306a36Sopenharmony_ci session->nr_oos_count = 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci session->nr_oos = nr_oos; 56362306a36Sopenharmony_ci if (session->nr_oos_count > session->nr_oos_count_max) { 56462306a36Sopenharmony_ci session->reorder_skip = 1; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci if (!session->reorder_skip) { 56762306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 56862306a36Sopenharmony_ci trace_session_pkt_oos(session, cb->ns); 56962306a36Sopenharmony_ci goto discard; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciout: 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cidiscard: 57862306a36Sopenharmony_ci return 1; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/* Do receive processing of L2TP data frames. We handle both L2TPv2 58262306a36Sopenharmony_ci * and L2TPv3 data frames here. 58362306a36Sopenharmony_ci * 58462306a36Sopenharmony_ci * L2TPv2 Data Message Header 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * 0 1 2 3 58762306a36Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 58862306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 58962306a36Sopenharmony_ci * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) | 59062306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59162306a36Sopenharmony_ci * | Tunnel ID | Session ID | 59262306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59362306a36Sopenharmony_ci * | Ns (opt) | Nr (opt) | 59462306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59562306a36Sopenharmony_ci * | Offset Size (opt) | Offset pad... (opt) 59662306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Data frames are marked by T=0. All other fields are the same as 59962306a36Sopenharmony_ci * those in L2TP control frames. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * L2TPv3 Data Message Header 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 60462306a36Sopenharmony_ci * | L2TP Session Header | 60562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 60662306a36Sopenharmony_ci * | L2-Specific Sublayer | 60762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 60862306a36Sopenharmony_ci * | Tunnel Payload ... 60962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61062306a36Sopenharmony_ci * 61162306a36Sopenharmony_ci * L2TPv3 Session Header Over IP 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * 0 1 2 3 61462306a36Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 61562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61662306a36Sopenharmony_ci * | Session ID | 61762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61862306a36Sopenharmony_ci * | Cookie (optional, maximum 64 bits)... 61962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62062306a36Sopenharmony_ci * | 62162306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * L2TPv3 L2-Specific Sublayer Format 62462306a36Sopenharmony_ci * 62562306a36Sopenharmony_ci * 0 1 2 3 62662306a36Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 62762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62862306a36Sopenharmony_ci * |x|S|x|x|x|x|x|x| Sequence Number | 62962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * Cookie value and sublayer format are negotiated with the peer when 63262306a36Sopenharmony_ci * the session is set up. Unlike L2TPv2, we do not need to parse the 63362306a36Sopenharmony_ci * packet header to determine if optional fields are present. 63462306a36Sopenharmony_ci * 63562306a36Sopenharmony_ci * Caller must already have parsed the frame and determined that it is 63662306a36Sopenharmony_ci * a data (not control) frame before coming here. Fields up to the 63762306a36Sopenharmony_ci * session-id have already been parsed and ptr points to the data 63862306a36Sopenharmony_ci * after the session-id. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_civoid l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, 64162306a36Sopenharmony_ci unsigned char *ptr, unsigned char *optr, u16 hdrflags, 64262306a36Sopenharmony_ci int length) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 64562306a36Sopenharmony_ci int offset; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Parse and check optional cookie */ 64862306a36Sopenharmony_ci if (session->peer_cookie_len > 0) { 64962306a36Sopenharmony_ci if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { 65062306a36Sopenharmony_ci pr_debug_ratelimited("%s: cookie mismatch (%u/%u). Discarding.\n", 65162306a36Sopenharmony_ci tunnel->name, tunnel->tunnel_id, 65262306a36Sopenharmony_ci session->session_id); 65362306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_cookie_discards); 65462306a36Sopenharmony_ci goto discard; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci ptr += session->peer_cookie_len; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* Handle the optional sequence numbers. Sequence numbers are 66062306a36Sopenharmony_ci * in different places for L2TPv2 and L2TPv3. 66162306a36Sopenharmony_ci * 66262306a36Sopenharmony_ci * If we are the LAC, enable/disable sequence numbers under 66362306a36Sopenharmony_ci * the control of the LNS. If no sequence numbers present but 66462306a36Sopenharmony_ci * we were expecting them, discard frame. 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 0; 66762306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 66862306a36Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_S) { 66962306a36Sopenharmony_ci /* Store L2TP info in the skb */ 67062306a36Sopenharmony_ci L2TP_SKB_CB(skb)->ns = ntohs(*(__be16 *)ptr); 67162306a36Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 1; 67262306a36Sopenharmony_ci ptr += 2; 67362306a36Sopenharmony_ci /* Skip past nr in the header */ 67462306a36Sopenharmony_ci ptr += 2; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 67862306a36Sopenharmony_ci u32 l2h = ntohl(*(__be32 *)ptr); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (l2h & 0x40000000) { 68162306a36Sopenharmony_ci /* Store L2TP info in the skb */ 68262306a36Sopenharmony_ci L2TP_SKB_CB(skb)->ns = l2h & 0x00ffffff; 68362306a36Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 1; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci ptr += 4; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 68962306a36Sopenharmony_ci /* Received a packet with sequence numbers. If we're the LAC, 69062306a36Sopenharmony_ci * check if we sre sending sequence numbers and if not, 69162306a36Sopenharmony_ci * configure it so. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci if (!session->lns_mode && !session->send_seq) { 69462306a36Sopenharmony_ci trace_session_seqnum_lns_enable(session); 69562306a36Sopenharmony_ci session->send_seq = 1; 69662306a36Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci /* No sequence numbers. 70062306a36Sopenharmony_ci * If user has configured mandatory sequence numbers, discard. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci if (session->recv_seq) { 70362306a36Sopenharmony_ci pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n", 70462306a36Sopenharmony_ci session->name); 70562306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 70662306a36Sopenharmony_ci goto discard; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* If we're the LAC and we're sending sequence numbers, the 71062306a36Sopenharmony_ci * LNS has requested that we no longer send sequence numbers. 71162306a36Sopenharmony_ci * If we're the LNS and we're sending sequence numbers, the 71262306a36Sopenharmony_ci * LAC is broken. Discard the frame. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci if (!session->lns_mode && session->send_seq) { 71562306a36Sopenharmony_ci trace_session_seqnum_lns_disable(session); 71662306a36Sopenharmony_ci session->send_seq = 0; 71762306a36Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 71862306a36Sopenharmony_ci } else if (session->send_seq) { 71962306a36Sopenharmony_ci pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n", 72062306a36Sopenharmony_ci session->name); 72162306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 72262306a36Sopenharmony_ci goto discard; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Session data offset is defined only for L2TPv2 and is 72762306a36Sopenharmony_ci * indicated by an optional 16-bit value in the header. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 73062306a36Sopenharmony_ci /* If offset bit set, skip it. */ 73162306a36Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_O) { 73262306a36Sopenharmony_ci offset = ntohs(*(__be16 *)ptr); 73362306a36Sopenharmony_ci ptr += 2 + offset; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci offset = ptr - optr; 73862306a36Sopenharmony_ci if (!pskb_may_pull(skb, offset)) 73962306a36Sopenharmony_ci goto discard; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci __skb_pull(skb, offset); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* Prepare skb for adding to the session's reorder_q. Hold 74462306a36Sopenharmony_ci * packets for max reorder_timeout or 1 second if not 74562306a36Sopenharmony_ci * reordering. 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ci L2TP_SKB_CB(skb)->length = length; 74862306a36Sopenharmony_ci L2TP_SKB_CB(skb)->expires = jiffies + 74962306a36Sopenharmony_ci (session->reorder_timeout ? session->reorder_timeout : HZ); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Add packet to the session's receive queue. Reordering is done here, if 75262306a36Sopenharmony_ci * enabled. Saved L2TP protocol info is stored in skb->sb[]. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 75562306a36Sopenharmony_ci if (l2tp_recv_data_seq(session, skb)) 75662306a36Sopenharmony_ci goto discard; 75762306a36Sopenharmony_ci } else { 75862306a36Sopenharmony_ci /* No sequence numbers. Add the skb to the tail of the 75962306a36Sopenharmony_ci * reorder queue. This ensures that it will be 76062306a36Sopenharmony_ci * delivered after all previous sequenced skbs. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Try to dequeue as many skbs from reorder_q as we can. */ 76662306a36Sopenharmony_ci l2tp_recv_dequeue(session); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cidiscard: 77162306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 77262306a36Sopenharmony_ci kfree_skb(skb); 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_recv_common); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* Drop skbs from the session's reorder_q 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_cistatic void l2tp_session_queue_purge(struct l2tp_session *session) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct sk_buff *skb = NULL; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci while ((skb = skb_dequeue(&session->reorder_q))) { 78362306a36Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 78462306a36Sopenharmony_ci kfree_skb(skb); 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci/* Internal UDP receive frame. Do the real work of receiving an L2TP data frame 78962306a36Sopenharmony_ci * here. The skb is not on a list when we get here. 79062306a36Sopenharmony_ci * Returns 0 if the packet was a data packet and was successfully passed on. 79162306a36Sopenharmony_ci * Returns 1 if the packet was not a good data packet and could not be 79262306a36Sopenharmony_ci * forwarded. All such packets are passed up to userspace to deal with. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_cistatic int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct l2tp_session *session = NULL; 79762306a36Sopenharmony_ci unsigned char *ptr, *optr; 79862306a36Sopenharmony_ci u16 hdrflags; 79962306a36Sopenharmony_ci u32 tunnel_id, session_id; 80062306a36Sopenharmony_ci u16 version; 80162306a36Sopenharmony_ci int length; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* UDP has verified checksum */ 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* UDP always verifies the packet length. */ 80662306a36Sopenharmony_ci __skb_pull(skb, sizeof(struct udphdr)); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Short packet? */ 80962306a36Sopenharmony_ci if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) { 81062306a36Sopenharmony_ci pr_debug_ratelimited("%s: recv short packet (len=%d)\n", 81162306a36Sopenharmony_ci tunnel->name, skb->len); 81262306a36Sopenharmony_ci goto invalid; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* Point to L2TP header */ 81662306a36Sopenharmony_ci optr = skb->data; 81762306a36Sopenharmony_ci ptr = skb->data; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* Get L2TP header flags */ 82062306a36Sopenharmony_ci hdrflags = ntohs(*(__be16 *)ptr); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* Check protocol version */ 82362306a36Sopenharmony_ci version = hdrflags & L2TP_HDR_VER_MASK; 82462306a36Sopenharmony_ci if (version != tunnel->version) { 82562306a36Sopenharmony_ci pr_debug_ratelimited("%s: recv protocol version mismatch: got %d expected %d\n", 82662306a36Sopenharmony_ci tunnel->name, version, tunnel->version); 82762306a36Sopenharmony_ci goto invalid; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* Get length of L2TP packet */ 83162306a36Sopenharmony_ci length = skb->len; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* If type is control packet, it is handled by userspace. */ 83462306a36Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_T) 83562306a36Sopenharmony_ci goto pass; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* Skip flags */ 83862306a36Sopenharmony_ci ptr += 2; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 84162306a36Sopenharmony_ci /* If length is present, skip it */ 84262306a36Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_L) 84362306a36Sopenharmony_ci ptr += 2; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Extract tunnel and session ID */ 84662306a36Sopenharmony_ci tunnel_id = ntohs(*(__be16 *)ptr); 84762306a36Sopenharmony_ci ptr += 2; 84862306a36Sopenharmony_ci session_id = ntohs(*(__be16 *)ptr); 84962306a36Sopenharmony_ci ptr += 2; 85062306a36Sopenharmony_ci } else { 85162306a36Sopenharmony_ci ptr += 2; /* skip reserved bits */ 85262306a36Sopenharmony_ci tunnel_id = tunnel->tunnel_id; 85362306a36Sopenharmony_ci session_id = ntohl(*(__be32 *)ptr); 85462306a36Sopenharmony_ci ptr += 4; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Find the session context */ 85862306a36Sopenharmony_ci session = l2tp_tunnel_get_session(tunnel, session_id); 85962306a36Sopenharmony_ci if (!session || !session->recv_skb) { 86062306a36Sopenharmony_ci if (session) 86162306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Not found? Pass to userspace to deal with */ 86462306a36Sopenharmony_ci pr_debug_ratelimited("%s: no session found (%u/%u). Passing up.\n", 86562306a36Sopenharmony_ci tunnel->name, tunnel_id, session_id); 86662306a36Sopenharmony_ci goto pass; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_3 && 87062306a36Sopenharmony_ci l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) { 87162306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 87262306a36Sopenharmony_ci goto invalid; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci l2tp_recv_common(session, skb, ptr, optr, hdrflags, length); 87662306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ciinvalid: 88162306a36Sopenharmony_ci atomic_long_inc(&tunnel->stats.rx_invalid); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cipass: 88462306a36Sopenharmony_ci /* Put UDP header back */ 88562306a36Sopenharmony_ci __skb_push(skb, sizeof(struct udphdr)); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return 1; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* UDP encapsulation receive handler. See net/ipv4/udp.c. 89162306a36Sopenharmony_ci * Return codes: 89262306a36Sopenharmony_ci * 0 : success. 89362306a36Sopenharmony_ci * <0: error 89462306a36Sopenharmony_ci * >0: skb should be passed up to userspace as UDP. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ciint l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* Note that this is called from the encap_rcv hook inside an 90162306a36Sopenharmony_ci * RCU-protected region, but without the socket being locked. 90262306a36Sopenharmony_ci * Hence we use rcu_dereference_sk_user_data to access the 90362306a36Sopenharmony_ci * tunnel data structure rather the usual l2tp_sk_to_tunnel 90462306a36Sopenharmony_ci * accessor function. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci tunnel = rcu_dereference_sk_user_data(sk); 90762306a36Sopenharmony_ci if (!tunnel) 90862306a36Sopenharmony_ci goto pass_up; 90962306a36Sopenharmony_ci if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC)) 91062306a36Sopenharmony_ci goto pass_up; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (l2tp_udp_recv_core(tunnel, skb)) 91362306a36Sopenharmony_ci goto pass_up; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cipass_up: 91862306a36Sopenharmony_ci return 1; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_udp_encap_recv); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/************************************************************************ 92362306a36Sopenharmony_ci * Transmit handling 92462306a36Sopenharmony_ci ***********************************************************************/ 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci/* Build an L2TP header for the session into the buffer provided. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_cistatic int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 93162306a36Sopenharmony_ci __be16 *bufp = buf; 93262306a36Sopenharmony_ci __be16 *optr = buf; 93362306a36Sopenharmony_ci u16 flags = L2TP_HDR_VER_2; 93462306a36Sopenharmony_ci u32 tunnel_id = tunnel->peer_tunnel_id; 93562306a36Sopenharmony_ci u32 session_id = session->peer_session_id; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (session->send_seq) 93862306a36Sopenharmony_ci flags |= L2TP_HDRFLAG_S; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* Setup L2TP header. */ 94162306a36Sopenharmony_ci *bufp++ = htons(flags); 94262306a36Sopenharmony_ci *bufp++ = htons(tunnel_id); 94362306a36Sopenharmony_ci *bufp++ = htons(session_id); 94462306a36Sopenharmony_ci if (session->send_seq) { 94562306a36Sopenharmony_ci *bufp++ = htons(session->ns); 94662306a36Sopenharmony_ci *bufp++ = 0; 94762306a36Sopenharmony_ci session->ns++; 94862306a36Sopenharmony_ci session->ns &= 0xffff; 94962306a36Sopenharmony_ci trace_session_seqnum_update(session); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return bufp - optr; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 95862306a36Sopenharmony_ci char *bufp = buf; 95962306a36Sopenharmony_ci char *optr = bufp; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Setup L2TP header. The header differs slightly for UDP and 96262306a36Sopenharmony_ci * IP encapsulations. For UDP, there is 4 bytes of flags. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_ci if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 96562306a36Sopenharmony_ci u16 flags = L2TP_HDR_VER_3; 96662306a36Sopenharmony_ci *((__be16 *)bufp) = htons(flags); 96762306a36Sopenharmony_ci bufp += 2; 96862306a36Sopenharmony_ci *((__be16 *)bufp) = 0; 96962306a36Sopenharmony_ci bufp += 2; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci *((__be32 *)bufp) = htonl(session->peer_session_id); 97362306a36Sopenharmony_ci bufp += 4; 97462306a36Sopenharmony_ci if (session->cookie_len) { 97562306a36Sopenharmony_ci memcpy(bufp, &session->cookie[0], session->cookie_len); 97662306a36Sopenharmony_ci bufp += session->cookie_len; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 97962306a36Sopenharmony_ci u32 l2h = 0; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (session->send_seq) { 98262306a36Sopenharmony_ci l2h = 0x40000000 | session->ns; 98362306a36Sopenharmony_ci session->ns++; 98462306a36Sopenharmony_ci session->ns &= 0xffffff; 98562306a36Sopenharmony_ci trace_session_seqnum_update(session); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci *((__be32 *)bufp) = htonl(l2h); 98962306a36Sopenharmony_ci bufp += 4; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return bufp - optr; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci/* Queue the packet to IP for output: tunnel socket lock must be held */ 99662306a36Sopenharmony_cistatic int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, struct flowi *fl) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci int err; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci skb->ignore_df = 1; 100162306a36Sopenharmony_ci skb_dst_drop(skb); 100262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 100362306a36Sopenharmony_ci if (l2tp_sk_is_v6(tunnel->sock)) 100462306a36Sopenharmony_ci err = inet6_csk_xmit(tunnel->sock, skb, NULL); 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci#endif 100762306a36Sopenharmony_ci err = ip_queue_xmit(tunnel->sock, skb, fl); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return err >= 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, unsigned int *len) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 101562306a36Sopenharmony_ci unsigned int data_len = skb->len; 101662306a36Sopenharmony_ci struct sock *sk = tunnel->sock; 101762306a36Sopenharmony_ci int headroom, uhlen, udp_len; 101862306a36Sopenharmony_ci int ret = NET_XMIT_SUCCESS; 101962306a36Sopenharmony_ci struct inet_sock *inet; 102062306a36Sopenharmony_ci struct udphdr *uh; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Check that there's enough headroom in the skb to insert IP, 102362306a36Sopenharmony_ci * UDP and L2TP headers. If not enough, expand it to 102462306a36Sopenharmony_ci * make room. Adjust truesize. 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_ci uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0; 102762306a36Sopenharmony_ci headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len; 102862306a36Sopenharmony_ci if (skb_cow_head(skb, headroom)) { 102962306a36Sopenharmony_ci kfree_skb(skb); 103062306a36Sopenharmony_ci return NET_XMIT_DROP; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Setup L2TP header */ 103462306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) 103562306a36Sopenharmony_ci l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len)); 103662306a36Sopenharmony_ci else 103762306a36Sopenharmony_ci l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len)); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* Reset skb netfilter state */ 104062306a36Sopenharmony_ci memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 104162306a36Sopenharmony_ci IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); 104262306a36Sopenharmony_ci nf_reset_ct(skb); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci bh_lock_sock_nested(sk); 104562306a36Sopenharmony_ci if (sock_owned_by_user(sk)) { 104662306a36Sopenharmony_ci kfree_skb(skb); 104762306a36Sopenharmony_ci ret = NET_XMIT_DROP; 104862306a36Sopenharmony_ci goto out_unlock; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* The user-space may change the connection status for the user-space 105262306a36Sopenharmony_ci * provided socket at run time: we must check it under the socket lock 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_ci if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { 105562306a36Sopenharmony_ci kfree_skb(skb); 105662306a36Sopenharmony_ci ret = NET_XMIT_DROP; 105762306a36Sopenharmony_ci goto out_unlock; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* Report transmitted length before we add encap header, which keeps 106162306a36Sopenharmony_ci * statistics consistent for both UDP and IP encap tx/rx paths. 106262306a36Sopenharmony_ci */ 106362306a36Sopenharmony_ci *len = skb->len; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci inet = inet_sk(sk); 106662306a36Sopenharmony_ci switch (tunnel->encap) { 106762306a36Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 106862306a36Sopenharmony_ci /* Setup UDP header */ 106962306a36Sopenharmony_ci __skb_push(skb, sizeof(*uh)); 107062306a36Sopenharmony_ci skb_reset_transport_header(skb); 107162306a36Sopenharmony_ci uh = udp_hdr(skb); 107262306a36Sopenharmony_ci uh->source = inet->inet_sport; 107362306a36Sopenharmony_ci uh->dest = inet->inet_dport; 107462306a36Sopenharmony_ci udp_len = uhlen + session->hdr_len + data_len; 107562306a36Sopenharmony_ci uh->len = htons(udp_len); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* Calculate UDP checksum if configured to do so */ 107862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 107962306a36Sopenharmony_ci if (l2tp_sk_is_v6(sk)) 108062306a36Sopenharmony_ci udp6_set_csum(udp_get_no_check6_tx(sk), 108162306a36Sopenharmony_ci skb, &inet6_sk(sk)->saddr, 108262306a36Sopenharmony_ci &sk->sk_v6_daddr, udp_len); 108362306a36Sopenharmony_ci else 108462306a36Sopenharmony_ci#endif 108562306a36Sopenharmony_ci udp_set_csum(sk->sk_no_check_tx, skb, inet->inet_saddr, 108662306a36Sopenharmony_ci inet->inet_daddr, udp_len); 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 109062306a36Sopenharmony_ci break; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci ret = l2tp_xmit_queue(tunnel, skb, &inet->cork.fl); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciout_unlock: 109662306a36Sopenharmony_ci bh_unlock_sock(sk); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci/* If caller requires the skb to have a ppp header, the header must be 110262306a36Sopenharmony_ci * inserted in the skb data before calling this function. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ciint l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci unsigned int len = 0; 110762306a36Sopenharmony_ci int ret; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci ret = l2tp_xmit_core(session, skb, &len); 111062306a36Sopenharmony_ci if (ret == NET_XMIT_SUCCESS) { 111162306a36Sopenharmony_ci atomic_long_inc(&session->tunnel->stats.tx_packets); 111262306a36Sopenharmony_ci atomic_long_add(len, &session->tunnel->stats.tx_bytes); 111362306a36Sopenharmony_ci atomic_long_inc(&session->stats.tx_packets); 111462306a36Sopenharmony_ci atomic_long_add(len, &session->stats.tx_bytes); 111562306a36Sopenharmony_ci } else { 111662306a36Sopenharmony_ci atomic_long_inc(&session->tunnel->stats.tx_errors); 111762306a36Sopenharmony_ci atomic_long_inc(&session->stats.tx_errors); 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_xmit_skb); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci/***************************************************************************** 112462306a36Sopenharmony_ci * Tinnel and session create/destroy. 112562306a36Sopenharmony_ci *****************************************************************************/ 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci/* Tunnel socket destruct hook. 112862306a36Sopenharmony_ci * The tunnel context is deleted only when all session sockets have been 112962306a36Sopenharmony_ci * closed. 113062306a36Sopenharmony_ci */ 113162306a36Sopenharmony_cistatic void l2tp_tunnel_destruct(struct sock *sk) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (!tunnel) 113662306a36Sopenharmony_ci goto end; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci /* Disable udp encapsulation */ 113962306a36Sopenharmony_ci switch (tunnel->encap) { 114062306a36Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 114162306a36Sopenharmony_ci /* No longer an encapsulation socket. See net/ipv4/udp.c */ 114262306a36Sopenharmony_ci WRITE_ONCE(udp_sk(sk)->encap_type, 0); 114362306a36Sopenharmony_ci udp_sk(sk)->encap_rcv = NULL; 114462306a36Sopenharmony_ci udp_sk(sk)->encap_destroy = NULL; 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* Remove hooks into tunnel socket */ 115162306a36Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 115262306a36Sopenharmony_ci sk->sk_destruct = tunnel->old_sk_destruct; 115362306a36Sopenharmony_ci sk->sk_user_data = NULL; 115462306a36Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* Call the original destructor */ 115762306a36Sopenharmony_ci if (sk->sk_destruct) 115862306a36Sopenharmony_ci (*sk->sk_destruct)(sk); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci kfree_rcu(tunnel, rcu); 116162306a36Sopenharmony_ciend: 116262306a36Sopenharmony_ci return; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci/* Remove an l2tp session from l2tp_core's hash lists. */ 116662306a36Sopenharmony_cistatic void l2tp_session_unhash(struct l2tp_session *session) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* Remove the session from core hashes */ 117162306a36Sopenharmony_ci if (tunnel) { 117262306a36Sopenharmony_ci /* Remove from the per-tunnel hash */ 117362306a36Sopenharmony_ci spin_lock_bh(&tunnel->hlist_lock); 117462306a36Sopenharmony_ci hlist_del_init_rcu(&session->hlist); 117562306a36Sopenharmony_ci spin_unlock_bh(&tunnel->hlist_lock); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* For L2TPv3 we have a per-net hash: remove from there, too */ 117862306a36Sopenharmony_ci if (tunnel->version != L2TP_HDR_VER_2) { 117962306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci spin_lock_bh(&pn->l2tp_session_hlist_lock); 118262306a36Sopenharmony_ci hlist_del_init_rcu(&session->global_hlist); 118362306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci synchronize_rcu(); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci/* When the tunnel is closed, all the attached sessions need to go too. 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_cistatic void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct l2tp_session *session; 119562306a36Sopenharmony_ci int hash; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci spin_lock_bh(&tunnel->hlist_lock); 119862306a36Sopenharmony_ci tunnel->acpt_newsess = false; 119962306a36Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 120062306a36Sopenharmony_ciagain: 120162306a36Sopenharmony_ci hlist_for_each_entry_rcu(session, &tunnel->session_hlist[hash], hlist) { 120262306a36Sopenharmony_ci hlist_del_init_rcu(&session->hlist); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci spin_unlock_bh(&tunnel->hlist_lock); 120562306a36Sopenharmony_ci l2tp_session_delete(session); 120662306a36Sopenharmony_ci spin_lock_bh(&tunnel->hlist_lock); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci /* Now restart from the beginning of this hash 120962306a36Sopenharmony_ci * chain. We always remove a session from the 121062306a36Sopenharmony_ci * list so we are guaranteed to make forward 121162306a36Sopenharmony_ci * progress. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci goto again; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci spin_unlock_bh(&tunnel->hlist_lock); 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci/* Tunnel socket destroy hook for UDP encapsulation */ 122062306a36Sopenharmony_cistatic void l2tp_udp_encap_destroy(struct sock *sk) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (tunnel) 122562306a36Sopenharmony_ci l2tp_tunnel_delete(tunnel); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic void l2tp_tunnel_remove(struct net *net, struct l2tp_tunnel *tunnel) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 123362306a36Sopenharmony_ci idr_remove(&pn->l2tp_tunnel_idr, tunnel->tunnel_id); 123462306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci/* Workqueue tunnel deletion function */ 123862306a36Sopenharmony_cistatic void l2tp_tunnel_del_work(struct work_struct *work) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, 124162306a36Sopenharmony_ci del_work); 124262306a36Sopenharmony_ci struct sock *sk = tunnel->sock; 124362306a36Sopenharmony_ci struct socket *sock = sk->sk_socket; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci l2tp_tunnel_closeall(tunnel); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* If the tunnel socket was created within the kernel, use 124862306a36Sopenharmony_ci * the sk API to release it here. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci if (tunnel->fd < 0) { 125162306a36Sopenharmony_ci if (sock) { 125262306a36Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 125362306a36Sopenharmony_ci sock_release(sock); 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci l2tp_tunnel_remove(tunnel->l2tp_net, tunnel); 125862306a36Sopenharmony_ci /* drop initial ref */ 125962306a36Sopenharmony_ci l2tp_tunnel_dec_refcount(tunnel); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* drop workqueue ref */ 126262306a36Sopenharmony_ci l2tp_tunnel_dec_refcount(tunnel); 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci/* Create a socket for the tunnel, if one isn't set up by 126662306a36Sopenharmony_ci * userspace. This is used for static tunnels where there is no 126762306a36Sopenharmony_ci * managing L2TP daemon. 126862306a36Sopenharmony_ci * 126962306a36Sopenharmony_ci * Since we don't want these sockets to keep a namespace alive by 127062306a36Sopenharmony_ci * themselves, we drop the socket's namespace refcount after creation. 127162306a36Sopenharmony_ci * These sockets are freed when the namespace exits using the pernet 127262306a36Sopenharmony_ci * exit hook. 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_cistatic int l2tp_tunnel_sock_create(struct net *net, 127562306a36Sopenharmony_ci u32 tunnel_id, 127662306a36Sopenharmony_ci u32 peer_tunnel_id, 127762306a36Sopenharmony_ci struct l2tp_tunnel_cfg *cfg, 127862306a36Sopenharmony_ci struct socket **sockp) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci int err = -EINVAL; 128162306a36Sopenharmony_ci struct socket *sock = NULL; 128262306a36Sopenharmony_ci struct udp_port_cfg udp_conf; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci switch (cfg->encap) { 128562306a36Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 128662306a36Sopenharmony_ci memset(&udp_conf, 0, sizeof(udp_conf)); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 128962306a36Sopenharmony_ci if (cfg->local_ip6 && cfg->peer_ip6) { 129062306a36Sopenharmony_ci udp_conf.family = AF_INET6; 129162306a36Sopenharmony_ci memcpy(&udp_conf.local_ip6, cfg->local_ip6, 129262306a36Sopenharmony_ci sizeof(udp_conf.local_ip6)); 129362306a36Sopenharmony_ci memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, 129462306a36Sopenharmony_ci sizeof(udp_conf.peer_ip6)); 129562306a36Sopenharmony_ci udp_conf.use_udp6_tx_checksums = 129662306a36Sopenharmony_ci !cfg->udp6_zero_tx_checksums; 129762306a36Sopenharmony_ci udp_conf.use_udp6_rx_checksums = 129862306a36Sopenharmony_ci !cfg->udp6_zero_rx_checksums; 129962306a36Sopenharmony_ci } else 130062306a36Sopenharmony_ci#endif 130162306a36Sopenharmony_ci { 130262306a36Sopenharmony_ci udp_conf.family = AF_INET; 130362306a36Sopenharmony_ci udp_conf.local_ip = cfg->local_ip; 130462306a36Sopenharmony_ci udp_conf.peer_ip = cfg->peer_ip; 130562306a36Sopenharmony_ci udp_conf.use_udp_checksums = cfg->use_udp_checksums; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci udp_conf.local_udp_port = htons(cfg->local_udp_port); 130962306a36Sopenharmony_ci udp_conf.peer_udp_port = htons(cfg->peer_udp_port); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci err = udp_sock_create(net, &udp_conf, &sock); 131262306a36Sopenharmony_ci if (err < 0) 131362306a36Sopenharmony_ci goto out; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 131862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 131962306a36Sopenharmony_ci if (cfg->local_ip6 && cfg->peer_ip6) { 132062306a36Sopenharmony_ci struct sockaddr_l2tpip6 ip6_addr = {0}; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 132362306a36Sopenharmony_ci IPPROTO_L2TP, &sock); 132462306a36Sopenharmony_ci if (err < 0) 132562306a36Sopenharmony_ci goto out; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci ip6_addr.l2tp_family = AF_INET6; 132862306a36Sopenharmony_ci memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6, 132962306a36Sopenharmony_ci sizeof(ip6_addr.l2tp_addr)); 133062306a36Sopenharmony_ci ip6_addr.l2tp_conn_id = tunnel_id; 133162306a36Sopenharmony_ci err = kernel_bind(sock, (struct sockaddr *)&ip6_addr, 133262306a36Sopenharmony_ci sizeof(ip6_addr)); 133362306a36Sopenharmony_ci if (err < 0) 133462306a36Sopenharmony_ci goto out; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci ip6_addr.l2tp_family = AF_INET6; 133762306a36Sopenharmony_ci memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6, 133862306a36Sopenharmony_ci sizeof(ip6_addr.l2tp_addr)); 133962306a36Sopenharmony_ci ip6_addr.l2tp_conn_id = peer_tunnel_id; 134062306a36Sopenharmony_ci err = kernel_connect(sock, 134162306a36Sopenharmony_ci (struct sockaddr *)&ip6_addr, 134262306a36Sopenharmony_ci sizeof(ip6_addr), 0); 134362306a36Sopenharmony_ci if (err < 0) 134462306a36Sopenharmony_ci goto out; 134562306a36Sopenharmony_ci } else 134662306a36Sopenharmony_ci#endif 134762306a36Sopenharmony_ci { 134862306a36Sopenharmony_ci struct sockaddr_l2tpip ip_addr = {0}; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 135162306a36Sopenharmony_ci IPPROTO_L2TP, &sock); 135262306a36Sopenharmony_ci if (err < 0) 135362306a36Sopenharmony_ci goto out; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci ip_addr.l2tp_family = AF_INET; 135662306a36Sopenharmony_ci ip_addr.l2tp_addr = cfg->local_ip; 135762306a36Sopenharmony_ci ip_addr.l2tp_conn_id = tunnel_id; 135862306a36Sopenharmony_ci err = kernel_bind(sock, (struct sockaddr *)&ip_addr, 135962306a36Sopenharmony_ci sizeof(ip_addr)); 136062306a36Sopenharmony_ci if (err < 0) 136162306a36Sopenharmony_ci goto out; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ip_addr.l2tp_family = AF_INET; 136462306a36Sopenharmony_ci ip_addr.l2tp_addr = cfg->peer_ip; 136562306a36Sopenharmony_ci ip_addr.l2tp_conn_id = peer_tunnel_id; 136662306a36Sopenharmony_ci err = kernel_connect(sock, (struct sockaddr *)&ip_addr, 136762306a36Sopenharmony_ci sizeof(ip_addr), 0); 136862306a36Sopenharmony_ci if (err < 0) 136962306a36Sopenharmony_ci goto out; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci break; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci default: 137462306a36Sopenharmony_ci goto out; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ciout: 137862306a36Sopenharmony_ci *sockp = sock; 137962306a36Sopenharmony_ci if (err < 0 && sock) { 138062306a36Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 138162306a36Sopenharmony_ci sock_release(sock); 138262306a36Sopenharmony_ci *sockp = NULL; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return err; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ciint l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, 138962306a36Sopenharmony_ci struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = NULL; 139262306a36Sopenharmony_ci int err; 139362306a36Sopenharmony_ci enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (cfg) 139662306a36Sopenharmony_ci encap = cfg->encap; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL); 139962306a36Sopenharmony_ci if (!tunnel) { 140062306a36Sopenharmony_ci err = -ENOMEM; 140162306a36Sopenharmony_ci goto err; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci tunnel->version = version; 140562306a36Sopenharmony_ci tunnel->tunnel_id = tunnel_id; 140662306a36Sopenharmony_ci tunnel->peer_tunnel_id = peer_tunnel_id; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci tunnel->magic = L2TP_TUNNEL_MAGIC; 140962306a36Sopenharmony_ci sprintf(&tunnel->name[0], "tunl %u", tunnel_id); 141062306a36Sopenharmony_ci spin_lock_init(&tunnel->hlist_lock); 141162306a36Sopenharmony_ci tunnel->acpt_newsess = true; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci tunnel->encap = encap; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci refcount_set(&tunnel->ref_count, 1); 141662306a36Sopenharmony_ci tunnel->fd = fd; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* Init delete workqueue struct */ 141962306a36Sopenharmony_ci INIT_WORK(&tunnel->del_work, l2tp_tunnel_del_work); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci INIT_LIST_HEAD(&tunnel->list); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci err = 0; 142462306a36Sopenharmony_cierr: 142562306a36Sopenharmony_ci if (tunnelp) 142662306a36Sopenharmony_ci *tunnelp = tunnel; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci return err; 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_create); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic int l2tp_validate_socket(const struct sock *sk, const struct net *net, 143362306a36Sopenharmony_ci enum l2tp_encap_type encap) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci if (!net_eq(sock_net(sk), net)) 143662306a36Sopenharmony_ci return -EINVAL; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (sk->sk_type != SOCK_DGRAM) 143962306a36Sopenharmony_ci return -EPROTONOSUPPORT; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) 144262306a36Sopenharmony_ci return -EPROTONOSUPPORT; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if ((encap == L2TP_ENCAPTYPE_UDP && sk->sk_protocol != IPPROTO_UDP) || 144562306a36Sopenharmony_ci (encap == L2TP_ENCAPTYPE_IP && sk->sk_protocol != IPPROTO_L2TP)) 144662306a36Sopenharmony_ci return -EPROTONOSUPPORT; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (sk->sk_user_data) 144962306a36Sopenharmony_ci return -EBUSY; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci return 0; 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ciint l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, 145562306a36Sopenharmony_ci struct l2tp_tunnel_cfg *cfg) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 145862306a36Sopenharmony_ci u32 tunnel_id = tunnel->tunnel_id; 145962306a36Sopenharmony_ci struct socket *sock; 146062306a36Sopenharmony_ci struct sock *sk; 146162306a36Sopenharmony_ci int ret; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 146462306a36Sopenharmony_ci ret = idr_alloc_u32(&pn->l2tp_tunnel_idr, NULL, &tunnel_id, tunnel_id, 146562306a36Sopenharmony_ci GFP_ATOMIC); 146662306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 146762306a36Sopenharmony_ci if (ret) 146862306a36Sopenharmony_ci return ret == -ENOSPC ? -EEXIST : ret; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (tunnel->fd < 0) { 147162306a36Sopenharmony_ci ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id, 147262306a36Sopenharmony_ci tunnel->peer_tunnel_id, cfg, 147362306a36Sopenharmony_ci &sock); 147462306a36Sopenharmony_ci if (ret < 0) 147562306a36Sopenharmony_ci goto err; 147662306a36Sopenharmony_ci } else { 147762306a36Sopenharmony_ci sock = sockfd_lookup(tunnel->fd, &ret); 147862306a36Sopenharmony_ci if (!sock) 147962306a36Sopenharmony_ci goto err; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci sk = sock->sk; 148362306a36Sopenharmony_ci lock_sock(sk); 148462306a36Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 148562306a36Sopenharmony_ci ret = l2tp_validate_socket(sk, net, tunnel->encap); 148662306a36Sopenharmony_ci if (ret < 0) 148762306a36Sopenharmony_ci goto err_inval_sock; 148862306a36Sopenharmony_ci rcu_assign_sk_user_data(sk, tunnel); 148962306a36Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 149262306a36Sopenharmony_ci struct udp_tunnel_sock_cfg udp_cfg = { 149362306a36Sopenharmony_ci .sk_user_data = tunnel, 149462306a36Sopenharmony_ci .encap_type = UDP_ENCAP_L2TPINUDP, 149562306a36Sopenharmony_ci .encap_rcv = l2tp_udp_encap_recv, 149662306a36Sopenharmony_ci .encap_destroy = l2tp_udp_encap_destroy, 149762306a36Sopenharmony_ci }; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci setup_udp_tunnel_sock(net, sock, &udp_cfg); 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci tunnel->old_sk_destruct = sk->sk_destruct; 150362306a36Sopenharmony_ci sk->sk_destruct = &l2tp_tunnel_destruct; 150462306a36Sopenharmony_ci sk->sk_allocation = GFP_ATOMIC; 150562306a36Sopenharmony_ci release_sock(sk); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci sock_hold(sk); 150862306a36Sopenharmony_ci tunnel->sock = sk; 150962306a36Sopenharmony_ci tunnel->l2tp_net = net; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 151262306a36Sopenharmony_ci idr_replace(&pn->l2tp_tunnel_idr, tunnel, tunnel->tunnel_id); 151362306a36Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci trace_register_tunnel(tunnel); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (tunnel->fd >= 0) 151862306a36Sopenharmony_ci sockfd_put(sock); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci return 0; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cierr_inval_sock: 152362306a36Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 152462306a36Sopenharmony_ci release_sock(sk); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (tunnel->fd < 0) 152762306a36Sopenharmony_ci sock_release(sock); 152862306a36Sopenharmony_ci else 152962306a36Sopenharmony_ci sockfd_put(sock); 153062306a36Sopenharmony_cierr: 153162306a36Sopenharmony_ci l2tp_tunnel_remove(net, tunnel); 153262306a36Sopenharmony_ci return ret; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_register); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci/* This function is used by the netlink TUNNEL_DELETE command. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_civoid l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) 153962306a36Sopenharmony_ci{ 154062306a36Sopenharmony_ci if (!test_and_set_bit(0, &tunnel->dead)) { 154162306a36Sopenharmony_ci trace_delete_tunnel(tunnel); 154262306a36Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 154362306a36Sopenharmony_ci queue_work(l2tp_wq, &tunnel->del_work); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_delete); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_civoid l2tp_session_delete(struct l2tp_session *session) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci if (test_and_set_bit(0, &session->dead)) 155162306a36Sopenharmony_ci return; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci trace_delete_session(session); 155462306a36Sopenharmony_ci l2tp_session_unhash(session); 155562306a36Sopenharmony_ci l2tp_session_queue_purge(session); 155662306a36Sopenharmony_ci if (session->session_close) 155762306a36Sopenharmony_ci (*session->session_close)(session); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_delete); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci/* We come here whenever a session's send_seq, cookie_len or 156462306a36Sopenharmony_ci * l2specific_type parameters are set. 156562306a36Sopenharmony_ci */ 156662306a36Sopenharmony_civoid l2tp_session_set_header_len(struct l2tp_session *session, int version) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci if (version == L2TP_HDR_VER_2) { 156962306a36Sopenharmony_ci session->hdr_len = 6; 157062306a36Sopenharmony_ci if (session->send_seq) 157162306a36Sopenharmony_ci session->hdr_len += 4; 157262306a36Sopenharmony_ci } else { 157362306a36Sopenharmony_ci session->hdr_len = 4 + session->cookie_len; 157462306a36Sopenharmony_ci session->hdr_len += l2tp_get_l2specific_len(session); 157562306a36Sopenharmony_ci if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP) 157662306a36Sopenharmony_ci session->hdr_len += 4; 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_set_header_len); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistruct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, 158262306a36Sopenharmony_ci u32 peer_session_id, struct l2tp_session_cfg *cfg) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci struct l2tp_session *session; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci session = kzalloc(sizeof(*session) + priv_size, GFP_KERNEL); 158762306a36Sopenharmony_ci if (session) { 158862306a36Sopenharmony_ci session->magic = L2TP_SESSION_MAGIC; 158962306a36Sopenharmony_ci session->tunnel = tunnel; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci session->session_id = session_id; 159262306a36Sopenharmony_ci session->peer_session_id = peer_session_id; 159362306a36Sopenharmony_ci session->nr = 0; 159462306a36Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) 159562306a36Sopenharmony_ci session->nr_max = 0xffff; 159662306a36Sopenharmony_ci else 159762306a36Sopenharmony_ci session->nr_max = 0xffffff; 159862306a36Sopenharmony_ci session->nr_window_size = session->nr_max / 2; 159962306a36Sopenharmony_ci session->nr_oos_count_max = 4; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Use NR of first received packet */ 160262306a36Sopenharmony_ci session->reorder_skip = 1; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci sprintf(&session->name[0], "sess %u/%u", 160562306a36Sopenharmony_ci tunnel->tunnel_id, session->session_id); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci skb_queue_head_init(&session->reorder_q); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci INIT_HLIST_NODE(&session->hlist); 161062306a36Sopenharmony_ci INIT_HLIST_NODE(&session->global_hlist); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (cfg) { 161362306a36Sopenharmony_ci session->pwtype = cfg->pw_type; 161462306a36Sopenharmony_ci session->send_seq = cfg->send_seq; 161562306a36Sopenharmony_ci session->recv_seq = cfg->recv_seq; 161662306a36Sopenharmony_ci session->lns_mode = cfg->lns_mode; 161762306a36Sopenharmony_ci session->reorder_timeout = cfg->reorder_timeout; 161862306a36Sopenharmony_ci session->l2specific_type = cfg->l2specific_type; 161962306a36Sopenharmony_ci session->cookie_len = cfg->cookie_len; 162062306a36Sopenharmony_ci memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len); 162162306a36Sopenharmony_ci session->peer_cookie_len = cfg->peer_cookie_len; 162262306a36Sopenharmony_ci memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len); 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci refcount_set(&session->ref_count, 1); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci return session; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_create); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci/***************************************************************************** 163762306a36Sopenharmony_ci * Init and cleanup 163862306a36Sopenharmony_ci *****************************************************************************/ 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cistatic __net_init int l2tp_init_net(struct net *net) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci struct l2tp_net *pn = net_generic(net, l2tp_net_id); 164362306a36Sopenharmony_ci int hash; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci idr_init(&pn->l2tp_tunnel_idr); 164662306a36Sopenharmony_ci spin_lock_init(&pn->l2tp_tunnel_idr_lock); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 164962306a36Sopenharmony_ci INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci spin_lock_init(&pn->l2tp_session_hlist_lock); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci return 0; 165462306a36Sopenharmony_ci} 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cistatic __net_exit void l2tp_exit_net(struct net *net) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 165962306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = NULL; 166062306a36Sopenharmony_ci unsigned long tunnel_id, tmp; 166162306a36Sopenharmony_ci int hash; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci rcu_read_lock_bh(); 166462306a36Sopenharmony_ci idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) { 166562306a36Sopenharmony_ci if (tunnel) 166662306a36Sopenharmony_ci l2tp_tunnel_delete(tunnel); 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci rcu_read_unlock_bh(); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (l2tp_wq) 167162306a36Sopenharmony_ci flush_workqueue(l2tp_wq); 167262306a36Sopenharmony_ci rcu_barrier(); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 167562306a36Sopenharmony_ci WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash])); 167662306a36Sopenharmony_ci idr_destroy(&pn->l2tp_tunnel_idr); 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic struct pernet_operations l2tp_net_ops = { 168062306a36Sopenharmony_ci .init = l2tp_init_net, 168162306a36Sopenharmony_ci .exit = l2tp_exit_net, 168262306a36Sopenharmony_ci .id = &l2tp_net_id, 168362306a36Sopenharmony_ci .size = sizeof(struct l2tp_net), 168462306a36Sopenharmony_ci}; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic int __init l2tp_init(void) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci int rc = 0; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci rc = register_pernet_device(&l2tp_net_ops); 169162306a36Sopenharmony_ci if (rc) 169262306a36Sopenharmony_ci goto out; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); 169562306a36Sopenharmony_ci if (!l2tp_wq) { 169662306a36Sopenharmony_ci pr_err("alloc_workqueue failed\n"); 169762306a36Sopenharmony_ci unregister_pernet_device(&l2tp_net_ops); 169862306a36Sopenharmony_ci rc = -ENOMEM; 169962306a36Sopenharmony_ci goto out; 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci pr_info("L2TP core driver, %s\n", L2TP_DRV_VERSION); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ciout: 170562306a36Sopenharmony_ci return rc; 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic void __exit l2tp_exit(void) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci unregister_pernet_device(&l2tp_net_ops); 171162306a36Sopenharmony_ci if (l2tp_wq) { 171262306a36Sopenharmony_ci destroy_workqueue(l2tp_wq); 171362306a36Sopenharmony_ci l2tp_wq = NULL; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cimodule_init(l2tp_init); 171862306a36Sopenharmony_cimodule_exit(l2tp_exit); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ciMODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 172162306a36Sopenharmony_ciMODULE_DESCRIPTION("L2TP core"); 172262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 172362306a36Sopenharmony_ciMODULE_VERSION(L2TP_DRV_VERSION); 1724