18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* L2TP core. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008,2009,2010 Katalix Systems Ltd 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file contains some code of the original L2TPv2 pppol2tp 78c2ecf20Sopenharmony_ci * driver, which has the following copyright: 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Authors: Martijn van Oosterhout <kleptog@svana.org> 108c2ecf20Sopenharmony_ci * James Chapman (jchapman@katalix.com) 118c2ecf20Sopenharmony_ci * Contributors: 128c2ecf20Sopenharmony_ci * Michal Ostrowski <mostrows@speakeasy.net> 138c2ecf20Sopenharmony_ci * Arnaldo Carvalho de Melo <acme@xconectiva.com.br> 148c2ecf20Sopenharmony_ci * David S. Miller (davem@redhat.com) 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci#include <linux/list.h> 228c2ecf20Sopenharmony_ci#include <linux/rculist.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 278c2ecf20Sopenharmony_ci#include <linux/kthread.h> 288c2ecf20Sopenharmony_ci#include <linux/sched.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/errno.h> 318c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 348c2ecf20Sopenharmony_ci#include <linux/net.h> 358c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 368c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 378c2ecf20Sopenharmony_ci#include <linux/init.h> 388c2ecf20Sopenharmony_ci#include <linux/in.h> 398c2ecf20Sopenharmony_ci#include <linux/ip.h> 408c2ecf20Sopenharmony_ci#include <linux/udp.h> 418c2ecf20Sopenharmony_ci#include <linux/l2tp.h> 428c2ecf20Sopenharmony_ci#include <linux/hash.h> 438c2ecf20Sopenharmony_ci#include <linux/sort.h> 448c2ecf20Sopenharmony_ci#include <linux/file.h> 458c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 468c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 478c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 488c2ecf20Sopenharmony_ci#include <net/dst.h> 498c2ecf20Sopenharmony_ci#include <net/ip.h> 508c2ecf20Sopenharmony_ci#include <net/udp.h> 518c2ecf20Sopenharmony_ci#include <net/udp_tunnel.h> 528c2ecf20Sopenharmony_ci#include <net/inet_common.h> 538c2ecf20Sopenharmony_ci#include <net/xfrm.h> 548c2ecf20Sopenharmony_ci#include <net/protocol.h> 558c2ecf20Sopenharmony_ci#include <net/inet6_connection_sock.h> 568c2ecf20Sopenharmony_ci#include <net/inet_ecn.h> 578c2ecf20Sopenharmony_ci#include <net/ip6_route.h> 588c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 618c2ecf20Sopenharmony_ci#include <linux/atomic.h> 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#include "l2tp_core.h" 648c2ecf20Sopenharmony_ci#include "trace.h" 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 678c2ecf20Sopenharmony_ci#include "trace.h" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define L2TP_DRV_VERSION "V2.0" 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* L2TP header constants */ 728c2ecf20Sopenharmony_ci#define L2TP_HDRFLAG_T 0x8000 738c2ecf20Sopenharmony_ci#define L2TP_HDRFLAG_L 0x4000 748c2ecf20Sopenharmony_ci#define L2TP_HDRFLAG_S 0x0800 758c2ecf20Sopenharmony_ci#define L2TP_HDRFLAG_O 0x0200 768c2ecf20Sopenharmony_ci#define L2TP_HDRFLAG_P 0x0100 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define L2TP_HDR_VER_MASK 0x000F 798c2ecf20Sopenharmony_ci#define L2TP_HDR_VER_2 0x0002 808c2ecf20Sopenharmony_ci#define L2TP_HDR_VER_3 0x0003 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* L2TPv3 default L2-specific sublayer */ 838c2ecf20Sopenharmony_ci#define L2TP_SLFLAG_S 0x40000000 848c2ecf20Sopenharmony_ci#define L2TP_SL_SEQ_MASK 0x00ffffff 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define L2TP_HDR_SIZE_MAX 14 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Default trace flags */ 898c2ecf20Sopenharmony_ci#define L2TP_DEFAULT_DEBUG_FLAGS 0 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* Private data stored for received packets in the skb. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistruct l2tp_skb_cb { 948c2ecf20Sopenharmony_ci u32 ns; 958c2ecf20Sopenharmony_ci u16 has_seq; 968c2ecf20Sopenharmony_ci u16 length; 978c2ecf20Sopenharmony_ci unsigned long expires; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define L2TP_SKB_CB(skb) ((struct l2tp_skb_cb *)&(skb)->cb[sizeof(struct inet_skb_parm)]) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic struct workqueue_struct *l2tp_wq; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* per-net private data for this module */ 1058c2ecf20Sopenharmony_cistatic unsigned int l2tp_net_id; 1068c2ecf20Sopenharmony_cistruct l2tp_net { 1078c2ecf20Sopenharmony_ci /* Lock for write access to l2tp_tunnel_idr */ 1088c2ecf20Sopenharmony_ci spinlock_t l2tp_tunnel_idr_lock; 1098c2ecf20Sopenharmony_ci struct idr l2tp_tunnel_idr; 1108c2ecf20Sopenharmony_ci struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; 1118c2ecf20Sopenharmony_ci /* Lock for write access to l2tp_session_hlist */ 1128c2ecf20Sopenharmony_ci spinlock_t l2tp_session_hlist_lock; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1168c2ecf20Sopenharmony_cistatic bool l2tp_sk_is_v6(struct sock *sk) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return sk->sk_family == PF_INET6 && 1198c2ecf20Sopenharmony_ci !ipv6_addr_v4mapped(&sk->sk_v6_daddr); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci#endif 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline struct l2tp_net *l2tp_pernet(const struct net *net) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return net_generic(net, l2tp_net_id); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* Session hash global list for L2TPv3. 1298c2ecf20Sopenharmony_ci * The session_id SHOULD be random according to RFC3931, but several 1308c2ecf20Sopenharmony_ci * L2TP implementations use incrementing session_ids. So we do a real 1318c2ecf20Sopenharmony_ci * hash on the session_id, rather than a simple bitmask. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic inline struct hlist_head * 1348c2ecf20Sopenharmony_cil2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Session hash list. 1408c2ecf20Sopenharmony_ci * The session_id SHOULD be random according to RFC2661, but several 1418c2ecf20Sopenharmony_ci * L2TP implementations (Cisco and Microsoft) use incrementing 1428c2ecf20Sopenharmony_ci * session_ids. So we do a real hash on the session_id, rather than a 1438c2ecf20Sopenharmony_ci * simple bitmask. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic inline struct hlist_head * 1468c2ecf20Sopenharmony_cil2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci trace_free_tunnel(tunnel); 1548c2ecf20Sopenharmony_ci sock_put(tunnel->sock); 1558c2ecf20Sopenharmony_ci /* the tunnel is freed in the socket destructor */ 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void l2tp_session_free(struct l2tp_session *session) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci trace_free_session(session); 1618c2ecf20Sopenharmony_ci if (session->tunnel) 1628c2ecf20Sopenharmony_ci l2tp_tunnel_dec_refcount(session->tunnel); 1638c2ecf20Sopenharmony_ci kfree(session); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistruct l2tp_tunnel *l2tp_sk_to_tunnel(struct sock *sk) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = sk->sk_user_data; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (tunnel) 1718c2ecf20Sopenharmony_ci if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC)) 1728c2ecf20Sopenharmony_ci return NULL; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return tunnel; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_sk_to_tunnel); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_civoid l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci refcount_inc(&tunnel->ref_count); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_inc_refcount); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_civoid l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&tunnel->ref_count)) 1878c2ecf20Sopenharmony_ci l2tp_tunnel_free(tunnel); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_dec_refcount); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_civoid l2tp_session_inc_refcount(struct l2tp_session *session) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci refcount_inc(&session->ref_count); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_inc_refcount); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_civoid l2tp_session_dec_refcount(struct l2tp_session *session) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&session->ref_count)) 2008c2ecf20Sopenharmony_ci l2tp_session_free(session); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_dec_refcount); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* Lookup a tunnel. A new reference is held on the returned tunnel. */ 2058c2ecf20Sopenharmony_cistruct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci const struct l2tp_net *pn = l2tp_pernet(net); 2088c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 2118c2ecf20Sopenharmony_ci tunnel = idr_find(&pn->l2tp_tunnel_idr, tunnel_id); 2128c2ecf20Sopenharmony_ci if (tunnel && refcount_inc_not_zero(&tunnel->ref_count)) { 2138c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2148c2ecf20Sopenharmony_ci return tunnel; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return NULL; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistruct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 2258c2ecf20Sopenharmony_ci unsigned long tunnel_id, tmp; 2268c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel; 2278c2ecf20Sopenharmony_ci int count = 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 2308c2ecf20Sopenharmony_ci idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) { 2318c2ecf20Sopenharmony_ci if (tunnel && ++count > nth && 2328c2ecf20Sopenharmony_ci refcount_inc_not_zero(&tunnel->ref_count)) { 2338c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2348c2ecf20Sopenharmony_ci return tunnel; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return NULL; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistruct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel, 2448c2ecf20Sopenharmony_ci u32 session_id) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct hlist_head *session_list; 2478c2ecf20Sopenharmony_ci struct l2tp_session *session; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci session_list = l2tp_session_id_hash(tunnel, session_id); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci read_lock_bh(&tunnel->hlist_lock); 2528c2ecf20Sopenharmony_ci hlist_for_each_entry(session, session_list, hlist) 2538c2ecf20Sopenharmony_ci if (session->session_id == session_id) { 2548c2ecf20Sopenharmony_ci l2tp_session_inc_refcount(session); 2558c2ecf20Sopenharmony_ci read_unlock_bh(&tunnel->hlist_lock); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return session; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci read_unlock_bh(&tunnel->hlist_lock); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return NULL; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_get_session); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistruct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct hlist_head *session_list; 2688c2ecf20Sopenharmony_ci struct l2tp_session *session; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci session_list = l2tp_session_id_hash_2(l2tp_pernet(net), session_id); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 2738c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(session, session_list, global_hlist) 2748c2ecf20Sopenharmony_ci if (session->session_id == session_id) { 2758c2ecf20Sopenharmony_ci l2tp_session_inc_refcount(session); 2768c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return session; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return NULL; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistruct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci int hash; 2898c2ecf20Sopenharmony_ci struct l2tp_session *session; 2908c2ecf20Sopenharmony_ci int count = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci read_lock_bh(&tunnel->hlist_lock); 2938c2ecf20Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 2948c2ecf20Sopenharmony_ci hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { 2958c2ecf20Sopenharmony_ci if (++count > nth) { 2968c2ecf20Sopenharmony_ci l2tp_session_inc_refcount(session); 2978c2ecf20Sopenharmony_ci read_unlock_bh(&tunnel->hlist_lock); 2988c2ecf20Sopenharmony_ci return session; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci read_unlock_bh(&tunnel->hlist_lock); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return NULL; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get_nth); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* Lookup a session by interface name. 3108c2ecf20Sopenharmony_ci * This is very inefficient but is only used by management interfaces. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_cistruct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, 3138c2ecf20Sopenharmony_ci const char *ifname) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 3168c2ecf20Sopenharmony_ci int hash; 3178c2ecf20Sopenharmony_ci struct l2tp_session *session; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 3208c2ecf20Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { 3218c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { 3228c2ecf20Sopenharmony_ci if (!strcmp(session->ifname, ifname)) { 3238c2ecf20Sopenharmony_ci l2tp_session_inc_refcount(session); 3248c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return session; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return NULL; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint l2tp_session_register(struct l2tp_session *session, 3388c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct l2tp_session *session_walk; 3418c2ecf20Sopenharmony_ci struct hlist_head *g_head; 3428c2ecf20Sopenharmony_ci struct hlist_head *head; 3438c2ecf20Sopenharmony_ci struct l2tp_net *pn; 3448c2ecf20Sopenharmony_ci int err; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci head = l2tp_session_id_hash(tunnel, session->session_id); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci write_lock_bh(&tunnel->hlist_lock); 3498c2ecf20Sopenharmony_ci if (!tunnel->acpt_newsess) { 3508c2ecf20Sopenharmony_ci err = -ENODEV; 3518c2ecf20Sopenharmony_ci goto err_tlock; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci hlist_for_each_entry(session_walk, head, hlist) 3558c2ecf20Sopenharmony_ci if (session_walk->session_id == session->session_id) { 3568c2ecf20Sopenharmony_ci err = -EEXIST; 3578c2ecf20Sopenharmony_ci goto err_tlock; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_3) { 3618c2ecf20Sopenharmony_ci pn = l2tp_pernet(tunnel->l2tp_net); 3628c2ecf20Sopenharmony_ci g_head = l2tp_session_id_hash_2(pn, session->session_id); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci spin_lock_bh(&pn->l2tp_session_hlist_lock); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* IP encap expects session IDs to be globally unique, while 3678c2ecf20Sopenharmony_ci * UDP encap doesn't. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci hlist_for_each_entry(session_walk, g_head, global_hlist) 3708c2ecf20Sopenharmony_ci if (session_walk->session_id == session->session_id && 3718c2ecf20Sopenharmony_ci (session_walk->tunnel->encap == L2TP_ENCAPTYPE_IP || 3728c2ecf20Sopenharmony_ci tunnel->encap == L2TP_ENCAPTYPE_IP)) { 3738c2ecf20Sopenharmony_ci err = -EEXIST; 3748c2ecf20Sopenharmony_ci goto err_tlock_pnlock; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 3788c2ecf20Sopenharmony_ci hlist_add_head_rcu(&session->global_hlist, g_head); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci hlist_add_head(&session->hlist, head); 3868c2ecf20Sopenharmony_ci write_unlock_bh(&tunnel->hlist_lock); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci trace_register_session(session); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cierr_tlock_pnlock: 3938c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 3948c2ecf20Sopenharmony_cierr_tlock: 3958c2ecf20Sopenharmony_ci write_unlock_bh(&tunnel->hlist_lock); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return err; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_register); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/***************************************************************************** 4028c2ecf20Sopenharmony_ci * Receive data handling 4038c2ecf20Sopenharmony_ci *****************************************************************************/ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* Queue a skb in order. We come here only if the skb has an L2TP sequence 4068c2ecf20Sopenharmony_ci * number. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *skb) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct sk_buff *skbp; 4118c2ecf20Sopenharmony_ci struct sk_buff *tmp; 4128c2ecf20Sopenharmony_ci u32 ns = L2TP_SKB_CB(skb)->ns; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci spin_lock_bh(&session->reorder_q.lock); 4158c2ecf20Sopenharmony_ci skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { 4168c2ecf20Sopenharmony_ci if (L2TP_SKB_CB(skbp)->ns > ns) { 4178c2ecf20Sopenharmony_ci __skb_queue_before(&session->reorder_q, skbp, skb); 4188c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_oos_packets); 4198c2ecf20Sopenharmony_ci goto out; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci __skb_queue_tail(&session->reorder_q, skb); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ciout: 4268c2ecf20Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* Dequeue a single skb. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_cistatic void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *skb) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 4348c2ecf20Sopenharmony_ci int length = L2TP_SKB_CB(skb)->length; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* We're about to requeue the skb, so return resources 4378c2ecf20Sopenharmony_ci * to its current owner (a socket receive buffer). 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci skb_orphan(skb); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci atomic_long_inc(&tunnel->stats.rx_packets); 4428c2ecf20Sopenharmony_ci atomic_long_add(length, &tunnel->stats.rx_bytes); 4438c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_packets); 4448c2ecf20Sopenharmony_ci atomic_long_add(length, &session->stats.rx_bytes); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 4478c2ecf20Sopenharmony_ci /* Bump our Nr */ 4488c2ecf20Sopenharmony_ci session->nr++; 4498c2ecf20Sopenharmony_ci session->nr &= session->nr_max; 4508c2ecf20Sopenharmony_ci trace_session_seqnum_update(session); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* call private receive handler */ 4548c2ecf20Sopenharmony_ci if (session->recv_skb) 4558c2ecf20Sopenharmony_ci (*session->recv_skb)(session, skb, L2TP_SKB_CB(skb)->length); 4568c2ecf20Sopenharmony_ci else 4578c2ecf20Sopenharmony_ci kfree_skb(skb); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* Dequeue skbs from the session's reorder_q, subject to packet order. 4618c2ecf20Sopenharmony_ci * Skbs that have been in the queue for too long are simply discarded. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_cistatic void l2tp_recv_dequeue(struct l2tp_session *session) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct sk_buff *skb; 4668c2ecf20Sopenharmony_ci struct sk_buff *tmp; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* If the pkt at the head of the queue has the nr that we 4698c2ecf20Sopenharmony_ci * expect to send up next, dequeue it and any other 4708c2ecf20Sopenharmony_ci * in-sequence packets behind it. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistart: 4738c2ecf20Sopenharmony_ci spin_lock_bh(&session->reorder_q.lock); 4748c2ecf20Sopenharmony_ci skb_queue_walk_safe(&session->reorder_q, skb, tmp) { 4758c2ecf20Sopenharmony_ci struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* If the packet has been pending on the queue for too long, discard it */ 4788c2ecf20Sopenharmony_ci if (time_after(jiffies, cb->expires)) { 4798c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 4808c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 4818c2ecf20Sopenharmony_ci trace_session_pkt_expired(session, cb->ns); 4828c2ecf20Sopenharmony_ci session->reorder_skip = 1; 4838c2ecf20Sopenharmony_ci __skb_unlink(skb, &session->reorder_q); 4848c2ecf20Sopenharmony_ci kfree_skb(skb); 4858c2ecf20Sopenharmony_ci continue; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (cb->has_seq) { 4898c2ecf20Sopenharmony_ci if (session->reorder_skip) { 4908c2ecf20Sopenharmony_ci session->reorder_skip = 0; 4918c2ecf20Sopenharmony_ci session->nr = cb->ns; 4928c2ecf20Sopenharmony_ci trace_session_seqnum_reset(session); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci if (cb->ns != session->nr) 4958c2ecf20Sopenharmony_ci goto out; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci __skb_unlink(skb, &session->reorder_q); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* Process the skb. We release the queue lock while we 5008c2ecf20Sopenharmony_ci * do so to let other contexts process the queue. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 5038c2ecf20Sopenharmony_ci l2tp_recv_dequeue_skb(session, skb); 5048c2ecf20Sopenharmony_ci goto start; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciout: 5088c2ecf20Sopenharmony_ci spin_unlock_bh(&session->reorder_q.lock); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci u32 nws; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (nr >= session->nr) 5168c2ecf20Sopenharmony_ci nws = nr - session->nr; 5178c2ecf20Sopenharmony_ci else 5188c2ecf20Sopenharmony_ci nws = (session->nr_max + 1) - (session->nr - nr); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return nws < session->nr_window_size; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* If packet has sequence numbers, queue it if acceptable. Returns 0 if 5248c2ecf20Sopenharmony_ci * acceptable, else non-zero. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_cistatic int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (!l2tp_seq_check_rx_window(session, cb->ns)) { 5318c2ecf20Sopenharmony_ci /* Packet sequence number is outside allowed window. 5328c2ecf20Sopenharmony_ci * Discard it. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci trace_session_pkt_outside_rx_window(session, cb->ns); 5358c2ecf20Sopenharmony_ci goto discard; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (session->reorder_timeout != 0) { 5398c2ecf20Sopenharmony_ci /* Packet reordering enabled. Add skb to session's 5408c2ecf20Sopenharmony_ci * reorder queue, in order of ns. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci l2tp_recv_queue_skb(session, skb); 5438c2ecf20Sopenharmony_ci goto out; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Packet reordering disabled. Discard out-of-sequence packets, while 5478c2ecf20Sopenharmony_ci * tracking the number if in-sequence packets after the first OOS packet 5488c2ecf20Sopenharmony_ci * is seen. After nr_oos_count_max in-sequence packets, reset the 5498c2ecf20Sopenharmony_ci * sequence number to re-enable packet reception. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci if (cb->ns == session->nr) { 5528c2ecf20Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci u32 nr_oos = cb->ns; 5558c2ecf20Sopenharmony_ci u32 nr_next = (session->nr_oos + 1) & session->nr_max; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (nr_oos == nr_next) 5588c2ecf20Sopenharmony_ci session->nr_oos_count++; 5598c2ecf20Sopenharmony_ci else 5608c2ecf20Sopenharmony_ci session->nr_oos_count = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci session->nr_oos = nr_oos; 5638c2ecf20Sopenharmony_ci if (session->nr_oos_count > session->nr_oos_count_max) { 5648c2ecf20Sopenharmony_ci session->reorder_skip = 1; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci if (!session->reorder_skip) { 5678c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 5688c2ecf20Sopenharmony_ci trace_session_pkt_oos(session, cb->ns); 5698c2ecf20Sopenharmony_ci goto discard; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ciout: 5758c2ecf20Sopenharmony_ci return 0; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cidiscard: 5788c2ecf20Sopenharmony_ci return 1; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/* Do receive processing of L2TP data frames. We handle both L2TPv2 5828c2ecf20Sopenharmony_ci * and L2TPv3 data frames here. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci * L2TPv2 Data Message Header 5858c2ecf20Sopenharmony_ci * 5868c2ecf20Sopenharmony_ci * 0 1 2 3 5878c2ecf20Sopenharmony_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 5888c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5898c2ecf20Sopenharmony_ci * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) | 5908c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5918c2ecf20Sopenharmony_ci * | Tunnel ID | Session ID | 5928c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5938c2ecf20Sopenharmony_ci * | Ns (opt) | Nr (opt) | 5948c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5958c2ecf20Sopenharmony_ci * | Offset Size (opt) | Offset pad... (opt) 5968c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5978c2ecf20Sopenharmony_ci * 5988c2ecf20Sopenharmony_ci * Data frames are marked by T=0. All other fields are the same as 5998c2ecf20Sopenharmony_ci * those in L2TP control frames. 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * L2TPv3 Data Message Header 6028c2ecf20Sopenharmony_ci * 6038c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6048c2ecf20Sopenharmony_ci * | L2TP Session Header | 6058c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6068c2ecf20Sopenharmony_ci * | L2-Specific Sublayer | 6078c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6088c2ecf20Sopenharmony_ci * | Tunnel Payload ... 6098c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * L2TPv3 Session Header Over IP 6128c2ecf20Sopenharmony_ci * 6138c2ecf20Sopenharmony_ci * 0 1 2 3 6148c2ecf20Sopenharmony_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 6158c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6168c2ecf20Sopenharmony_ci * | Session ID | 6178c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6188c2ecf20Sopenharmony_ci * | Cookie (optional, maximum 64 bits)... 6198c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6208c2ecf20Sopenharmony_ci * | 6218c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * L2TPv3 L2-Specific Sublayer Format 6248c2ecf20Sopenharmony_ci * 6258c2ecf20Sopenharmony_ci * 0 1 2 3 6268c2ecf20Sopenharmony_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 6278c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6288c2ecf20Sopenharmony_ci * |x|S|x|x|x|x|x|x| Sequence Number | 6298c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * Cookie value and sublayer format are negotiated with the peer when 6328c2ecf20Sopenharmony_ci * the session is set up. Unlike L2TPv2, we do not need to parse the 6338c2ecf20Sopenharmony_ci * packet header to determine if optional fields are present. 6348c2ecf20Sopenharmony_ci * 6358c2ecf20Sopenharmony_ci * Caller must already have parsed the frame and determined that it is 6368c2ecf20Sopenharmony_ci * a data (not control) frame before coming here. Fields up to the 6378c2ecf20Sopenharmony_ci * session-id have already been parsed and ptr points to the data 6388c2ecf20Sopenharmony_ci * after the session-id. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_civoid l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, 6418c2ecf20Sopenharmony_ci unsigned char *ptr, unsigned char *optr, u16 hdrflags, 6428c2ecf20Sopenharmony_ci int length) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 6458c2ecf20Sopenharmony_ci int offset; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Parse and check optional cookie */ 6488c2ecf20Sopenharmony_ci if (session->peer_cookie_len > 0) { 6498c2ecf20Sopenharmony_ci if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { 6508c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: cookie mismatch (%u/%u). Discarding.\n", 6518c2ecf20Sopenharmony_ci tunnel->name, tunnel->tunnel_id, 6528c2ecf20Sopenharmony_ci session->session_id); 6538c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_cookie_discards); 6548c2ecf20Sopenharmony_ci goto discard; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci ptr += session->peer_cookie_len; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Handle the optional sequence numbers. Sequence numbers are 6608c2ecf20Sopenharmony_ci * in different places for L2TPv2 and L2TPv3. 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * If we are the LAC, enable/disable sequence numbers under 6638c2ecf20Sopenharmony_ci * the control of the LNS. If no sequence numbers present but 6648c2ecf20Sopenharmony_ci * we were expecting them, discard frame. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 0; 6678c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 6688c2ecf20Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_S) { 6698c2ecf20Sopenharmony_ci /* Store L2TP info in the skb */ 6708c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->ns = ntohs(*(__be16 *)ptr); 6718c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 1; 6728c2ecf20Sopenharmony_ci ptr += 2; 6738c2ecf20Sopenharmony_ci /* Skip past nr in the header */ 6748c2ecf20Sopenharmony_ci ptr += 2; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 6788c2ecf20Sopenharmony_ci u32 l2h = ntohl(*(__be32 *)ptr); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (l2h & 0x40000000) { 6818c2ecf20Sopenharmony_ci /* Store L2TP info in the skb */ 6828c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->ns = l2h & 0x00ffffff; 6838c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->has_seq = 1; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci ptr += 4; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 6898c2ecf20Sopenharmony_ci /* Received a packet with sequence numbers. If we're the LAC, 6908c2ecf20Sopenharmony_ci * check if we sre sending sequence numbers and if not, 6918c2ecf20Sopenharmony_ci * configure it so. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (!session->lns_mode && !session->send_seq) { 6948c2ecf20Sopenharmony_ci trace_session_seqnum_lns_enable(session); 6958c2ecf20Sopenharmony_ci session->send_seq = 1; 6968c2ecf20Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci /* No sequence numbers. 7008c2ecf20Sopenharmony_ci * If user has configured mandatory sequence numbers, discard. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci if (session->recv_seq) { 7038c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n", 7048c2ecf20Sopenharmony_ci session->name); 7058c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 7068c2ecf20Sopenharmony_ci goto discard; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* If we're the LAC and we're sending sequence numbers, the 7108c2ecf20Sopenharmony_ci * LNS has requested that we no longer send sequence numbers. 7118c2ecf20Sopenharmony_ci * If we're the LNS and we're sending sequence numbers, the 7128c2ecf20Sopenharmony_ci * LAC is broken. Discard the frame. 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_ci if (!session->lns_mode && session->send_seq) { 7158c2ecf20Sopenharmony_ci trace_session_seqnum_lns_disable(session); 7168c2ecf20Sopenharmony_ci session->send_seq = 0; 7178c2ecf20Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 7188c2ecf20Sopenharmony_ci } else if (session->send_seq) { 7198c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n", 7208c2ecf20Sopenharmony_ci session->name); 7218c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_seq_discards); 7228c2ecf20Sopenharmony_ci goto discard; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Session data offset is defined only for L2TPv2 and is 7278c2ecf20Sopenharmony_ci * indicated by an optional 16-bit value in the header. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 7308c2ecf20Sopenharmony_ci /* If offset bit set, skip it. */ 7318c2ecf20Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_O) { 7328c2ecf20Sopenharmony_ci offset = ntohs(*(__be16 *)ptr); 7338c2ecf20Sopenharmony_ci ptr += 2 + offset; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci offset = ptr - optr; 7388c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, offset)) 7398c2ecf20Sopenharmony_ci goto discard; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci __skb_pull(skb, offset); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Prepare skb for adding to the session's reorder_q. Hold 7448c2ecf20Sopenharmony_ci * packets for max reorder_timeout or 1 second if not 7458c2ecf20Sopenharmony_ci * reordering. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->length = length; 7488c2ecf20Sopenharmony_ci L2TP_SKB_CB(skb)->expires = jiffies + 7498c2ecf20Sopenharmony_ci (session->reorder_timeout ? session->reorder_timeout : HZ); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Add packet to the session's receive queue. Reordering is done here, if 7528c2ecf20Sopenharmony_ci * enabled. Saved L2TP protocol info is stored in skb->sb[]. 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_ci if (L2TP_SKB_CB(skb)->has_seq) { 7558c2ecf20Sopenharmony_ci if (l2tp_recv_data_seq(session, skb)) 7568c2ecf20Sopenharmony_ci goto discard; 7578c2ecf20Sopenharmony_ci } else { 7588c2ecf20Sopenharmony_ci /* No sequence numbers. Add the skb to the tail of the 7598c2ecf20Sopenharmony_ci * reorder queue. This ensures that it will be 7608c2ecf20Sopenharmony_ci * delivered after all previous sequenced skbs. 7618c2ecf20Sopenharmony_ci */ 7628c2ecf20Sopenharmony_ci skb_queue_tail(&session->reorder_q, skb); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Try to dequeue as many skbs from reorder_q as we can. */ 7668c2ecf20Sopenharmony_ci l2tp_recv_dequeue(session); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cidiscard: 7718c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 7728c2ecf20Sopenharmony_ci kfree_skb(skb); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_recv_common); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci/* Drop skbs from the session's reorder_q 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_cistatic void l2tp_session_queue_purge(struct l2tp_session *session) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&session->reorder_q))) { 7838c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.rx_errors); 7848c2ecf20Sopenharmony_ci kfree_skb(skb); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci/* Internal UDP receive frame. Do the real work of receiving an L2TP data frame 7898c2ecf20Sopenharmony_ci * here. The skb is not on a list when we get here. 7908c2ecf20Sopenharmony_ci * Returns 0 if the packet was a data packet and was successfully passed on. 7918c2ecf20Sopenharmony_ci * Returns 1 if the packet was not a good data packet and could not be 7928c2ecf20Sopenharmony_ci * forwarded. All such packets are passed up to userspace to deal with. 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_cistatic int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct l2tp_session *session = NULL; 7978c2ecf20Sopenharmony_ci unsigned char *ptr, *optr; 7988c2ecf20Sopenharmony_ci u16 hdrflags; 7998c2ecf20Sopenharmony_ci u32 tunnel_id, session_id; 8008c2ecf20Sopenharmony_ci u16 version; 8018c2ecf20Sopenharmony_ci int length; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* UDP has verifed checksum */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* UDP always verifies the packet length. */ 8068c2ecf20Sopenharmony_ci __skb_pull(skb, sizeof(struct udphdr)); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Short packet? */ 8098c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) { 8108c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: recv short packet (len=%d)\n", 8118c2ecf20Sopenharmony_ci tunnel->name, skb->len); 8128c2ecf20Sopenharmony_ci goto invalid; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Point to L2TP header */ 8168c2ecf20Sopenharmony_ci optr = skb->data; 8178c2ecf20Sopenharmony_ci ptr = skb->data; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Get L2TP header flags */ 8208c2ecf20Sopenharmony_ci hdrflags = ntohs(*(__be16 *)ptr); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* Check protocol version */ 8238c2ecf20Sopenharmony_ci version = hdrflags & L2TP_HDR_VER_MASK; 8248c2ecf20Sopenharmony_ci if (version != tunnel->version) { 8258c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: recv protocol version mismatch: got %d expected %d\n", 8268c2ecf20Sopenharmony_ci tunnel->name, version, tunnel->version); 8278c2ecf20Sopenharmony_ci goto invalid; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* Get length of L2TP packet */ 8318c2ecf20Sopenharmony_ci length = skb->len; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* If type is control packet, it is handled by userspace. */ 8348c2ecf20Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_T) 8358c2ecf20Sopenharmony_ci goto pass; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* Skip flags */ 8388c2ecf20Sopenharmony_ci ptr += 2; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) { 8418c2ecf20Sopenharmony_ci /* If length is present, skip it */ 8428c2ecf20Sopenharmony_ci if (hdrflags & L2TP_HDRFLAG_L) 8438c2ecf20Sopenharmony_ci ptr += 2; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Extract tunnel and session ID */ 8468c2ecf20Sopenharmony_ci tunnel_id = ntohs(*(__be16 *)ptr); 8478c2ecf20Sopenharmony_ci ptr += 2; 8488c2ecf20Sopenharmony_ci session_id = ntohs(*(__be16 *)ptr); 8498c2ecf20Sopenharmony_ci ptr += 2; 8508c2ecf20Sopenharmony_ci } else { 8518c2ecf20Sopenharmony_ci ptr += 2; /* skip reserved bits */ 8528c2ecf20Sopenharmony_ci tunnel_id = tunnel->tunnel_id; 8538c2ecf20Sopenharmony_ci session_id = ntohl(*(__be32 *)ptr); 8548c2ecf20Sopenharmony_ci ptr += 4; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Find the session context */ 8588c2ecf20Sopenharmony_ci session = l2tp_tunnel_get_session(tunnel, session_id); 8598c2ecf20Sopenharmony_ci if (!session || !session->recv_skb) { 8608c2ecf20Sopenharmony_ci if (session) 8618c2ecf20Sopenharmony_ci l2tp_session_dec_refcount(session); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Not found? Pass to userspace to deal with */ 8648c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: no session found (%u/%u). Passing up.\n", 8658c2ecf20Sopenharmony_ci tunnel->name, tunnel_id, session_id); 8668c2ecf20Sopenharmony_ci goto pass; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_3 && 8708c2ecf20Sopenharmony_ci l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) { 8718c2ecf20Sopenharmony_ci l2tp_session_dec_refcount(session); 8728c2ecf20Sopenharmony_ci goto invalid; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci l2tp_recv_common(session, skb, ptr, optr, hdrflags, length); 8768c2ecf20Sopenharmony_ci l2tp_session_dec_refcount(session); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ciinvalid: 8818c2ecf20Sopenharmony_ci atomic_long_inc(&tunnel->stats.rx_invalid); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cipass: 8848c2ecf20Sopenharmony_ci /* Put UDP header back */ 8858c2ecf20Sopenharmony_ci __skb_push(skb, sizeof(struct udphdr)); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return 1; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci/* UDP encapsulation receive handler. See net/ipv4/udp.c. 8918c2ecf20Sopenharmony_ci * Return codes: 8928c2ecf20Sopenharmony_ci * 0 : success. 8938c2ecf20Sopenharmony_ci * <0: error 8948c2ecf20Sopenharmony_ci * >0: skb should be passed up to userspace as UDP. 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ciint l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Note that this is called from the encap_rcv hook inside an 9018c2ecf20Sopenharmony_ci * RCU-protected region, but without the socket being locked. 9028c2ecf20Sopenharmony_ci * Hence we use rcu_dereference_sk_user_data to access the 9038c2ecf20Sopenharmony_ci * tunnel data structure rather the usual l2tp_sk_to_tunnel 9048c2ecf20Sopenharmony_ci * accessor function. 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_ci tunnel = rcu_dereference_sk_user_data(sk); 9078c2ecf20Sopenharmony_ci if (!tunnel) 9088c2ecf20Sopenharmony_ci goto pass_up; 9098c2ecf20Sopenharmony_ci if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC)) 9108c2ecf20Sopenharmony_ci goto pass_up; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (l2tp_udp_recv_core(tunnel, skb)) 9138c2ecf20Sopenharmony_ci goto pass_up; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cipass_up: 9188c2ecf20Sopenharmony_ci return 1; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_udp_encap_recv); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/************************************************************************ 9238c2ecf20Sopenharmony_ci * Transmit handling 9248c2ecf20Sopenharmony_ci ***********************************************************************/ 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/* Build an L2TP header for the session into the buffer provided. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_cistatic int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 9318c2ecf20Sopenharmony_ci __be16 *bufp = buf; 9328c2ecf20Sopenharmony_ci __be16 *optr = buf; 9338c2ecf20Sopenharmony_ci u16 flags = L2TP_HDR_VER_2; 9348c2ecf20Sopenharmony_ci u32 tunnel_id = tunnel->peer_tunnel_id; 9358c2ecf20Sopenharmony_ci u32 session_id = session->peer_session_id; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (session->send_seq) 9388c2ecf20Sopenharmony_ci flags |= L2TP_HDRFLAG_S; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Setup L2TP header. */ 9418c2ecf20Sopenharmony_ci *bufp++ = htons(flags); 9428c2ecf20Sopenharmony_ci *bufp++ = htons(tunnel_id); 9438c2ecf20Sopenharmony_ci *bufp++ = htons(session_id); 9448c2ecf20Sopenharmony_ci if (session->send_seq) { 9458c2ecf20Sopenharmony_ci *bufp++ = htons(session->ns); 9468c2ecf20Sopenharmony_ci *bufp++ = 0; 9478c2ecf20Sopenharmony_ci session->ns++; 9488c2ecf20Sopenharmony_ci session->ns &= 0xffff; 9498c2ecf20Sopenharmony_ci trace_session_seqnum_update(session); 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return bufp - optr; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 9588c2ecf20Sopenharmony_ci char *bufp = buf; 9598c2ecf20Sopenharmony_ci char *optr = bufp; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Setup L2TP header. The header differs slightly for UDP and 9628c2ecf20Sopenharmony_ci * IP encapsulations. For UDP, there is 4 bytes of flags. 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_ci if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 9658c2ecf20Sopenharmony_ci u16 flags = L2TP_HDR_VER_3; 9668c2ecf20Sopenharmony_ci *((__be16 *)bufp) = htons(flags); 9678c2ecf20Sopenharmony_ci bufp += 2; 9688c2ecf20Sopenharmony_ci *((__be16 *)bufp) = 0; 9698c2ecf20Sopenharmony_ci bufp += 2; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci *((__be32 *)bufp) = htonl(session->peer_session_id); 9738c2ecf20Sopenharmony_ci bufp += 4; 9748c2ecf20Sopenharmony_ci if (session->cookie_len) { 9758c2ecf20Sopenharmony_ci memcpy(bufp, &session->cookie[0], session->cookie_len); 9768c2ecf20Sopenharmony_ci bufp += session->cookie_len; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 9798c2ecf20Sopenharmony_ci u32 l2h = 0; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (session->send_seq) { 9828c2ecf20Sopenharmony_ci l2h = 0x40000000 | session->ns; 9838c2ecf20Sopenharmony_ci session->ns++; 9848c2ecf20Sopenharmony_ci session->ns &= 0xffffff; 9858c2ecf20Sopenharmony_ci trace_session_seqnum_update(session); 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci *((__be32 *)bufp) = htonl(l2h); 9898c2ecf20Sopenharmony_ci bufp += 4; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci return bufp - optr; 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci/* Queue the packet to IP for output: tunnel socket lock must be held */ 9968c2ecf20Sopenharmony_cistatic int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, struct flowi *fl) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci int err; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci skb->ignore_df = 1; 10018c2ecf20Sopenharmony_ci skb_dst_drop(skb); 10028c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10038c2ecf20Sopenharmony_ci if (l2tp_sk_is_v6(tunnel->sock)) 10048c2ecf20Sopenharmony_ci err = inet6_csk_xmit(tunnel->sock, skb, NULL); 10058c2ecf20Sopenharmony_ci else 10068c2ecf20Sopenharmony_ci#endif 10078c2ecf20Sopenharmony_ci err = ip_queue_xmit(tunnel->sock, skb, fl); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return err >= 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, unsigned int *len) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 10158c2ecf20Sopenharmony_ci unsigned int data_len = skb->len; 10168c2ecf20Sopenharmony_ci struct sock *sk = tunnel->sock; 10178c2ecf20Sopenharmony_ci int headroom, uhlen, udp_len; 10188c2ecf20Sopenharmony_ci int ret = NET_XMIT_SUCCESS; 10198c2ecf20Sopenharmony_ci struct inet_sock *inet; 10208c2ecf20Sopenharmony_ci struct udphdr *uh; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* Check that there's enough headroom in the skb to insert IP, 10238c2ecf20Sopenharmony_ci * UDP and L2TP headers. If not enough, expand it to 10248c2ecf20Sopenharmony_ci * make room. Adjust truesize. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_ci uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0; 10278c2ecf20Sopenharmony_ci headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len; 10288c2ecf20Sopenharmony_ci if (skb_cow_head(skb, headroom)) { 10298c2ecf20Sopenharmony_ci kfree_skb(skb); 10308c2ecf20Sopenharmony_ci return NET_XMIT_DROP; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Setup L2TP header */ 10348c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) 10358c2ecf20Sopenharmony_ci l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len)); 10368c2ecf20Sopenharmony_ci else 10378c2ecf20Sopenharmony_ci l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len)); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* Reset skb netfilter state */ 10408c2ecf20Sopenharmony_ci memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 10418c2ecf20Sopenharmony_ci IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); 10428c2ecf20Sopenharmony_ci nf_reset_ct(skb); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci bh_lock_sock_nested(sk); 10458c2ecf20Sopenharmony_ci if (sock_owned_by_user(sk)) { 10468c2ecf20Sopenharmony_ci kfree_skb(skb); 10478c2ecf20Sopenharmony_ci ret = NET_XMIT_DROP; 10488c2ecf20Sopenharmony_ci goto out_unlock; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* The user-space may change the connection status for the user-space 10528c2ecf20Sopenharmony_ci * provided socket at run time: we must check it under the socket lock 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { 10558c2ecf20Sopenharmony_ci kfree_skb(skb); 10568c2ecf20Sopenharmony_ci ret = NET_XMIT_DROP; 10578c2ecf20Sopenharmony_ci goto out_unlock; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* Report transmitted length before we add encap header, which keeps 10618c2ecf20Sopenharmony_ci * statistics consistent for both UDP and IP encap tx/rx paths. 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci *len = skb->len; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci inet = inet_sk(sk); 10668c2ecf20Sopenharmony_ci switch (tunnel->encap) { 10678c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 10688c2ecf20Sopenharmony_ci /* Setup UDP header */ 10698c2ecf20Sopenharmony_ci __skb_push(skb, sizeof(*uh)); 10708c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 10718c2ecf20Sopenharmony_ci uh = udp_hdr(skb); 10728c2ecf20Sopenharmony_ci uh->source = inet->inet_sport; 10738c2ecf20Sopenharmony_ci uh->dest = inet->inet_dport; 10748c2ecf20Sopenharmony_ci udp_len = uhlen + session->hdr_len + data_len; 10758c2ecf20Sopenharmony_ci uh->len = htons(udp_len); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Calculate UDP checksum if configured to do so */ 10788c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10798c2ecf20Sopenharmony_ci if (l2tp_sk_is_v6(sk)) 10808c2ecf20Sopenharmony_ci udp6_set_csum(udp_get_no_check6_tx(sk), 10818c2ecf20Sopenharmony_ci skb, &inet6_sk(sk)->saddr, 10828c2ecf20Sopenharmony_ci &sk->sk_v6_daddr, udp_len); 10838c2ecf20Sopenharmony_ci else 10848c2ecf20Sopenharmony_ci#endif 10858c2ecf20Sopenharmony_ci udp_set_csum(sk->sk_no_check_tx, skb, inet->inet_saddr, 10868c2ecf20Sopenharmony_ci inet->inet_daddr, udp_len); 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci ret = l2tp_xmit_queue(tunnel, skb, &inet->cork.fl); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciout_unlock: 10968c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return ret; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci/* If caller requires the skb to have a ppp header, the header must be 11028c2ecf20Sopenharmony_ci * inserted in the skb data before calling this function. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_ciint l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci unsigned int len = 0; 11078c2ecf20Sopenharmony_ci int ret; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci ret = l2tp_xmit_core(session, skb, &len); 11108c2ecf20Sopenharmony_ci if (ret == NET_XMIT_SUCCESS) { 11118c2ecf20Sopenharmony_ci atomic_long_inc(&session->tunnel->stats.tx_packets); 11128c2ecf20Sopenharmony_ci atomic_long_add(len, &session->tunnel->stats.tx_bytes); 11138c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.tx_packets); 11148c2ecf20Sopenharmony_ci atomic_long_add(len, &session->stats.tx_bytes); 11158c2ecf20Sopenharmony_ci } else { 11168c2ecf20Sopenharmony_ci atomic_long_inc(&session->tunnel->stats.tx_errors); 11178c2ecf20Sopenharmony_ci atomic_long_inc(&session->stats.tx_errors); 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci return ret; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_xmit_skb); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci/***************************************************************************** 11248c2ecf20Sopenharmony_ci * Tinnel and session create/destroy. 11258c2ecf20Sopenharmony_ci *****************************************************************************/ 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci/* Tunnel socket destruct hook. 11288c2ecf20Sopenharmony_ci * The tunnel context is deleted only when all session sockets have been 11298c2ecf20Sopenharmony_ci * closed. 11308c2ecf20Sopenharmony_ci */ 11318c2ecf20Sopenharmony_cistatic void l2tp_tunnel_destruct(struct sock *sk) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (!tunnel) 11368c2ecf20Sopenharmony_ci goto end; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* Disable udp encapsulation */ 11398c2ecf20Sopenharmony_ci switch (tunnel->encap) { 11408c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 11418c2ecf20Sopenharmony_ci /* No longer an encapsulation socket. See net/ipv4/udp.c */ 11428c2ecf20Sopenharmony_ci (udp_sk(sk))->encap_type = 0; 11438c2ecf20Sopenharmony_ci (udp_sk(sk))->encap_rcv = NULL; 11448c2ecf20Sopenharmony_ci (udp_sk(sk))->encap_destroy = NULL; 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* Remove hooks into tunnel socket */ 11518c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 11528c2ecf20Sopenharmony_ci sk->sk_destruct = tunnel->old_sk_destruct; 11538c2ecf20Sopenharmony_ci sk->sk_user_data = NULL; 11548c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* Call the original destructor */ 11578c2ecf20Sopenharmony_ci if (sk->sk_destruct) 11588c2ecf20Sopenharmony_ci (*sk->sk_destruct)(sk); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci kfree_rcu(tunnel, rcu); 11618c2ecf20Sopenharmony_ciend: 11628c2ecf20Sopenharmony_ci return; 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci/* Remove an l2tp session from l2tp_core's hash lists. */ 11668c2ecf20Sopenharmony_cistatic void l2tp_session_unhash(struct l2tp_session *session) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = session->tunnel; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* Remove the session from core hashes */ 11718c2ecf20Sopenharmony_ci if (tunnel) { 11728c2ecf20Sopenharmony_ci /* Remove from the per-tunnel hash */ 11738c2ecf20Sopenharmony_ci write_lock_bh(&tunnel->hlist_lock); 11748c2ecf20Sopenharmony_ci hlist_del_init(&session->hlist); 11758c2ecf20Sopenharmony_ci write_unlock_bh(&tunnel->hlist_lock); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* For L2TPv3 we have a per-net hash: remove from there, too */ 11788c2ecf20Sopenharmony_ci if (tunnel->version != L2TP_HDR_VER_2) { 11798c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_bh(&pn->l2tp_session_hlist_lock); 11828c2ecf20Sopenharmony_ci hlist_del_init_rcu(&session->global_hlist); 11838c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_session_hlist_lock); 11848c2ecf20Sopenharmony_ci synchronize_rcu(); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci/* When the tunnel is closed, all the attached sessions need to go too. 11908c2ecf20Sopenharmony_ci */ 11918c2ecf20Sopenharmony_cistatic void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci int hash; 11948c2ecf20Sopenharmony_ci struct hlist_node *walk; 11958c2ecf20Sopenharmony_ci struct hlist_node *tmp; 11968c2ecf20Sopenharmony_ci struct l2tp_session *session; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci write_lock_bh(&tunnel->hlist_lock); 11998c2ecf20Sopenharmony_ci tunnel->acpt_newsess = false; 12008c2ecf20Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 12018c2ecf20Sopenharmony_ciagain: 12028c2ecf20Sopenharmony_ci hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { 12038c2ecf20Sopenharmony_ci session = hlist_entry(walk, struct l2tp_session, hlist); 12048c2ecf20Sopenharmony_ci hlist_del_init(&session->hlist); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci write_unlock_bh(&tunnel->hlist_lock); 12078c2ecf20Sopenharmony_ci l2tp_session_delete(session); 12088c2ecf20Sopenharmony_ci write_lock_bh(&tunnel->hlist_lock); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* Now restart from the beginning of this hash 12118c2ecf20Sopenharmony_ci * chain. We always remove a session from the 12128c2ecf20Sopenharmony_ci * list so we are guaranteed to make forward 12138c2ecf20Sopenharmony_ci * progress. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_ci goto again; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci write_unlock_bh(&tunnel->hlist_lock); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/* Tunnel socket destroy hook for UDP encapsulation */ 12228c2ecf20Sopenharmony_cistatic void l2tp_udp_encap_destroy(struct sock *sk) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (tunnel) 12278c2ecf20Sopenharmony_ci l2tp_tunnel_delete(tunnel); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic void l2tp_tunnel_remove(struct net *net, struct l2tp_tunnel *tunnel) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 12358c2ecf20Sopenharmony_ci idr_remove(&pn->l2tp_tunnel_idr, tunnel->tunnel_id); 12368c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* Workqueue tunnel deletion function */ 12408c2ecf20Sopenharmony_cistatic void l2tp_tunnel_del_work(struct work_struct *work) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, 12438c2ecf20Sopenharmony_ci del_work); 12448c2ecf20Sopenharmony_ci struct sock *sk = tunnel->sock; 12458c2ecf20Sopenharmony_ci struct socket *sock = sk->sk_socket; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci l2tp_tunnel_closeall(tunnel); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* If the tunnel socket was created within the kernel, use 12508c2ecf20Sopenharmony_ci * the sk API to release it here. 12518c2ecf20Sopenharmony_ci */ 12528c2ecf20Sopenharmony_ci if (tunnel->fd < 0) { 12538c2ecf20Sopenharmony_ci if (sock) { 12548c2ecf20Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 12558c2ecf20Sopenharmony_ci sock_release(sock); 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci l2tp_tunnel_remove(tunnel->l2tp_net, tunnel); 12608c2ecf20Sopenharmony_ci /* drop initial ref */ 12618c2ecf20Sopenharmony_ci l2tp_tunnel_dec_refcount(tunnel); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* drop workqueue ref */ 12648c2ecf20Sopenharmony_ci l2tp_tunnel_dec_refcount(tunnel); 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/* Create a socket for the tunnel, if one isn't set up by 12688c2ecf20Sopenharmony_ci * userspace. This is used for static tunnels where there is no 12698c2ecf20Sopenharmony_ci * managing L2TP daemon. 12708c2ecf20Sopenharmony_ci * 12718c2ecf20Sopenharmony_ci * Since we don't want these sockets to keep a namespace alive by 12728c2ecf20Sopenharmony_ci * themselves, we drop the socket's namespace refcount after creation. 12738c2ecf20Sopenharmony_ci * These sockets are freed when the namespace exits using the pernet 12748c2ecf20Sopenharmony_ci * exit hook. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_cistatic int l2tp_tunnel_sock_create(struct net *net, 12778c2ecf20Sopenharmony_ci u32 tunnel_id, 12788c2ecf20Sopenharmony_ci u32 peer_tunnel_id, 12798c2ecf20Sopenharmony_ci struct l2tp_tunnel_cfg *cfg, 12808c2ecf20Sopenharmony_ci struct socket **sockp) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci int err = -EINVAL; 12838c2ecf20Sopenharmony_ci struct socket *sock = NULL; 12848c2ecf20Sopenharmony_ci struct udp_port_cfg udp_conf; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci switch (cfg->encap) { 12878c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_UDP: 12888c2ecf20Sopenharmony_ci memset(&udp_conf, 0, sizeof(udp_conf)); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 12918c2ecf20Sopenharmony_ci if (cfg->local_ip6 && cfg->peer_ip6) { 12928c2ecf20Sopenharmony_ci udp_conf.family = AF_INET6; 12938c2ecf20Sopenharmony_ci memcpy(&udp_conf.local_ip6, cfg->local_ip6, 12948c2ecf20Sopenharmony_ci sizeof(udp_conf.local_ip6)); 12958c2ecf20Sopenharmony_ci memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, 12968c2ecf20Sopenharmony_ci sizeof(udp_conf.peer_ip6)); 12978c2ecf20Sopenharmony_ci udp_conf.use_udp6_tx_checksums = 12988c2ecf20Sopenharmony_ci !cfg->udp6_zero_tx_checksums; 12998c2ecf20Sopenharmony_ci udp_conf.use_udp6_rx_checksums = 13008c2ecf20Sopenharmony_ci !cfg->udp6_zero_rx_checksums; 13018c2ecf20Sopenharmony_ci } else 13028c2ecf20Sopenharmony_ci#endif 13038c2ecf20Sopenharmony_ci { 13048c2ecf20Sopenharmony_ci udp_conf.family = AF_INET; 13058c2ecf20Sopenharmony_ci udp_conf.local_ip = cfg->local_ip; 13068c2ecf20Sopenharmony_ci udp_conf.peer_ip = cfg->peer_ip; 13078c2ecf20Sopenharmony_ci udp_conf.use_udp_checksums = cfg->use_udp_checksums; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci udp_conf.local_udp_port = htons(cfg->local_udp_port); 13118c2ecf20Sopenharmony_ci udp_conf.peer_udp_port = htons(cfg->peer_udp_port); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci err = udp_sock_create(net, &udp_conf, &sock); 13148c2ecf20Sopenharmony_ci if (err < 0) 13158c2ecf20Sopenharmony_ci goto out; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci break; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci case L2TP_ENCAPTYPE_IP: 13208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 13218c2ecf20Sopenharmony_ci if (cfg->local_ip6 && cfg->peer_ip6) { 13228c2ecf20Sopenharmony_ci struct sockaddr_l2tpip6 ip6_addr = {0}; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 13258c2ecf20Sopenharmony_ci IPPROTO_L2TP, &sock); 13268c2ecf20Sopenharmony_ci if (err < 0) 13278c2ecf20Sopenharmony_ci goto out; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci ip6_addr.l2tp_family = AF_INET6; 13308c2ecf20Sopenharmony_ci memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6, 13318c2ecf20Sopenharmony_ci sizeof(ip6_addr.l2tp_addr)); 13328c2ecf20Sopenharmony_ci ip6_addr.l2tp_conn_id = tunnel_id; 13338c2ecf20Sopenharmony_ci err = kernel_bind(sock, (struct sockaddr *)&ip6_addr, 13348c2ecf20Sopenharmony_ci sizeof(ip6_addr)); 13358c2ecf20Sopenharmony_ci if (err < 0) 13368c2ecf20Sopenharmony_ci goto out; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci ip6_addr.l2tp_family = AF_INET6; 13398c2ecf20Sopenharmony_ci memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6, 13408c2ecf20Sopenharmony_ci sizeof(ip6_addr.l2tp_addr)); 13418c2ecf20Sopenharmony_ci ip6_addr.l2tp_conn_id = peer_tunnel_id; 13428c2ecf20Sopenharmony_ci err = kernel_connect(sock, 13438c2ecf20Sopenharmony_ci (struct sockaddr *)&ip6_addr, 13448c2ecf20Sopenharmony_ci sizeof(ip6_addr), 0); 13458c2ecf20Sopenharmony_ci if (err < 0) 13468c2ecf20Sopenharmony_ci goto out; 13478c2ecf20Sopenharmony_ci } else 13488c2ecf20Sopenharmony_ci#endif 13498c2ecf20Sopenharmony_ci { 13508c2ecf20Sopenharmony_ci struct sockaddr_l2tpip ip_addr = {0}; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 13538c2ecf20Sopenharmony_ci IPPROTO_L2TP, &sock); 13548c2ecf20Sopenharmony_ci if (err < 0) 13558c2ecf20Sopenharmony_ci goto out; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci ip_addr.l2tp_family = AF_INET; 13588c2ecf20Sopenharmony_ci ip_addr.l2tp_addr = cfg->local_ip; 13598c2ecf20Sopenharmony_ci ip_addr.l2tp_conn_id = tunnel_id; 13608c2ecf20Sopenharmony_ci err = kernel_bind(sock, (struct sockaddr *)&ip_addr, 13618c2ecf20Sopenharmony_ci sizeof(ip_addr)); 13628c2ecf20Sopenharmony_ci if (err < 0) 13638c2ecf20Sopenharmony_ci goto out; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci ip_addr.l2tp_family = AF_INET; 13668c2ecf20Sopenharmony_ci ip_addr.l2tp_addr = cfg->peer_ip; 13678c2ecf20Sopenharmony_ci ip_addr.l2tp_conn_id = peer_tunnel_id; 13688c2ecf20Sopenharmony_ci err = kernel_connect(sock, (struct sockaddr *)&ip_addr, 13698c2ecf20Sopenharmony_ci sizeof(ip_addr), 0); 13708c2ecf20Sopenharmony_ci if (err < 0) 13718c2ecf20Sopenharmony_ci goto out; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci default: 13768c2ecf20Sopenharmony_ci goto out; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ciout: 13808c2ecf20Sopenharmony_ci *sockp = sock; 13818c2ecf20Sopenharmony_ci if (err < 0 && sock) { 13828c2ecf20Sopenharmony_ci kernel_sock_shutdown(sock, SHUT_RDWR); 13838c2ecf20Sopenharmony_ci sock_release(sock); 13848c2ecf20Sopenharmony_ci *sockp = NULL; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci return err; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ciint l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, 13918c2ecf20Sopenharmony_ci struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = NULL; 13948c2ecf20Sopenharmony_ci int err; 13958c2ecf20Sopenharmony_ci enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (cfg) 13988c2ecf20Sopenharmony_ci encap = cfg->encap; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL); 14018c2ecf20Sopenharmony_ci if (!tunnel) { 14028c2ecf20Sopenharmony_ci err = -ENOMEM; 14038c2ecf20Sopenharmony_ci goto err; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci tunnel->version = version; 14078c2ecf20Sopenharmony_ci tunnel->tunnel_id = tunnel_id; 14088c2ecf20Sopenharmony_ci tunnel->peer_tunnel_id = peer_tunnel_id; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci tunnel->magic = L2TP_TUNNEL_MAGIC; 14118c2ecf20Sopenharmony_ci sprintf(&tunnel->name[0], "tunl %u", tunnel_id); 14128c2ecf20Sopenharmony_ci rwlock_init(&tunnel->hlist_lock); 14138c2ecf20Sopenharmony_ci tunnel->acpt_newsess = true; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci tunnel->encap = encap; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci refcount_set(&tunnel->ref_count, 1); 14188c2ecf20Sopenharmony_ci tunnel->fd = fd; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* Init delete workqueue struct */ 14218c2ecf20Sopenharmony_ci INIT_WORK(&tunnel->del_work, l2tp_tunnel_del_work); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tunnel->list); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci err = 0; 14268c2ecf20Sopenharmony_cierr: 14278c2ecf20Sopenharmony_ci if (tunnelp) 14288c2ecf20Sopenharmony_ci *tunnelp = tunnel; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return err; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_create); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic int l2tp_validate_socket(const struct sock *sk, const struct net *net, 14358c2ecf20Sopenharmony_ci enum l2tp_encap_type encap) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci if (!net_eq(sock_net(sk), net)) 14388c2ecf20Sopenharmony_ci return -EINVAL; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (sk->sk_type != SOCK_DGRAM) 14418c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) 14448c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if ((encap == L2TP_ENCAPTYPE_UDP && sk->sk_protocol != IPPROTO_UDP) || 14478c2ecf20Sopenharmony_ci (encap == L2TP_ENCAPTYPE_IP && sk->sk_protocol != IPPROTO_L2TP)) 14488c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (sk->sk_user_data) 14518c2ecf20Sopenharmony_ci return -EBUSY; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci return 0; 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ciint l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, 14578c2ecf20Sopenharmony_ci struct l2tp_tunnel_cfg *cfg) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 14608c2ecf20Sopenharmony_ci u32 tunnel_id = tunnel->tunnel_id; 14618c2ecf20Sopenharmony_ci struct socket *sock; 14628c2ecf20Sopenharmony_ci struct sock *sk; 14638c2ecf20Sopenharmony_ci int ret; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 14668c2ecf20Sopenharmony_ci ret = idr_alloc_u32(&pn->l2tp_tunnel_idr, NULL, &tunnel_id, tunnel_id, 14678c2ecf20Sopenharmony_ci GFP_ATOMIC); 14688c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 14698c2ecf20Sopenharmony_ci if (ret) 14708c2ecf20Sopenharmony_ci return ret == -ENOSPC ? -EEXIST : ret; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (tunnel->fd < 0) { 14738c2ecf20Sopenharmony_ci ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id, 14748c2ecf20Sopenharmony_ci tunnel->peer_tunnel_id, cfg, 14758c2ecf20Sopenharmony_ci &sock); 14768c2ecf20Sopenharmony_ci if (ret < 0) 14778c2ecf20Sopenharmony_ci goto err; 14788c2ecf20Sopenharmony_ci } else { 14798c2ecf20Sopenharmony_ci sock = sockfd_lookup(tunnel->fd, &ret); 14808c2ecf20Sopenharmony_ci if (!sock) 14818c2ecf20Sopenharmony_ci goto err; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci sk = sock->sk; 14858c2ecf20Sopenharmony_ci lock_sock(sk); 14868c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 14878c2ecf20Sopenharmony_ci ret = l2tp_validate_socket(sk, net, tunnel->encap); 14888c2ecf20Sopenharmony_ci if (ret < 0) 14898c2ecf20Sopenharmony_ci goto err_inval_sock; 14908c2ecf20Sopenharmony_ci rcu_assign_sk_user_data(sk, tunnel); 14918c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 14948c2ecf20Sopenharmony_ci struct udp_tunnel_sock_cfg udp_cfg = { 14958c2ecf20Sopenharmony_ci .sk_user_data = tunnel, 14968c2ecf20Sopenharmony_ci .encap_type = UDP_ENCAP_L2TPINUDP, 14978c2ecf20Sopenharmony_ci .encap_rcv = l2tp_udp_encap_recv, 14988c2ecf20Sopenharmony_ci .encap_destroy = l2tp_udp_encap_destroy, 14998c2ecf20Sopenharmony_ci }; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci setup_udp_tunnel_sock(net, sock, &udp_cfg); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci tunnel->old_sk_destruct = sk->sk_destruct; 15058c2ecf20Sopenharmony_ci sk->sk_destruct = &l2tp_tunnel_destruct; 15068c2ecf20Sopenharmony_ci sk->sk_allocation = GFP_ATOMIC; 15078c2ecf20Sopenharmony_ci release_sock(sk); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci sock_hold(sk); 15108c2ecf20Sopenharmony_ci tunnel->sock = sk; 15118c2ecf20Sopenharmony_ci tunnel->l2tp_net = net; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci spin_lock_bh(&pn->l2tp_tunnel_idr_lock); 15148c2ecf20Sopenharmony_ci idr_replace(&pn->l2tp_tunnel_idr, tunnel, tunnel->tunnel_id); 15158c2ecf20Sopenharmony_ci spin_unlock_bh(&pn->l2tp_tunnel_idr_lock); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci trace_register_tunnel(tunnel); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (tunnel->fd >= 0) 15208c2ecf20Sopenharmony_ci sockfd_put(sock); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci return 0; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cierr_inval_sock: 15258c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 15268c2ecf20Sopenharmony_ci release_sock(sk); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (tunnel->fd < 0) 15298c2ecf20Sopenharmony_ci sock_release(sock); 15308c2ecf20Sopenharmony_ci else 15318c2ecf20Sopenharmony_ci sockfd_put(sock); 15328c2ecf20Sopenharmony_cierr: 15338c2ecf20Sopenharmony_ci l2tp_tunnel_remove(net, tunnel); 15348c2ecf20Sopenharmony_ci return ret; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_register); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci/* This function is used by the netlink TUNNEL_DELETE command. 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_civoid l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) 15418c2ecf20Sopenharmony_ci{ 15428c2ecf20Sopenharmony_ci if (!test_and_set_bit(0, &tunnel->dead)) { 15438c2ecf20Sopenharmony_ci trace_delete_tunnel(tunnel); 15448c2ecf20Sopenharmony_ci l2tp_tunnel_inc_refcount(tunnel); 15458c2ecf20Sopenharmony_ci queue_work(l2tp_wq, &tunnel->del_work); 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_tunnel_delete); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_civoid l2tp_session_delete(struct l2tp_session *session) 15518c2ecf20Sopenharmony_ci{ 15528c2ecf20Sopenharmony_ci if (test_and_set_bit(0, &session->dead)) 15538c2ecf20Sopenharmony_ci return; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci trace_delete_session(session); 15568c2ecf20Sopenharmony_ci l2tp_session_unhash(session); 15578c2ecf20Sopenharmony_ci l2tp_session_queue_purge(session); 15588c2ecf20Sopenharmony_ci if (session->session_close) 15598c2ecf20Sopenharmony_ci (*session->session_close)(session); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci l2tp_session_dec_refcount(session); 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_delete); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/* We come here whenever a session's send_seq, cookie_len or 15668c2ecf20Sopenharmony_ci * l2specific_type parameters are set. 15678c2ecf20Sopenharmony_ci */ 15688c2ecf20Sopenharmony_civoid l2tp_session_set_header_len(struct l2tp_session *session, int version) 15698c2ecf20Sopenharmony_ci{ 15708c2ecf20Sopenharmony_ci if (version == L2TP_HDR_VER_2) { 15718c2ecf20Sopenharmony_ci session->hdr_len = 6; 15728c2ecf20Sopenharmony_ci if (session->send_seq) 15738c2ecf20Sopenharmony_ci session->hdr_len += 4; 15748c2ecf20Sopenharmony_ci } else { 15758c2ecf20Sopenharmony_ci session->hdr_len = 4 + session->cookie_len; 15768c2ecf20Sopenharmony_ci session->hdr_len += l2tp_get_l2specific_len(session); 15778c2ecf20Sopenharmony_ci if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP) 15788c2ecf20Sopenharmony_ci session->hdr_len += 4; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_set_header_len); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cistruct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, 15848c2ecf20Sopenharmony_ci u32 peer_session_id, struct l2tp_session_cfg *cfg) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci struct l2tp_session *session; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci session = kzalloc(sizeof(*session) + priv_size, GFP_KERNEL); 15898c2ecf20Sopenharmony_ci if (session) { 15908c2ecf20Sopenharmony_ci session->magic = L2TP_SESSION_MAGIC; 15918c2ecf20Sopenharmony_ci session->tunnel = tunnel; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci session->session_id = session_id; 15948c2ecf20Sopenharmony_ci session->peer_session_id = peer_session_id; 15958c2ecf20Sopenharmony_ci session->nr = 0; 15968c2ecf20Sopenharmony_ci if (tunnel->version == L2TP_HDR_VER_2) 15978c2ecf20Sopenharmony_ci session->nr_max = 0xffff; 15988c2ecf20Sopenharmony_ci else 15998c2ecf20Sopenharmony_ci session->nr_max = 0xffffff; 16008c2ecf20Sopenharmony_ci session->nr_window_size = session->nr_max / 2; 16018c2ecf20Sopenharmony_ci session->nr_oos_count_max = 4; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci /* Use NR of first received packet */ 16048c2ecf20Sopenharmony_ci session->reorder_skip = 1; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci sprintf(&session->name[0], "sess %u/%u", 16078c2ecf20Sopenharmony_ci tunnel->tunnel_id, session->session_id); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci skb_queue_head_init(&session->reorder_q); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&session->hlist); 16128c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&session->global_hlist); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (cfg) { 16158c2ecf20Sopenharmony_ci session->pwtype = cfg->pw_type; 16168c2ecf20Sopenharmony_ci session->send_seq = cfg->send_seq; 16178c2ecf20Sopenharmony_ci session->recv_seq = cfg->recv_seq; 16188c2ecf20Sopenharmony_ci session->lns_mode = cfg->lns_mode; 16198c2ecf20Sopenharmony_ci session->reorder_timeout = cfg->reorder_timeout; 16208c2ecf20Sopenharmony_ci session->l2specific_type = cfg->l2specific_type; 16218c2ecf20Sopenharmony_ci session->cookie_len = cfg->cookie_len; 16228c2ecf20Sopenharmony_ci memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len); 16238c2ecf20Sopenharmony_ci session->peer_cookie_len = cfg->peer_cookie_len; 16248c2ecf20Sopenharmony_ci memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len); 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci l2tp_session_set_header_len(session, tunnel->version); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci refcount_set(&session->ref_count, 1); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci return session; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_session_create); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci/***************************************************************************** 16398c2ecf20Sopenharmony_ci * Init and cleanup 16408c2ecf20Sopenharmony_ci *****************************************************************************/ 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_cistatic __net_init int l2tp_init_net(struct net *net) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct l2tp_net *pn = net_generic(net, l2tp_net_id); 16458c2ecf20Sopenharmony_ci int hash; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci idr_init(&pn->l2tp_tunnel_idr); 16488c2ecf20Sopenharmony_ci spin_lock_init(&pn->l2tp_tunnel_idr_lock); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 16518c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci spin_lock_init(&pn->l2tp_session_hlist_lock); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci return 0; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic __net_exit void l2tp_exit_net(struct net *net) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct l2tp_net *pn = l2tp_pernet(net); 16618c2ecf20Sopenharmony_ci struct l2tp_tunnel *tunnel = NULL; 16628c2ecf20Sopenharmony_ci unsigned long tunnel_id, tmp; 16638c2ecf20Sopenharmony_ci int hash; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 16668c2ecf20Sopenharmony_ci idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) { 16678c2ecf20Sopenharmony_ci if (tunnel) 16688c2ecf20Sopenharmony_ci l2tp_tunnel_delete(tunnel); 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (l2tp_wq) 16738c2ecf20Sopenharmony_ci flush_workqueue(l2tp_wq); 16748c2ecf20Sopenharmony_ci rcu_barrier(); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 16778c2ecf20Sopenharmony_ci WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash])); 16788c2ecf20Sopenharmony_ci idr_destroy(&pn->l2tp_tunnel_idr); 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_cistatic struct pernet_operations l2tp_net_ops = { 16828c2ecf20Sopenharmony_ci .init = l2tp_init_net, 16838c2ecf20Sopenharmony_ci .exit = l2tp_exit_net, 16848c2ecf20Sopenharmony_ci .id = &l2tp_net_id, 16858c2ecf20Sopenharmony_ci .size = sizeof(struct l2tp_net), 16868c2ecf20Sopenharmony_ci}; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic int __init l2tp_init(void) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci int rc = 0; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci rc = register_pernet_device(&l2tp_net_ops); 16938c2ecf20Sopenharmony_ci if (rc) 16948c2ecf20Sopenharmony_ci goto out; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); 16978c2ecf20Sopenharmony_ci if (!l2tp_wq) { 16988c2ecf20Sopenharmony_ci pr_err("alloc_workqueue failed\n"); 16998c2ecf20Sopenharmony_ci unregister_pernet_device(&l2tp_net_ops); 17008c2ecf20Sopenharmony_ci rc = -ENOMEM; 17018c2ecf20Sopenharmony_ci goto out; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci pr_info("L2TP core driver, %s\n", L2TP_DRV_VERSION); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ciout: 17078c2ecf20Sopenharmony_ci return rc; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic void __exit l2tp_exit(void) 17118c2ecf20Sopenharmony_ci{ 17128c2ecf20Sopenharmony_ci unregister_pernet_device(&l2tp_net_ops); 17138c2ecf20Sopenharmony_ci if (l2tp_wq) { 17148c2ecf20Sopenharmony_ci destroy_workqueue(l2tp_wq); 17158c2ecf20Sopenharmony_ci l2tp_wq = NULL; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cimodule_init(l2tp_init); 17208c2ecf20Sopenharmony_cimodule_exit(l2tp_exit); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 17238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("L2TP core"); 17248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17258c2ecf20Sopenharmony_ciMODULE_VERSION(L2TP_DRV_VERSION); 1726