1fd558d18SJames Chapman /* 2fd558d18SJames Chapman * L2TP core. 3fd558d18SJames Chapman * 4fd558d18SJames Chapman * Copyright (c) 2008,2009,2010 Katalix Systems Ltd 5fd558d18SJames Chapman * 6fd558d18SJames Chapman * This file contains some code of the original L2TPv2 pppol2tp 7fd558d18SJames Chapman * driver, which has the following copyright: 8fd558d18SJames Chapman * 9fd558d18SJames Chapman * Authors: Martijn van Oosterhout <kleptog@svana.org> 10fd558d18SJames Chapman * James Chapman (jchapman@katalix.com) 11fd558d18SJames Chapman * Contributors: 12fd558d18SJames Chapman * Michal Ostrowski <mostrows@speakeasy.net> 13fd558d18SJames Chapman * Arnaldo Carvalho de Melo <acme@xconectiva.com.br> 14fd558d18SJames Chapman * David S. Miller (davem@redhat.com) 15fd558d18SJames Chapman * 16fd558d18SJames Chapman * This program is free software; you can redistribute it and/or modify 17fd558d18SJames Chapman * it under the terms of the GNU General Public License version 2 as 18fd558d18SJames Chapman * published by the Free Software Foundation. 19fd558d18SJames Chapman */ 20fd558d18SJames Chapman 21a4ca44faSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22a4ca44faSJoe Perches 23fd558d18SJames Chapman #include <linux/module.h> 24fd558d18SJames Chapman #include <linux/string.h> 25fd558d18SJames Chapman #include <linux/list.h> 26e02d494dSJames Chapman #include <linux/rculist.h> 27fd558d18SJames Chapman #include <linux/uaccess.h> 28fd558d18SJames Chapman 29fd558d18SJames Chapman #include <linux/kernel.h> 30fd558d18SJames Chapman #include <linux/spinlock.h> 31fd558d18SJames Chapman #include <linux/kthread.h> 32fd558d18SJames Chapman #include <linux/sched.h> 33fd558d18SJames Chapman #include <linux/slab.h> 34fd558d18SJames Chapman #include <linux/errno.h> 35fd558d18SJames Chapman #include <linux/jiffies.h> 36fd558d18SJames Chapman 37fd558d18SJames Chapman #include <linux/netdevice.h> 38fd558d18SJames Chapman #include <linux/net.h> 39fd558d18SJames Chapman #include <linux/inetdevice.h> 40fd558d18SJames Chapman #include <linux/skbuff.h> 41fd558d18SJames Chapman #include <linux/init.h> 420d76751fSJames Chapman #include <linux/in.h> 43fd558d18SJames Chapman #include <linux/ip.h> 44fd558d18SJames Chapman #include <linux/udp.h> 450d76751fSJames Chapman #include <linux/l2tp.h> 46fd558d18SJames Chapman #include <linux/hash.h> 47fd558d18SJames Chapman #include <linux/sort.h> 48fd558d18SJames Chapman #include <linux/file.h> 49fd558d18SJames Chapman #include <linux/nsproxy.h> 50fd558d18SJames Chapman #include <net/net_namespace.h> 51fd558d18SJames Chapman #include <net/netns/generic.h> 52fd558d18SJames Chapman #include <net/dst.h> 53fd558d18SJames Chapman #include <net/ip.h> 54fd558d18SJames Chapman #include <net/udp.h> 5585644b4dSTom Herbert #include <net/udp_tunnel.h> 56309795f4SJames Chapman #include <net/inet_common.h> 57fd558d18SJames Chapman #include <net/xfrm.h> 580d76751fSJames Chapman #include <net/protocol.h> 59d2cf3361SBenjamin LaHaise #include <net/inet6_connection_sock.h> 60d2cf3361SBenjamin LaHaise #include <net/inet_ecn.h> 61d2cf3361SBenjamin LaHaise #include <net/ip6_route.h> 62d499bd2eSDavid S. Miller #include <net/ip6_checksum.h> 63fd558d18SJames Chapman 64fd558d18SJames Chapman #include <asm/byteorder.h> 6560063497SArun Sharma #include <linux/atomic.h> 66fd558d18SJames Chapman 67fd558d18SJames Chapman #include "l2tp_core.h" 68fd558d18SJames Chapman 69fd558d18SJames Chapman #define L2TP_DRV_VERSION "V2.0" 70fd558d18SJames Chapman 71fd558d18SJames Chapman /* L2TP header constants */ 72fd558d18SJames Chapman #define L2TP_HDRFLAG_T 0x8000 73fd558d18SJames Chapman #define L2TP_HDRFLAG_L 0x4000 74fd558d18SJames Chapman #define L2TP_HDRFLAG_S 0x0800 75fd558d18SJames Chapman #define L2TP_HDRFLAG_O 0x0200 76fd558d18SJames Chapman #define L2TP_HDRFLAG_P 0x0100 77fd558d18SJames Chapman 78fd558d18SJames Chapman #define L2TP_HDR_VER_MASK 0x000F 79fd558d18SJames Chapman #define L2TP_HDR_VER_2 0x0002 80f7faffa3SJames Chapman #define L2TP_HDR_VER_3 0x0003 81fd558d18SJames Chapman 82fd558d18SJames Chapman /* L2TPv3 default L2-specific sublayer */ 83fd558d18SJames Chapman #define L2TP_SLFLAG_S 0x40000000 84fd558d18SJames Chapman #define L2TP_SL_SEQ_MASK 0x00ffffff 85fd558d18SJames Chapman 8691c52470SJacob Wen #define L2TP_HDR_SIZE_MAX 14 87fd558d18SJames Chapman 88fd558d18SJames Chapman /* Default trace flags */ 89fd558d18SJames Chapman #define L2TP_DEFAULT_DEBUG_FLAGS 0 90fd558d18SJames Chapman 91fd558d18SJames Chapman /* Private data stored for received packets in the skb. 92fd558d18SJames Chapman */ 93fd558d18SJames Chapman struct l2tp_skb_cb { 94f7faffa3SJames Chapman u32 ns; 95fd558d18SJames Chapman u16 has_seq; 96fd558d18SJames Chapman u16 length; 97fd558d18SJames Chapman unsigned long expires; 98fd558d18SJames Chapman }; 99fd558d18SJames Chapman 100fd558d18SJames Chapman #define L2TP_SKB_CB(skb) ((struct l2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)]) 101fd558d18SJames Chapman 102f8ccac0eSTom Parkin static struct workqueue_struct *l2tp_wq; 103fd558d18SJames Chapman 104fd558d18SJames Chapman /* per-net private data for this module */ 105fd558d18SJames Chapman static unsigned int l2tp_net_id; 106fd558d18SJames Chapman struct l2tp_net { 107fd558d18SJames Chapman struct list_head l2tp_tunnel_list; 108e02d494dSJames Chapman spinlock_t l2tp_tunnel_list_lock; 109f7faffa3SJames Chapman struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; 110e02d494dSJames Chapman spinlock_t l2tp_session_hlist_lock; 111fd558d18SJames Chapman }; 112fd558d18SJames Chapman 113b954f940SPaolo Abeni #if IS_ENABLED(CONFIG_IPV6) 114b954f940SPaolo Abeni static bool l2tp_sk_is_v6(struct sock *sk) 115b954f940SPaolo Abeni { 116b954f940SPaolo Abeni return sk->sk_family == PF_INET6 && 117b954f940SPaolo Abeni !ipv6_addr_v4mapped(&sk->sk_v6_daddr); 118b954f940SPaolo Abeni } 119b954f940SPaolo Abeni #endif 120fc130840Sstephen hemminger 1218d8a51e2SDavid S. Miller static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) 1228d8a51e2SDavid S. Miller { 1238d8a51e2SDavid S. Miller return sk->sk_user_data; 1248d8a51e2SDavid S. Miller } 1258d8a51e2SDavid S. Miller 1269aaef50cSGuillaume Nault static inline struct l2tp_net *l2tp_pernet(const struct net *net) 127fd558d18SJames Chapman { 128fd558d18SJames Chapman BUG_ON(!net); 129fd558d18SJames Chapman 130fd558d18SJames Chapman return net_generic(net, l2tp_net_id); 131fd558d18SJames Chapman } 132fd558d18SJames Chapman 133f7faffa3SJames Chapman /* Session hash global list for L2TPv3. 134f7faffa3SJames Chapman * The session_id SHOULD be random according to RFC3931, but several 135f7faffa3SJames Chapman * L2TP implementations use incrementing session_ids. So we do a real 136f7faffa3SJames Chapman * hash on the session_id, rather than a simple bitmask. 137f7faffa3SJames Chapman */ 138f7faffa3SJames Chapman static inline struct hlist_head * 139f7faffa3SJames Chapman l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) 140f7faffa3SJames Chapman { 141f7faffa3SJames Chapman return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; 142f7faffa3SJames Chapman 143f7faffa3SJames Chapman } 144f7faffa3SJames Chapman 145fd558d18SJames Chapman /* Session hash list. 146fd558d18SJames Chapman * The session_id SHOULD be random according to RFC2661, but several 147fd558d18SJames Chapman * L2TP implementations (Cisco and Microsoft) use incrementing 148fd558d18SJames Chapman * session_ids. So we do a real hash on the session_id, rather than a 149fd558d18SJames Chapman * simple bitmask. 150fd558d18SJames Chapman */ 151fd558d18SJames Chapman static inline struct hlist_head * 152fd558d18SJames Chapman l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) 153fd558d18SJames Chapman { 154fd558d18SJames Chapman return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; 155fd558d18SJames Chapman } 156fd558d18SJames Chapman 157d00fa9adSJames Chapman void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) 158d00fa9adSJames Chapman { 159d00fa9adSJames Chapman sock_put(tunnel->sock); 160d00fa9adSJames Chapman /* the tunnel is freed in the socket destructor */ 161d00fa9adSJames Chapman } 162d00fa9adSJames Chapman EXPORT_SYMBOL(l2tp_tunnel_free); 163d00fa9adSJames Chapman 16454652eb1SGuillaume Nault /* Lookup a tunnel. A new reference is held on the returned tunnel. */ 16554652eb1SGuillaume Nault struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) 16654652eb1SGuillaume Nault { 16754652eb1SGuillaume Nault const struct l2tp_net *pn = l2tp_pernet(net); 16854652eb1SGuillaume Nault struct l2tp_tunnel *tunnel; 16954652eb1SGuillaume Nault 17054652eb1SGuillaume Nault rcu_read_lock_bh(); 17154652eb1SGuillaume Nault list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { 17254652eb1SGuillaume Nault if (tunnel->tunnel_id == tunnel_id) { 17354652eb1SGuillaume Nault l2tp_tunnel_inc_refcount(tunnel); 17454652eb1SGuillaume Nault rcu_read_unlock_bh(); 17554652eb1SGuillaume Nault 17654652eb1SGuillaume Nault return tunnel; 17754652eb1SGuillaume Nault } 17854652eb1SGuillaume Nault } 17954652eb1SGuillaume Nault rcu_read_unlock_bh(); 18054652eb1SGuillaume Nault 18154652eb1SGuillaume Nault return NULL; 18254652eb1SGuillaume Nault } 18354652eb1SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get); 18454652eb1SGuillaume Nault 1855846c131SGuillaume Nault struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth) 1865846c131SGuillaume Nault { 1875846c131SGuillaume Nault const struct l2tp_net *pn = l2tp_pernet(net); 1885846c131SGuillaume Nault struct l2tp_tunnel *tunnel; 1895846c131SGuillaume Nault int count = 0; 1905846c131SGuillaume Nault 1915846c131SGuillaume Nault rcu_read_lock_bh(); 1925846c131SGuillaume Nault list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { 1935846c131SGuillaume Nault if (++count > nth) { 1945846c131SGuillaume Nault l2tp_tunnel_inc_refcount(tunnel); 1955846c131SGuillaume Nault rcu_read_unlock_bh(); 1965846c131SGuillaume Nault return tunnel; 1975846c131SGuillaume Nault } 1985846c131SGuillaume Nault } 1995846c131SGuillaume Nault rcu_read_unlock_bh(); 2005846c131SGuillaume Nault 2015846c131SGuillaume Nault return NULL; 2025846c131SGuillaume Nault } 2035846c131SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth); 2045846c131SGuillaume Nault 20501e28b92SGuillaume Nault struct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel, 206a4346210SGuillaume Nault u32 session_id) 20761b9a047SGuillaume Nault { 20861b9a047SGuillaume Nault struct hlist_head *session_list; 20961b9a047SGuillaume Nault struct l2tp_session *session; 21061b9a047SGuillaume Nault 21101e28b92SGuillaume Nault session_list = l2tp_session_id_hash(tunnel, session_id); 21261b9a047SGuillaume Nault 21301e28b92SGuillaume Nault read_lock_bh(&tunnel->hlist_lock); 21401e28b92SGuillaume Nault hlist_for_each_entry(session, session_list, hlist) 21561b9a047SGuillaume Nault if (session->session_id == session_id) { 21661b9a047SGuillaume Nault l2tp_session_inc_refcount(session); 21701e28b92SGuillaume Nault read_unlock_bh(&tunnel->hlist_lock); 21861b9a047SGuillaume Nault 21961b9a047SGuillaume Nault return session; 22061b9a047SGuillaume Nault } 22101e28b92SGuillaume Nault read_unlock_bh(&tunnel->hlist_lock); 22261b9a047SGuillaume Nault 22361b9a047SGuillaume Nault return NULL; 22461b9a047SGuillaume Nault } 22501e28b92SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get_session); 22661b9a047SGuillaume Nault 22701e28b92SGuillaume Nault struct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id) 22801e28b92SGuillaume Nault { 22901e28b92SGuillaume Nault struct hlist_head *session_list; 23001e28b92SGuillaume Nault struct l2tp_session *session; 23101e28b92SGuillaume Nault 23201e28b92SGuillaume Nault session_list = l2tp_session_id_hash_2(l2tp_pernet(net), session_id); 23301e28b92SGuillaume Nault 23401e28b92SGuillaume Nault rcu_read_lock_bh(); 23501e28b92SGuillaume Nault hlist_for_each_entry_rcu(session, session_list, global_hlist) 23661b9a047SGuillaume Nault if (session->session_id == session_id) { 23761b9a047SGuillaume Nault l2tp_session_inc_refcount(session); 23801e28b92SGuillaume Nault rcu_read_unlock_bh(); 23961b9a047SGuillaume Nault 24061b9a047SGuillaume Nault return session; 24161b9a047SGuillaume Nault } 24201e28b92SGuillaume Nault rcu_read_unlock_bh(); 24361b9a047SGuillaume Nault 24461b9a047SGuillaume Nault return NULL; 24561b9a047SGuillaume Nault } 24661b9a047SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get); 24761b9a047SGuillaume Nault 248a4346210SGuillaume Nault struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth) 249fd558d18SJames Chapman { 250fd558d18SJames Chapman int hash; 251fd558d18SJames Chapman struct l2tp_session *session; 252fd558d18SJames Chapman int count = 0; 253fd558d18SJames Chapman 254fd558d18SJames Chapman read_lock_bh(&tunnel->hlist_lock); 255fd558d18SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 256b67bfe0dSSasha Levin hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { 257fd558d18SJames Chapman if (++count > nth) { 258e08293a4SGuillaume Nault l2tp_session_inc_refcount(session); 259fd558d18SJames Chapman read_unlock_bh(&tunnel->hlist_lock); 260fd558d18SJames Chapman return session; 261fd558d18SJames Chapman } 262fd558d18SJames Chapman } 263fd558d18SJames Chapman } 264fd558d18SJames Chapman 265fd558d18SJames Chapman read_unlock_bh(&tunnel->hlist_lock); 266fd558d18SJames Chapman 267fd558d18SJames Chapman return NULL; 268fd558d18SJames Chapman } 269e08293a4SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get_nth); 270fd558d18SJames Chapman 271309795f4SJames Chapman /* Lookup a session by interface name. 272309795f4SJames Chapman * This is very inefficient but is only used by management interfaces. 273309795f4SJames Chapman */ 2749aaef50cSGuillaume Nault struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, 275a4346210SGuillaume Nault const char *ifname) 276309795f4SJames Chapman { 277309795f4SJames Chapman struct l2tp_net *pn = l2tp_pernet(net); 278309795f4SJames Chapman int hash; 279309795f4SJames Chapman struct l2tp_session *session; 280309795f4SJames Chapman 281e02d494dSJames Chapman rcu_read_lock_bh(); 282309795f4SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { 283b67bfe0dSSasha Levin hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { 284309795f4SJames Chapman if (!strcmp(session->ifname, ifname)) { 2852777e2abSGuillaume Nault l2tp_session_inc_refcount(session); 286e02d494dSJames Chapman rcu_read_unlock_bh(); 2872777e2abSGuillaume Nault 288309795f4SJames Chapman return session; 289309795f4SJames Chapman } 290309795f4SJames Chapman } 291309795f4SJames Chapman } 292309795f4SJames Chapman 293e02d494dSJames Chapman rcu_read_unlock_bh(); 294309795f4SJames Chapman 295309795f4SJames Chapman return NULL; 296309795f4SJames Chapman } 2972777e2abSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname); 298309795f4SJames Chapman 2993953ae7bSGuillaume Nault int l2tp_session_register(struct l2tp_session *session, 3003953ae7bSGuillaume Nault struct l2tp_tunnel *tunnel) 301dbdbc73bSGuillaume Nault { 302dbdbc73bSGuillaume Nault struct l2tp_session *session_walk; 303dbdbc73bSGuillaume Nault struct hlist_head *g_head; 304dbdbc73bSGuillaume Nault struct hlist_head *head; 305dbdbc73bSGuillaume Nault struct l2tp_net *pn; 306f3c66d4eSGuillaume Nault int err; 307dbdbc73bSGuillaume Nault 308dbdbc73bSGuillaume Nault head = l2tp_session_id_hash(tunnel, session->session_id); 309dbdbc73bSGuillaume Nault 310dbdbc73bSGuillaume Nault write_lock_bh(&tunnel->hlist_lock); 311f3c66d4eSGuillaume Nault if (!tunnel->acpt_newsess) { 312f3c66d4eSGuillaume Nault err = -ENODEV; 313f3c66d4eSGuillaume Nault goto err_tlock; 314f3c66d4eSGuillaume Nault } 315f3c66d4eSGuillaume Nault 316dbdbc73bSGuillaume Nault hlist_for_each_entry(session_walk, head, hlist) 317f3c66d4eSGuillaume Nault if (session_walk->session_id == session->session_id) { 318f3c66d4eSGuillaume Nault err = -EEXIST; 319f3c66d4eSGuillaume Nault goto err_tlock; 320f3c66d4eSGuillaume Nault } 321dbdbc73bSGuillaume Nault 322dbdbc73bSGuillaume Nault if (tunnel->version == L2TP_HDR_VER_3) { 323dbdbc73bSGuillaume Nault pn = l2tp_pernet(tunnel->l2tp_net); 324363a341dSGuillaume Nault g_head = l2tp_session_id_hash_2(pn, session->session_id); 325dbdbc73bSGuillaume Nault 326dbdbc73bSGuillaume Nault spin_lock_bh(&pn->l2tp_session_hlist_lock); 327dbdbc73bSGuillaume Nault 328f3c66d4eSGuillaume Nault hlist_for_each_entry(session_walk, g_head, global_hlist) 329f3c66d4eSGuillaume Nault if (session_walk->session_id == session->session_id) { 330f3c66d4eSGuillaume Nault err = -EEXIST; 331f3c66d4eSGuillaume Nault goto err_tlock_pnlock; 332f3c66d4eSGuillaume Nault } 333f3c66d4eSGuillaume Nault 334f3c66d4eSGuillaume Nault l2tp_tunnel_inc_refcount(tunnel); 335dbdbc73bSGuillaume Nault hlist_add_head_rcu(&session->global_hlist, g_head); 336f3c66d4eSGuillaume Nault 337dbdbc73bSGuillaume Nault spin_unlock_bh(&pn->l2tp_session_hlist_lock); 338f3c66d4eSGuillaume Nault } else { 339f3c66d4eSGuillaume Nault l2tp_tunnel_inc_refcount(tunnel); 340dbdbc73bSGuillaume Nault } 341dbdbc73bSGuillaume Nault 342dbdbc73bSGuillaume Nault hlist_add_head(&session->hlist, head); 343dbdbc73bSGuillaume Nault write_unlock_bh(&tunnel->hlist_lock); 344dbdbc73bSGuillaume Nault 345dbdbc73bSGuillaume Nault return 0; 346dbdbc73bSGuillaume Nault 347f3c66d4eSGuillaume Nault err_tlock_pnlock: 348dbdbc73bSGuillaume Nault spin_unlock_bh(&pn->l2tp_session_hlist_lock); 349f3c66d4eSGuillaume Nault err_tlock: 350dbdbc73bSGuillaume Nault write_unlock_bh(&tunnel->hlist_lock); 351dbdbc73bSGuillaume Nault 352f3c66d4eSGuillaume Nault return err; 353dbdbc73bSGuillaume Nault } 3543953ae7bSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_register); 355dbdbc73bSGuillaume Nault 356fd558d18SJames Chapman /***************************************************************************** 357fd558d18SJames Chapman * Receive data handling 358fd558d18SJames Chapman *****************************************************************************/ 359fd558d18SJames Chapman 360fd558d18SJames Chapman /* Queue a skb in order. We come here only if the skb has an L2TP sequence 361fd558d18SJames Chapman * number. 362fd558d18SJames Chapman */ 363fd558d18SJames Chapman static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *skb) 364fd558d18SJames Chapman { 365fd558d18SJames Chapman struct sk_buff *skbp; 366fd558d18SJames Chapman struct sk_buff *tmp; 367f7faffa3SJames Chapman u32 ns = L2TP_SKB_CB(skb)->ns; 368fd558d18SJames Chapman 369fd558d18SJames Chapman spin_lock_bh(&session->reorder_q.lock); 370fd558d18SJames Chapman skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { 371fd558d18SJames Chapman if (L2TP_SKB_CB(skbp)->ns > ns) { 372fd558d18SJames Chapman __skb_queue_before(&session->reorder_q, skbp, skb); 373a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 374fd558d18SJames Chapman "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", 375fd558d18SJames Chapman session->name, ns, L2TP_SKB_CB(skbp)->ns, 376fd558d18SJames Chapman skb_queue_len(&session->reorder_q)); 3777b7c0719STom Parkin atomic_long_inc(&session->stats.rx_oos_packets); 378fd558d18SJames Chapman goto out; 379fd558d18SJames Chapman } 380fd558d18SJames Chapman } 381fd558d18SJames Chapman 382fd558d18SJames Chapman __skb_queue_tail(&session->reorder_q, skb); 383fd558d18SJames Chapman 384fd558d18SJames Chapman out: 385fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock); 386fd558d18SJames Chapman } 387fd558d18SJames Chapman 388fd558d18SJames Chapman /* Dequeue a single skb. 389fd558d18SJames Chapman */ 390fd558d18SJames Chapman static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *skb) 391fd558d18SJames Chapman { 392fd558d18SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 393fd558d18SJames Chapman int length = L2TP_SKB_CB(skb)->length; 394fd558d18SJames Chapman 395fd558d18SJames Chapman /* We're about to requeue the skb, so return resources 396fd558d18SJames Chapman * to its current owner (a socket receive buffer). 397fd558d18SJames Chapman */ 398fd558d18SJames Chapman skb_orphan(skb); 399fd558d18SJames Chapman 4007b7c0719STom Parkin atomic_long_inc(&tunnel->stats.rx_packets); 4017b7c0719STom Parkin atomic_long_add(length, &tunnel->stats.rx_bytes); 4027b7c0719STom Parkin atomic_long_inc(&session->stats.rx_packets); 4037b7c0719STom Parkin atomic_long_add(length, &session->stats.rx_bytes); 404fd558d18SJames Chapman 405fd558d18SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) { 406fd558d18SJames Chapman /* Bump our Nr */ 407fd558d18SJames Chapman session->nr++; 4088a1631d5SJames Chapman session->nr &= session->nr_max; 409f7faffa3SJames Chapman 410a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated nr to %hu\n", 411a4ca44faSJoe Perches session->name, session->nr); 412fd558d18SJames Chapman } 413fd558d18SJames Chapman 414fd558d18SJames Chapman /* call private receive handler */ 415fd558d18SJames Chapman if (session->recv_skb != NULL) 416fd558d18SJames Chapman (*session->recv_skb)(session, skb, L2TP_SKB_CB(skb)->length); 417fd558d18SJames Chapman else 418fd558d18SJames Chapman kfree_skb(skb); 419fd558d18SJames Chapman } 420fd558d18SJames Chapman 421fd558d18SJames Chapman /* Dequeue skbs from the session's reorder_q, subject to packet order. 422fd558d18SJames Chapman * Skbs that have been in the queue for too long are simply discarded. 423fd558d18SJames Chapman */ 424fd558d18SJames Chapman static void l2tp_recv_dequeue(struct l2tp_session *session) 425fd558d18SJames Chapman { 426fd558d18SJames Chapman struct sk_buff *skb; 427fd558d18SJames Chapman struct sk_buff *tmp; 428fd558d18SJames Chapman 429fd558d18SJames Chapman /* If the pkt at the head of the queue has the nr that we 430fd558d18SJames Chapman * expect to send up next, dequeue it and any other 431fd558d18SJames Chapman * in-sequence packets behind it. 432fd558d18SJames Chapman */ 433e2e210c0SEric Dumazet start: 434fd558d18SJames Chapman spin_lock_bh(&session->reorder_q.lock); 435fd558d18SJames Chapman skb_queue_walk_safe(&session->reorder_q, skb, tmp) { 436fd558d18SJames Chapman if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { 4377b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards); 4387b7c0719STom Parkin atomic_long_inc(&session->stats.rx_errors); 439a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 440a4ca44faSJoe Perches "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n", 441fd558d18SJames Chapman session->name, L2TP_SKB_CB(skb)->ns, 442fd558d18SJames Chapman L2TP_SKB_CB(skb)->length, session->nr, 443fd558d18SJames Chapman skb_queue_len(&session->reorder_q)); 44438d40b3fSJames Chapman session->reorder_skip = 1; 445fd558d18SJames Chapman __skb_unlink(skb, &session->reorder_q); 446fd558d18SJames Chapman kfree_skb(skb); 447fd558d18SJames Chapman continue; 448fd558d18SJames Chapman } 449fd558d18SJames Chapman 450fd558d18SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) { 45138d40b3fSJames Chapman if (session->reorder_skip) { 452a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 45338d40b3fSJames Chapman "%s: advancing nr to next pkt: %u -> %u", 45438d40b3fSJames Chapman session->name, session->nr, 45538d40b3fSJames Chapman L2TP_SKB_CB(skb)->ns); 45638d40b3fSJames Chapman session->reorder_skip = 0; 45738d40b3fSJames Chapman session->nr = L2TP_SKB_CB(skb)->ns; 45838d40b3fSJames Chapman } 459fd558d18SJames Chapman if (L2TP_SKB_CB(skb)->ns != session->nr) { 460a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 461a4ca44faSJoe Perches "%s: holding oos pkt %u len %d, waiting for %u, reorder_q_len=%d\n", 462fd558d18SJames Chapman session->name, L2TP_SKB_CB(skb)->ns, 463fd558d18SJames Chapman L2TP_SKB_CB(skb)->length, session->nr, 464fd558d18SJames Chapman skb_queue_len(&session->reorder_q)); 465fd558d18SJames Chapman goto out; 466fd558d18SJames Chapman } 467fd558d18SJames Chapman } 468fd558d18SJames Chapman __skb_unlink(skb, &session->reorder_q); 469fd558d18SJames Chapman 470fd558d18SJames Chapman /* Process the skb. We release the queue lock while we 471fd558d18SJames Chapman * do so to let other contexts process the queue. 472fd558d18SJames Chapman */ 473fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock); 474fd558d18SJames Chapman l2tp_recv_dequeue_skb(session, skb); 475e2e210c0SEric Dumazet goto start; 476fd558d18SJames Chapman } 477fd558d18SJames Chapman 478fd558d18SJames Chapman out: 479fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock); 480fd558d18SJames Chapman } 481fd558d18SJames Chapman 4828a1631d5SJames Chapman static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr) 4838a1631d5SJames Chapman { 4848a1631d5SJames Chapman u32 nws; 4858a1631d5SJames Chapman 4868a1631d5SJames Chapman if (nr >= session->nr) 4878a1631d5SJames Chapman nws = nr - session->nr; 4888a1631d5SJames Chapman else 4898a1631d5SJames Chapman nws = (session->nr_max + 1) - (session->nr - nr); 4908a1631d5SJames Chapman 4918a1631d5SJames Chapman return nws < session->nr_window_size; 4928a1631d5SJames Chapman } 4938a1631d5SJames Chapman 494b6dc01a4SJames Chapman /* If packet has sequence numbers, queue it if acceptable. Returns 0 if 495b6dc01a4SJames Chapman * acceptable, else non-zero. 496b6dc01a4SJames Chapman */ 497b6dc01a4SJames Chapman static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) 498b6dc01a4SJames Chapman { 4998a1631d5SJames Chapman if (!l2tp_seq_check_rx_window(session, L2TP_SKB_CB(skb)->ns)) { 5008a1631d5SJames Chapman /* Packet sequence number is outside allowed window. 5018a1631d5SJames Chapman * Discard it. 5028a1631d5SJames Chapman */ 5038a1631d5SJames Chapman l2tp_dbg(session, L2TP_MSG_SEQ, 5048a1631d5SJames Chapman "%s: pkt %u len %d discarded, outside window, nr=%u\n", 5058a1631d5SJames Chapman session->name, L2TP_SKB_CB(skb)->ns, 5068a1631d5SJames Chapman L2TP_SKB_CB(skb)->length, session->nr); 5078a1631d5SJames Chapman goto discard; 5088a1631d5SJames Chapman } 5098a1631d5SJames Chapman 510b6dc01a4SJames Chapman if (session->reorder_timeout != 0) { 511b6dc01a4SJames Chapman /* Packet reordering enabled. Add skb to session's 512b6dc01a4SJames Chapman * reorder queue, in order of ns. 513b6dc01a4SJames Chapman */ 514b6dc01a4SJames Chapman l2tp_recv_queue_skb(session, skb); 515a0dbd822SJames Chapman goto out; 516a0dbd822SJames Chapman } 517a0dbd822SJames Chapman 518a0dbd822SJames Chapman /* Packet reordering disabled. Discard out-of-sequence packets, while 519a0dbd822SJames Chapman * tracking the number if in-sequence packets after the first OOS packet 520a0dbd822SJames Chapman * is seen. After nr_oos_count_max in-sequence packets, reset the 521a0dbd822SJames Chapman * sequence number to re-enable packet reception. 522b6dc01a4SJames Chapman */ 523a0dbd822SJames Chapman if (L2TP_SKB_CB(skb)->ns == session->nr) { 524a0dbd822SJames Chapman skb_queue_tail(&session->reorder_q, skb); 525a0dbd822SJames Chapman } else { 526a0dbd822SJames Chapman u32 nr_oos = L2TP_SKB_CB(skb)->ns; 527a0dbd822SJames Chapman u32 nr_next = (session->nr_oos + 1) & session->nr_max; 528a0dbd822SJames Chapman 529a0dbd822SJames Chapman if (nr_oos == nr_next) 530a0dbd822SJames Chapman session->nr_oos_count++; 531a0dbd822SJames Chapman else 532a0dbd822SJames Chapman session->nr_oos_count = 0; 533a0dbd822SJames Chapman 534a0dbd822SJames Chapman session->nr_oos = nr_oos; 535a0dbd822SJames Chapman if (session->nr_oos_count > session->nr_oos_count_max) { 536a0dbd822SJames Chapman session->reorder_skip = 1; 537a0dbd822SJames Chapman l2tp_dbg(session, L2TP_MSG_SEQ, 538a0dbd822SJames Chapman "%s: %d oos packets received. Resetting sequence numbers\n", 539a0dbd822SJames Chapman session->name, session->nr_oos_count); 540a0dbd822SJames Chapman } 541a0dbd822SJames Chapman if (!session->reorder_skip) { 542b6dc01a4SJames Chapman atomic_long_inc(&session->stats.rx_seq_discards); 543b6dc01a4SJames Chapman l2tp_dbg(session, L2TP_MSG_SEQ, 544b6dc01a4SJames Chapman "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", 545b6dc01a4SJames Chapman session->name, L2TP_SKB_CB(skb)->ns, 546b6dc01a4SJames Chapman L2TP_SKB_CB(skb)->length, session->nr, 547b6dc01a4SJames Chapman skb_queue_len(&session->reorder_q)); 548b6dc01a4SJames Chapman goto discard; 549b6dc01a4SJames Chapman } 550b6dc01a4SJames Chapman skb_queue_tail(&session->reorder_q, skb); 551b6dc01a4SJames Chapman } 552b6dc01a4SJames Chapman 553a0dbd822SJames Chapman out: 554b6dc01a4SJames Chapman return 0; 555b6dc01a4SJames Chapman 556b6dc01a4SJames Chapman discard: 557b6dc01a4SJames Chapman return 1; 558b6dc01a4SJames Chapman } 559b6dc01a4SJames Chapman 560f7faffa3SJames Chapman /* Do receive processing of L2TP data frames. We handle both L2TPv2 561f7faffa3SJames Chapman * and L2TPv3 data frames here. 562f7faffa3SJames Chapman * 563f7faffa3SJames Chapman * L2TPv2 Data Message Header 564f7faffa3SJames Chapman * 565f7faffa3SJames Chapman * 0 1 2 3 566f7faffa3SJames Chapman * 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 567f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 568f7faffa3SJames Chapman * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) | 569f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 570f7faffa3SJames Chapman * | Tunnel ID | Session ID | 571f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 572f7faffa3SJames Chapman * | Ns (opt) | Nr (opt) | 573f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 574f7faffa3SJames Chapman * | Offset Size (opt) | Offset pad... (opt) 575f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 576f7faffa3SJames Chapman * 577f7faffa3SJames Chapman * Data frames are marked by T=0. All other fields are the same as 578f7faffa3SJames Chapman * those in L2TP control frames. 579f7faffa3SJames Chapman * 580f7faffa3SJames Chapman * L2TPv3 Data Message Header 581f7faffa3SJames Chapman * 582f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 583f7faffa3SJames Chapman * | L2TP Session Header | 584f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 585f7faffa3SJames Chapman * | L2-Specific Sublayer | 586f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 587f7faffa3SJames Chapman * | Tunnel Payload ... 588f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 589f7faffa3SJames Chapman * 590f7faffa3SJames Chapman * L2TPv3 Session Header Over IP 591f7faffa3SJames Chapman * 592f7faffa3SJames Chapman * 0 1 2 3 593f7faffa3SJames Chapman * 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 594f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 595f7faffa3SJames Chapman * | Session ID | 596f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 597f7faffa3SJames Chapman * | Cookie (optional, maximum 64 bits)... 598f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 599f7faffa3SJames Chapman * | 600f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 601f7faffa3SJames Chapman * 602f7faffa3SJames Chapman * L2TPv3 L2-Specific Sublayer Format 603f7faffa3SJames Chapman * 604f7faffa3SJames Chapman * 0 1 2 3 605f7faffa3SJames Chapman * 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 606f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 607f7faffa3SJames Chapman * |x|S|x|x|x|x|x|x| Sequence Number | 608f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 609f7faffa3SJames Chapman * 61023fe846fSGuillaume Nault * Cookie value and sublayer format are negotiated with the peer when 61123fe846fSGuillaume Nault * the session is set up. Unlike L2TPv2, we do not need to parse the 61223fe846fSGuillaume Nault * packet header to determine if optional fields are present. 613f7faffa3SJames Chapman * 614f7faffa3SJames Chapman * Caller must already have parsed the frame and determined that it is 615f7faffa3SJames Chapman * a data (not control) frame before coming here. Fields up to the 616f7faffa3SJames Chapman * session-id have already been parsed and ptr points to the data 617f7faffa3SJames Chapman * after the session-id. 618f7faffa3SJames Chapman */ 619f7faffa3SJames Chapman void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, 620f7faffa3SJames Chapman unsigned char *ptr, unsigned char *optr, u16 hdrflags, 6212b139e6bSGuillaume Nault int length) 622f7faffa3SJames Chapman { 623f7faffa3SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 624f7faffa3SJames Chapman int offset; 625f7faffa3SJames Chapman u32 ns, nr; 626f7faffa3SJames Chapman 627f7faffa3SJames Chapman /* Parse and check optional cookie */ 628f7faffa3SJames Chapman if (session->peer_cookie_len > 0) { 629f7faffa3SJames Chapman if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { 630a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_DATA, 631f7faffa3SJames Chapman "%s: cookie mismatch (%u/%u). Discarding.\n", 632a4ca44faSJoe Perches tunnel->name, tunnel->tunnel_id, 633a4ca44faSJoe Perches session->session_id); 6347b7c0719STom Parkin atomic_long_inc(&session->stats.rx_cookie_discards); 635f7faffa3SJames Chapman goto discard; 636f7faffa3SJames Chapman } 637f7faffa3SJames Chapman ptr += session->peer_cookie_len; 638f7faffa3SJames Chapman } 639f7faffa3SJames Chapman 640f7faffa3SJames Chapman /* Handle the optional sequence numbers. Sequence numbers are 641f7faffa3SJames Chapman * in different places for L2TPv2 and L2TPv3. 642f7faffa3SJames Chapman * 643f7faffa3SJames Chapman * If we are the LAC, enable/disable sequence numbers under 644f7faffa3SJames Chapman * the control of the LNS. If no sequence numbers present but 645f7faffa3SJames Chapman * we were expecting them, discard frame. 646f7faffa3SJames Chapman */ 647f7faffa3SJames Chapman ns = nr = 0; 648f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 0; 649f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) { 650f7faffa3SJames Chapman if (hdrflags & L2TP_HDRFLAG_S) { 651f7faffa3SJames Chapman ns = ntohs(*(__be16 *) ptr); 652f7faffa3SJames Chapman ptr += 2; 653f7faffa3SJames Chapman nr = ntohs(*(__be16 *) ptr); 654f7faffa3SJames Chapman ptr += 2; 655f7faffa3SJames Chapman 656f7faffa3SJames Chapman /* Store L2TP info in the skb */ 657f7faffa3SJames Chapman L2TP_SKB_CB(skb)->ns = ns; 658f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 1; 659f7faffa3SJames Chapman 660a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 661f7faffa3SJames Chapman "%s: recv data ns=%u, nr=%u, session nr=%u\n", 662f7faffa3SJames Chapman session->name, ns, nr, session->nr); 663f7faffa3SJames Chapman } 664f7faffa3SJames Chapman } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 665f7faffa3SJames Chapman u32 l2h = ntohl(*(__be32 *) ptr); 666f7faffa3SJames Chapman 667f7faffa3SJames Chapman if (l2h & 0x40000000) { 668f7faffa3SJames Chapman ns = l2h & 0x00ffffff; 669f7faffa3SJames Chapman 670f7faffa3SJames Chapman /* Store L2TP info in the skb */ 671f7faffa3SJames Chapman L2TP_SKB_CB(skb)->ns = ns; 672f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 1; 673f7faffa3SJames Chapman 674a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 675f7faffa3SJames Chapman "%s: recv data ns=%u, session nr=%u\n", 676f7faffa3SJames Chapman session->name, ns, session->nr); 677f7faffa3SJames Chapman } 67862e7b6a5SLorenzo Bianconi ptr += 4; 679f7faffa3SJames Chapman } 680f7faffa3SJames Chapman 681f7faffa3SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) { 682f7faffa3SJames Chapman /* Received a packet with sequence numbers. If we're the LNS, 683f7faffa3SJames Chapman * check if we sre sending sequence numbers and if not, 684f7faffa3SJames Chapman * configure it so. 685f7faffa3SJames Chapman */ 686f7faffa3SJames Chapman if ((!session->lns_mode) && (!session->send_seq)) { 687a4ca44faSJoe Perches l2tp_info(session, L2TP_MSG_SEQ, 688f7faffa3SJames Chapman "%s: requested to enable seq numbers by LNS\n", 689f7faffa3SJames Chapman session->name); 6903f9b9770SAsbjørn Sloth Tønnesen session->send_seq = 1; 691f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version); 692f7faffa3SJames Chapman } 693f7faffa3SJames Chapman } else { 694f7faffa3SJames Chapman /* No sequence numbers. 695f7faffa3SJames Chapman * If user has configured mandatory sequence numbers, discard. 696f7faffa3SJames Chapman */ 697f7faffa3SJames Chapman if (session->recv_seq) { 698a4ca44faSJoe Perches l2tp_warn(session, L2TP_MSG_SEQ, 699a4ca44faSJoe Perches "%s: recv data has no seq numbers when required. Discarding.\n", 700a4ca44faSJoe Perches session->name); 7017b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards); 702f7faffa3SJames Chapman goto discard; 703f7faffa3SJames Chapman } 704f7faffa3SJames Chapman 705f7faffa3SJames Chapman /* If we're the LAC and we're sending sequence numbers, the 706f7faffa3SJames Chapman * LNS has requested that we no longer send sequence numbers. 707f7faffa3SJames Chapman * If we're the LNS and we're sending sequence numbers, the 708f7faffa3SJames Chapman * LAC is broken. Discard the frame. 709f7faffa3SJames Chapman */ 710f7faffa3SJames Chapman if ((!session->lns_mode) && (session->send_seq)) { 711a4ca44faSJoe Perches l2tp_info(session, L2TP_MSG_SEQ, 712f7faffa3SJames Chapman "%s: requested to disable seq numbers by LNS\n", 713f7faffa3SJames Chapman session->name); 714f7faffa3SJames Chapman session->send_seq = 0; 715f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version); 716f7faffa3SJames Chapman } else if (session->send_seq) { 717a4ca44faSJoe Perches l2tp_warn(session, L2TP_MSG_SEQ, 718a4ca44faSJoe Perches "%s: recv data has no seq numbers when required. Discarding.\n", 719a4ca44faSJoe Perches session->name); 7207b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards); 721f7faffa3SJames Chapman goto discard; 722f7faffa3SJames Chapman } 723f7faffa3SJames Chapman } 724f7faffa3SJames Chapman 725900631eeSJames Chapman /* Session data offset is defined only for L2TPv2 and is 726900631eeSJames Chapman * indicated by an optional 16-bit value in the header. 727f7faffa3SJames Chapman */ 728f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) { 729f7faffa3SJames Chapman /* If offset bit set, skip it. */ 730f7faffa3SJames Chapman if (hdrflags & L2TP_HDRFLAG_O) { 731f7faffa3SJames Chapman offset = ntohs(*(__be16 *)ptr); 732f7faffa3SJames Chapman ptr += 2 + offset; 733f7faffa3SJames Chapman } 734900631eeSJames Chapman } 735f7faffa3SJames Chapman 736f7faffa3SJames Chapman offset = ptr - optr; 737f7faffa3SJames Chapman if (!pskb_may_pull(skb, offset)) 738f7faffa3SJames Chapman goto discard; 739f7faffa3SJames Chapman 740f7faffa3SJames Chapman __skb_pull(skb, offset); 741f7faffa3SJames Chapman 742f7faffa3SJames Chapman /* Prepare skb for adding to the session's reorder_q. Hold 743f7faffa3SJames Chapman * packets for max reorder_timeout or 1 second if not 744f7faffa3SJames Chapman * reordering. 745f7faffa3SJames Chapman */ 746f7faffa3SJames Chapman L2TP_SKB_CB(skb)->length = length; 747f7faffa3SJames Chapman L2TP_SKB_CB(skb)->expires = jiffies + 748f7faffa3SJames Chapman (session->reorder_timeout ? session->reorder_timeout : HZ); 749f7faffa3SJames Chapman 750f7faffa3SJames Chapman /* Add packet to the session's receive queue. Reordering is done here, if 751f7faffa3SJames Chapman * enabled. Saved L2TP protocol info is stored in skb->sb[]. 752f7faffa3SJames Chapman */ 753f7faffa3SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) { 754b6dc01a4SJames Chapman if (l2tp_recv_data_seq(session, skb)) 755f7faffa3SJames Chapman goto discard; 756f7faffa3SJames Chapman } else { 757f7faffa3SJames Chapman /* No sequence numbers. Add the skb to the tail of the 758f7faffa3SJames Chapman * reorder queue. This ensures that it will be 759f7faffa3SJames Chapman * delivered after all previous sequenced skbs. 760f7faffa3SJames Chapman */ 761f7faffa3SJames Chapman skb_queue_tail(&session->reorder_q, skb); 762f7faffa3SJames Chapman } 763f7faffa3SJames Chapman 764f7faffa3SJames Chapman /* Try to dequeue as many skbs from reorder_q as we can. */ 765f7faffa3SJames Chapman l2tp_recv_dequeue(session); 766f7faffa3SJames Chapman 767f7faffa3SJames Chapman return; 768f7faffa3SJames Chapman 769f7faffa3SJames Chapman discard: 7707b7c0719STom Parkin atomic_long_inc(&session->stats.rx_errors); 771f7faffa3SJames Chapman kfree_skb(skb); 772f7faffa3SJames Chapman } 773f7faffa3SJames Chapman EXPORT_SYMBOL(l2tp_recv_common); 774f7faffa3SJames Chapman 77548f72f92STom Parkin /* Drop skbs from the session's reorder_q 77648f72f92STom Parkin */ 7772e67560eSGuillaume Nault static int l2tp_session_queue_purge(struct l2tp_session *session) 77848f72f92STom Parkin { 77948f72f92STom Parkin struct sk_buff *skb = NULL; 78048f72f92STom Parkin BUG_ON(!session); 78148f72f92STom Parkin BUG_ON(session->magic != L2TP_SESSION_MAGIC); 78248f72f92STom Parkin while ((skb = skb_dequeue(&session->reorder_q))) { 78348f72f92STom Parkin atomic_long_inc(&session->stats.rx_errors); 78448f72f92STom Parkin kfree_skb(skb); 78548f72f92STom Parkin } 78648f72f92STom Parkin return 0; 78748f72f92STom Parkin } 78848f72f92STom Parkin 789fd558d18SJames Chapman /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame 790fd558d18SJames Chapman * here. The skb is not on a list when we get here. 791fd558d18SJames Chapman * Returns 0 if the packet was a data packet and was successfully passed on. 792fd558d18SJames Chapman * Returns 1 if the packet was not a good data packet and could not be 793fd558d18SJames Chapman * forwarded. All such packets are passed up to userspace to deal with. 794fd558d18SJames Chapman */ 7952b139e6bSGuillaume Nault static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb) 796fd558d18SJames Chapman { 797fd558d18SJames Chapman struct l2tp_session *session = NULL; 798fd558d18SJames Chapman unsigned char *ptr, *optr; 799fd558d18SJames Chapman u16 hdrflags; 800fd558d18SJames Chapman u32 tunnel_id, session_id; 801fd558d18SJames Chapman u16 version; 802f7faffa3SJames Chapman int length; 803fd558d18SJames Chapman 80458d6085cSTom Herbert /* UDP has verifed checksum */ 805fd558d18SJames Chapman 806fd558d18SJames Chapman /* UDP always verifies the packet length. */ 807fd558d18SJames Chapman __skb_pull(skb, sizeof(struct udphdr)); 808fd558d18SJames Chapman 809fd558d18SJames Chapman /* Short packet? */ 81091c52470SJacob Wen if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) { 811a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_DATA, 812a4ca44faSJoe Perches "%s: recv short packet (len=%d)\n", 813a4ca44faSJoe Perches tunnel->name, skb->len); 814fd558d18SJames Chapman goto error; 815fd558d18SJames Chapman } 816fd558d18SJames Chapman 817fd558d18SJames Chapman /* Trace packet contents, if enabled */ 818fd558d18SJames Chapman if (tunnel->debug & L2TP_MSG_DATA) { 819fd558d18SJames Chapman length = min(32u, skb->len); 820fd558d18SJames Chapman if (!pskb_may_pull(skb, length)) 821fd558d18SJames Chapman goto error; 822fd558d18SJames Chapman 823a4ca44faSJoe Perches pr_debug("%s: recv\n", tunnel->name); 824a4ca44faSJoe Perches print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length); 825fd558d18SJames Chapman } 826fd558d18SJames Chapman 827e50e705cSEric Dumazet /* Point to L2TP header */ 828e50e705cSEric Dumazet optr = ptr = skb->data; 829e50e705cSEric Dumazet 830fd558d18SJames Chapman /* Get L2TP header flags */ 831fd558d18SJames Chapman hdrflags = ntohs(*(__be16 *) ptr); 832fd558d18SJames Chapman 833fd558d18SJames Chapman /* Check protocol version */ 834fd558d18SJames Chapman version = hdrflags & L2TP_HDR_VER_MASK; 835fd558d18SJames Chapman if (version != tunnel->version) { 836a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_DATA, 837fd558d18SJames Chapman "%s: recv protocol version mismatch: got %d expected %d\n", 838fd558d18SJames Chapman tunnel->name, version, tunnel->version); 839fd558d18SJames Chapman goto error; 840fd558d18SJames Chapman } 841fd558d18SJames Chapman 842fd558d18SJames Chapman /* Get length of L2TP packet */ 843fd558d18SJames Chapman length = skb->len; 844fd558d18SJames Chapman 845fd558d18SJames Chapman /* If type is control packet, it is handled by userspace. */ 846fd558d18SJames Chapman if (hdrflags & L2TP_HDRFLAG_T) { 847a4ca44faSJoe Perches l2tp_dbg(tunnel, L2TP_MSG_DATA, 848a4ca44faSJoe Perches "%s: recv control packet, len=%d\n", 849a4ca44faSJoe Perches tunnel->name, length); 850fd558d18SJames Chapman goto error; 851fd558d18SJames Chapman } 852fd558d18SJames Chapman 853fd558d18SJames Chapman /* Skip flags */ 854fd558d18SJames Chapman ptr += 2; 855fd558d18SJames Chapman 856f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) { 857fd558d18SJames Chapman /* If length is present, skip it */ 858fd558d18SJames Chapman if (hdrflags & L2TP_HDRFLAG_L) 859fd558d18SJames Chapman ptr += 2; 860fd558d18SJames Chapman 861fd558d18SJames Chapman /* Extract tunnel and session ID */ 862fd558d18SJames Chapman tunnel_id = ntohs(*(__be16 *) ptr); 863fd558d18SJames Chapman ptr += 2; 864fd558d18SJames Chapman session_id = ntohs(*(__be16 *) ptr); 865fd558d18SJames Chapman ptr += 2; 866f7faffa3SJames Chapman } else { 867f7faffa3SJames Chapman ptr += 2; /* skip reserved bits */ 868f7faffa3SJames Chapman tunnel_id = tunnel->tunnel_id; 869f7faffa3SJames Chapman session_id = ntohl(*(__be32 *) ptr); 870f7faffa3SJames Chapman ptr += 4; 871f7faffa3SJames Chapman } 872fd558d18SJames Chapman 873fd558d18SJames Chapman /* Find the session context */ 87401e28b92SGuillaume Nault session = l2tp_tunnel_get_session(tunnel, session_id); 875309795f4SJames Chapman if (!session || !session->recv_skb) { 876a4346210SGuillaume Nault if (session) 87761b9a047SGuillaume Nault l2tp_session_dec_refcount(session); 87861b9a047SGuillaume Nault 879fd558d18SJames Chapman /* Not found? Pass to userspace to deal with */ 880a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_DATA, 881f7faffa3SJames Chapman "%s: no session found (%u/%u). Passing up.\n", 882fd558d18SJames Chapman tunnel->name, tunnel_id, session_id); 883fd558d18SJames Chapman goto error; 884fd558d18SJames Chapman } 885fd558d18SJames Chapman 8864522a70dSJacob Wen if (tunnel->version == L2TP_HDR_VER_3 && 8874522a70dSJacob Wen l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) 8884522a70dSJacob Wen goto error; 8894522a70dSJacob Wen 8902b139e6bSGuillaume Nault l2tp_recv_common(session, skb, ptr, optr, hdrflags, length); 89161b9a047SGuillaume Nault l2tp_session_dec_refcount(session); 892fd558d18SJames Chapman 893fd558d18SJames Chapman return 0; 894fd558d18SJames Chapman 895fd558d18SJames Chapman error: 896fd558d18SJames Chapman /* Put UDP header back */ 897fd558d18SJames Chapman __skb_push(skb, sizeof(struct udphdr)); 898fd558d18SJames Chapman 899fd558d18SJames Chapman return 1; 900fd558d18SJames Chapman } 901fd558d18SJames Chapman 902fd558d18SJames Chapman /* UDP encapsulation receive handler. See net/ipv4/udp.c. 903fd558d18SJames Chapman * Return codes: 904fd558d18SJames Chapman * 0 : success. 905fd558d18SJames Chapman * <0: error 906fd558d18SJames Chapman * >0: skb should be passed up to userspace as UDP. 907fd558d18SJames Chapman */ 908fd558d18SJames Chapman int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) 909fd558d18SJames Chapman { 910fd558d18SJames Chapman struct l2tp_tunnel *tunnel; 911fd558d18SJames Chapman 912d00fa9adSJames Chapman tunnel = l2tp_tunnel(sk); 913fd558d18SJames Chapman if (tunnel == NULL) 914fd558d18SJames Chapman goto pass_up; 915fd558d18SJames Chapman 916a4ca44faSJoe Perches l2tp_dbg(tunnel, L2TP_MSG_DATA, "%s: received %d bytes\n", 917a4ca44faSJoe Perches tunnel->name, skb->len); 918fd558d18SJames Chapman 9192b139e6bSGuillaume Nault if (l2tp_udp_recv_core(tunnel, skb)) 920d00fa9adSJames Chapman goto pass_up; 921fd558d18SJames Chapman 922fd558d18SJames Chapman return 0; 923fd558d18SJames Chapman 924fd558d18SJames Chapman pass_up: 925fd558d18SJames Chapman return 1; 926fd558d18SJames Chapman } 927fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_udp_encap_recv); 928fd558d18SJames Chapman 929fd558d18SJames Chapman /************************************************************************ 930fd558d18SJames Chapman * Transmit handling 931fd558d18SJames Chapman ***********************************************************************/ 932fd558d18SJames Chapman 933fd558d18SJames Chapman /* Build an L2TP header for the session into the buffer provided. 934fd558d18SJames Chapman */ 935f7faffa3SJames Chapman static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) 936fd558d18SJames Chapman { 937f7faffa3SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 938fd558d18SJames Chapman __be16 *bufp = buf; 939f7faffa3SJames Chapman __be16 *optr = buf; 940fd558d18SJames Chapman u16 flags = L2TP_HDR_VER_2; 941fd558d18SJames Chapman u32 tunnel_id = tunnel->peer_tunnel_id; 942fd558d18SJames Chapman u32 session_id = session->peer_session_id; 943fd558d18SJames Chapman 944fd558d18SJames Chapman if (session->send_seq) 945fd558d18SJames Chapman flags |= L2TP_HDRFLAG_S; 946fd558d18SJames Chapman 947fd558d18SJames Chapman /* Setup L2TP header. */ 948fd558d18SJames Chapman *bufp++ = htons(flags); 949fd558d18SJames Chapman *bufp++ = htons(tunnel_id); 950fd558d18SJames Chapman *bufp++ = htons(session_id); 951fd558d18SJames Chapman if (session->send_seq) { 952fd558d18SJames Chapman *bufp++ = htons(session->ns); 953fd558d18SJames Chapman *bufp++ = 0; 954fd558d18SJames Chapman session->ns++; 955f7faffa3SJames Chapman session->ns &= 0xffff; 956a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated ns to %u\n", 957a4ca44faSJoe Perches session->name, session->ns); 958fd558d18SJames Chapman } 959fd558d18SJames Chapman 960f7faffa3SJames Chapman return bufp - optr; 961f7faffa3SJames Chapman } 962f7faffa3SJames Chapman 963f7faffa3SJames Chapman static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) 964fd558d18SJames Chapman { 9650d76751fSJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 966f7faffa3SJames Chapman char *bufp = buf; 967f7faffa3SJames Chapman char *optr = bufp; 968fd558d18SJames Chapman 9690d76751fSJames Chapman /* Setup L2TP header. The header differs slightly for UDP and 9700d76751fSJames Chapman * IP encapsulations. For UDP, there is 4 bytes of flags. 9710d76751fSJames Chapman */ 9720d76751fSJames Chapman if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 9730d76751fSJames Chapman u16 flags = L2TP_HDR_VER_3; 974f7faffa3SJames Chapman *((__be16 *) bufp) = htons(flags); 975f7faffa3SJames Chapman bufp += 2; 976f7faffa3SJames Chapman *((__be16 *) bufp) = 0; 977f7faffa3SJames Chapman bufp += 2; 9780d76751fSJames Chapman } 9790d76751fSJames Chapman 980f7faffa3SJames Chapman *((__be32 *) bufp) = htonl(session->peer_session_id); 981f7faffa3SJames Chapman bufp += 4; 982f7faffa3SJames Chapman if (session->cookie_len) { 983f7faffa3SJames Chapman memcpy(bufp, &session->cookie[0], session->cookie_len); 984f7faffa3SJames Chapman bufp += session->cookie_len; 985fd558d18SJames Chapman } 986f7faffa3SJames Chapman if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { 987f7faffa3SJames Chapman u32 l2h = 0; 98862e7b6a5SLorenzo Bianconi 989f7faffa3SJames Chapman if (session->send_seq) { 990f7faffa3SJames Chapman l2h = 0x40000000 | session->ns; 991f7faffa3SJames Chapman session->ns++; 992f7faffa3SJames Chapman session->ns &= 0xffffff; 993a4ca44faSJoe Perches l2tp_dbg(session, L2TP_MSG_SEQ, 994a4ca44faSJoe Perches "%s: updated ns to %u\n", 995a4ca44faSJoe Perches session->name, session->ns); 996f7faffa3SJames Chapman } 997f7faffa3SJames Chapman 998f7faffa3SJames Chapman *((__be32 *)bufp) = htonl(l2h); 99962e7b6a5SLorenzo Bianconi bufp += 4; 1000f7faffa3SJames Chapman } 1001f7faffa3SJames Chapman 1002f7faffa3SJames Chapman return bufp - optr; 1003f7faffa3SJames Chapman } 1004fd558d18SJames Chapman 10052685fbb8SGuillaume Nault static void l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, 1006d9d8da80SDavid S. Miller struct flowi *fl, size_t data_len) 1007fd558d18SJames Chapman { 1008fd558d18SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 1009fd558d18SJames Chapman unsigned int len = skb->len; 1010fd558d18SJames Chapman int error; 1011fd558d18SJames Chapman 1012fd558d18SJames Chapman /* Debug */ 1013fd558d18SJames Chapman if (session->send_seq) 10145b5e0928SAlexey Dobriyan l2tp_dbg(session, L2TP_MSG_DATA, "%s: send %zd bytes, ns=%u\n", 1015a4ca44faSJoe Perches session->name, data_len, session->ns - 1); 1016fd558d18SJames Chapman else 10175b5e0928SAlexey Dobriyan l2tp_dbg(session, L2TP_MSG_DATA, "%s: send %zd bytes\n", 1018a4ca44faSJoe Perches session->name, data_len); 1019fd558d18SJames Chapman 1020fd558d18SJames Chapman if (session->debug & L2TP_MSG_DATA) { 10210d76751fSJames Chapman int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; 10220d76751fSJames Chapman unsigned char *datap = skb->data + uhlen; 1023fd558d18SJames Chapman 1024a4ca44faSJoe Perches pr_debug("%s: xmit\n", session->name); 1025a4ca44faSJoe Perches print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, 1026a4ca44faSJoe Perches datap, min_t(size_t, 32, len - uhlen)); 1027fd558d18SJames Chapman } 1028fd558d18SJames Chapman 1029fd558d18SJames Chapman /* Queue the packet to IP for output */ 103060ff7467SWANG Cong skb->ignore_df = 1; 1031d2cf3361SBenjamin LaHaise #if IS_ENABLED(CONFIG_IPV6) 1032b954f940SPaolo Abeni if (l2tp_sk_is_v6(tunnel->sock)) 1033b0270e91SEric Dumazet error = inet6_csk_xmit(tunnel->sock, skb, NULL); 1034d2cf3361SBenjamin LaHaise else 1035d2cf3361SBenjamin LaHaise #endif 1036b0270e91SEric Dumazet error = ip_queue_xmit(tunnel->sock, skb, fl); 1037fd558d18SJames Chapman 1038fd558d18SJames Chapman /* Update stats */ 1039fd558d18SJames Chapman if (error >= 0) { 10407b7c0719STom Parkin atomic_long_inc(&tunnel->stats.tx_packets); 10417b7c0719STom Parkin atomic_long_add(len, &tunnel->stats.tx_bytes); 10427b7c0719STom Parkin atomic_long_inc(&session->stats.tx_packets); 10437b7c0719STom Parkin atomic_long_add(len, &session->stats.tx_bytes); 1044fd558d18SJames Chapman } else { 10457b7c0719STom Parkin atomic_long_inc(&tunnel->stats.tx_errors); 10467b7c0719STom Parkin atomic_long_inc(&session->stats.tx_errors); 1047fd558d18SJames Chapman } 1048fd558d18SJames Chapman } 1049fd558d18SJames Chapman 1050fd558d18SJames Chapman /* If caller requires the skb to have a ppp header, the header must be 1051fd558d18SJames Chapman * inserted in the skb data before calling this function. 1052fd558d18SJames Chapman */ 1053fd558d18SJames Chapman int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len) 1054fd558d18SJames Chapman { 1055fd558d18SJames Chapman int data_len = skb->len; 10560d76751fSJames Chapman struct l2tp_tunnel *tunnel = session->tunnel; 10570d76751fSJames Chapman struct sock *sk = tunnel->sock; 1058d9d8da80SDavid S. Miller struct flowi *fl; 1059fd558d18SJames Chapman struct udphdr *uh; 1060fd558d18SJames Chapman struct inet_sock *inet; 1061fd558d18SJames Chapman int headroom; 10620d76751fSJames Chapman int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; 10630d76751fSJames Chapman int udp_len; 1064b8c84307SEric Dumazet int ret = NET_XMIT_SUCCESS; 1065fd558d18SJames Chapman 1066fd558d18SJames Chapman /* Check that there's enough headroom in the skb to insert IP, 1067fd558d18SJames Chapman * UDP and L2TP headers. If not enough, expand it to 1068fd558d18SJames Chapman * make room. Adjust truesize. 1069fd558d18SJames Chapman */ 1070fd558d18SJames Chapman headroom = NET_SKB_PAD + sizeof(struct iphdr) + 10710d76751fSJames Chapman uhlen + hdr_len; 1072835acf5dSEric Dumazet if (skb_cow_head(skb, headroom)) { 1073b8c84307SEric Dumazet kfree_skb(skb); 1074b8c84307SEric Dumazet return NET_XMIT_DROP; 1075835acf5dSEric Dumazet } 1076fd558d18SJames Chapman 1077fd558d18SJames Chapman /* Setup L2TP header */ 1078f7faffa3SJames Chapman session->build_header(session, __skb_push(skb, hdr_len)); 1079fd558d18SJames Chapman 10800d76751fSJames Chapman /* Reset skb netfilter state */ 1081fd558d18SJames Chapman memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 1082fd558d18SJames Chapman IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | 1083fd558d18SJames Chapman IPSKB_REROUTED); 1084fd558d18SJames Chapman nf_reset(skb); 1085fd558d18SJames Chapman 10866af88da1SDavid S. Miller bh_lock_sock(sk); 10876af88da1SDavid S. Miller if (sock_owned_by_user(sk)) { 1088b8c84307SEric Dumazet kfree_skb(skb); 1089b8c84307SEric Dumazet ret = NET_XMIT_DROP; 10906af88da1SDavid S. Miller goto out_unlock; 10916af88da1SDavid S. Miller } 10926af88da1SDavid S. Miller 1093b954f940SPaolo Abeni /* The user-space may change the connection status for the user-space 1094b954f940SPaolo Abeni * provided socket at run time: we must check it under the socket lock 1095b954f940SPaolo Abeni */ 1096b954f940SPaolo Abeni if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { 1097b954f940SPaolo Abeni kfree_skb(skb); 1098b954f940SPaolo Abeni ret = NET_XMIT_DROP; 1099b954f940SPaolo Abeni goto out_unlock; 1100b954f940SPaolo Abeni } 1101b954f940SPaolo Abeni 1102fd558d18SJames Chapman /* Get routing info from the tunnel socket */ 1103fd558d18SJames Chapman skb_dst_drop(skb); 11046d37fa49SWei Wang skb_dst_set(skb, sk_dst_check(sk, 0)); 11050d76751fSJames Chapman 1106d9d8da80SDavid S. Miller inet = inet_sk(sk); 1107d9d8da80SDavid S. Miller fl = &inet->cork.fl; 11080d76751fSJames Chapman switch (tunnel->encap) { 11090d76751fSJames Chapman case L2TP_ENCAPTYPE_UDP: 11100d76751fSJames Chapman /* Setup UDP header */ 11110d76751fSJames Chapman __skb_push(skb, sizeof(*uh)); 11120d76751fSJames Chapman skb_reset_transport_header(skb); 11130d76751fSJames Chapman uh = udp_hdr(skb); 11140d76751fSJames Chapman uh->source = inet->inet_sport; 11150d76751fSJames Chapman uh->dest = inet->inet_dport; 11160d76751fSJames Chapman udp_len = uhlen + hdr_len + data_len; 11170d76751fSJames Chapman uh->len = htons(udp_len); 1118fd558d18SJames Chapman 1119fd558d18SJames Chapman /* Calculate UDP checksum if configured to do so */ 1120d2cf3361SBenjamin LaHaise #if IS_ENABLED(CONFIG_IPV6) 1121b954f940SPaolo Abeni if (l2tp_sk_is_v6(sk)) 112277157e19STom Herbert udp6_set_csum(udp_get_no_check6_tx(sk), 112377157e19STom Herbert skb, &inet6_sk(sk)->saddr, 112477157e19STom Herbert &sk->sk_v6_daddr, udp_len); 1125d2cf3361SBenjamin LaHaise else 1126d2cf3361SBenjamin LaHaise #endif 112777157e19STom Herbert udp_set_csum(sk->sk_no_check_tx, skb, inet->inet_saddr, 112877157e19STom Herbert inet->inet_daddr, udp_len); 11290d76751fSJames Chapman break; 11300d76751fSJames Chapman 11310d76751fSJames Chapman case L2TP_ENCAPTYPE_IP: 11320d76751fSJames Chapman break; 11330d76751fSJames Chapman } 11340d76751fSJames Chapman 1135d9d8da80SDavid S. Miller l2tp_xmit_core(session, skb, fl, data_len); 11366af88da1SDavid S. Miller out_unlock: 11376af88da1SDavid S. Miller bh_unlock_sock(sk); 1138fd558d18SJames Chapman 1139b8c84307SEric Dumazet return ret; 1140fd558d18SJames Chapman } 1141fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_xmit_skb); 1142fd558d18SJames Chapman 1143fd558d18SJames Chapman /***************************************************************************** 1144fd558d18SJames Chapman * Tinnel and session create/destroy. 1145fd558d18SJames Chapman *****************************************************************************/ 1146fd558d18SJames Chapman 1147fd558d18SJames Chapman /* Tunnel socket destruct hook. 1148fd558d18SJames Chapman * The tunnel context is deleted only when all session sockets have been 1149fd558d18SJames Chapman * closed. 1150fd558d18SJames Chapman */ 1151fc130840Sstephen hemminger static void l2tp_tunnel_destruct(struct sock *sk) 1152fd558d18SJames Chapman { 11538d8a51e2SDavid S. Miller struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); 1154fd558d18SJames Chapman 1155fd558d18SJames Chapman if (tunnel == NULL) 1156fd558d18SJames Chapman goto end; 1157fd558d18SJames Chapman 1158a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name); 1159fd558d18SJames Chapman 1160f8ccac0eSTom Parkin /* Disable udp encapsulation */ 11610d76751fSJames Chapman switch (tunnel->encap) { 11620d76751fSJames Chapman case L2TP_ENCAPTYPE_UDP: 1163fd558d18SJames Chapman /* No longer an encapsulation socket. See net/ipv4/udp.c */ 1164fd558d18SJames Chapman (udp_sk(sk))->encap_type = 0; 1165fd558d18SJames Chapman (udp_sk(sk))->encap_rcv = NULL; 11669980d001STom Parkin (udp_sk(sk))->encap_destroy = NULL; 11670d76751fSJames Chapman break; 11680d76751fSJames Chapman case L2TP_ENCAPTYPE_IP: 11690d76751fSJames Chapman break; 11700d76751fSJames Chapman } 1171fd558d18SJames Chapman 1172fd558d18SJames Chapman /* Remove hooks into tunnel socket */ 1173fd558d18SJames Chapman sk->sk_destruct = tunnel->old_sk_destruct; 1174fd558d18SJames Chapman sk->sk_user_data = NULL; 1175f8ccac0eSTom Parkin 1176fd558d18SJames Chapman /* Call the original destructor */ 1177fd558d18SJames Chapman if (sk->sk_destruct) 1178fd558d18SJames Chapman (*sk->sk_destruct)(sk); 1179d00fa9adSJames Chapman 1180d00fa9adSJames Chapman kfree_rcu(tunnel, rcu); 1181fd558d18SJames Chapman end: 1182fd558d18SJames Chapman return; 1183fd558d18SJames Chapman } 1184fd558d18SJames Chapman 1185fd558d18SJames Chapman /* When the tunnel is closed, all the attached sessions need to go too. 1186fd558d18SJames Chapman */ 1187d08532bbSGuillaume Nault static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) 1188fd558d18SJames Chapman { 1189fd558d18SJames Chapman int hash; 1190fd558d18SJames Chapman struct hlist_node *walk; 1191fd558d18SJames Chapman struct hlist_node *tmp; 1192fd558d18SJames Chapman struct l2tp_session *session; 1193fd558d18SJames Chapman 1194fd558d18SJames Chapman BUG_ON(tunnel == NULL); 1195fd558d18SJames Chapman 1196a4ca44faSJoe Perches l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing all sessions...\n", 1197a4ca44faSJoe Perches tunnel->name); 1198fd558d18SJames Chapman 1199fd558d18SJames Chapman write_lock_bh(&tunnel->hlist_lock); 1200f3c66d4eSGuillaume Nault tunnel->acpt_newsess = false; 1201fd558d18SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { 1202fd558d18SJames Chapman again: 1203fd558d18SJames Chapman hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { 1204fd558d18SJames Chapman session = hlist_entry(walk, struct l2tp_session, hlist); 1205fd558d18SJames Chapman 1206a4ca44faSJoe Perches l2tp_info(session, L2TP_MSG_CONTROL, 1207fd558d18SJames Chapman "%s: closing session\n", session->name); 1208fd558d18SJames Chapman 1209fd558d18SJames Chapman hlist_del_init(&session->hlist); 1210fd558d18SJames Chapman 1211b228a940SGuillaume Nault if (test_and_set_bit(0, &session->dead)) 1212b228a940SGuillaume Nault goto again; 1213b228a940SGuillaume Nault 1214fd558d18SJames Chapman write_unlock_bh(&tunnel->hlist_lock); 1215fd558d18SJames Chapman 1216f6e16b29STom Parkin __l2tp_session_unhash(session); 12174c6e2fd3STom Parkin l2tp_session_queue_purge(session); 12184c6e2fd3STom Parkin 1219fd558d18SJames Chapman if (session->session_close != NULL) 1220fd558d18SJames Chapman (*session->session_close)(session); 1221fd558d18SJames Chapman 12229980d001STom Parkin l2tp_session_dec_refcount(session); 12239980d001STom Parkin 1224fd558d18SJames Chapman write_lock_bh(&tunnel->hlist_lock); 1225fd558d18SJames Chapman 1226fd558d18SJames Chapman /* Now restart from the beginning of this hash 1227fd558d18SJames Chapman * chain. We always remove a session from the 1228fd558d18SJames Chapman * list so we are guaranteed to make forward 1229fd558d18SJames Chapman * progress. 1230fd558d18SJames Chapman */ 1231fd558d18SJames Chapman goto again; 1232fd558d18SJames Chapman } 1233fd558d18SJames Chapman } 1234fd558d18SJames Chapman write_unlock_bh(&tunnel->hlist_lock); 1235fd558d18SJames Chapman } 1236fd558d18SJames Chapman 12379980d001STom Parkin /* Tunnel socket destroy hook for UDP encapsulation */ 12389980d001STom Parkin static void l2tp_udp_encap_destroy(struct sock *sk) 12399980d001STom Parkin { 1240d00fa9adSJames Chapman struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); 1241d00fa9adSJames Chapman 1242d00fa9adSJames Chapman if (tunnel) 1243d00fa9adSJames Chapman l2tp_tunnel_delete(tunnel); 12449980d001STom Parkin } 12459980d001STom Parkin 1246f8ccac0eSTom Parkin /* Workqueue tunnel deletion function */ 1247f8ccac0eSTom Parkin static void l2tp_tunnel_del_work(struct work_struct *work) 1248f8ccac0eSTom Parkin { 1249d00fa9adSJames Chapman struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, 1250d00fa9adSJames Chapman del_work); 1251d00fa9adSJames Chapman struct sock *sk = tunnel->sock; 1252d00fa9adSJames Chapman struct socket *sock = sk->sk_socket; 125328f5bfb8SJames Chapman struct l2tp_net *pn; 125412d656afSRidge Kennedy 125512d656afSRidge Kennedy l2tp_tunnel_closeall(tunnel); 125612d656afSRidge Kennedy 125776a6abdbSJames Chapman /* If the tunnel socket was created within the kernel, use 125802d13ed5STom Parkin * the sk API to release it here. 1259f8ccac0eSTom Parkin */ 126076a6abdbSJames Chapman if (tunnel->fd < 0) { 126126abe143SEric W. Biederman if (sock) { 1262167eb17eSTom Parkin kernel_sock_shutdown(sock, SHUT_RDWR); 126326abe143SEric W. Biederman sock_release(sock); 126426abe143SEric W. Biederman } 1265167eb17eSTom Parkin } 1266f8ccac0eSTom Parkin 126728f5bfb8SJames Chapman /* Remove the tunnel struct from the tunnel list */ 126828f5bfb8SJames Chapman pn = l2tp_pernet(tunnel->l2tp_net); 126928f5bfb8SJames Chapman spin_lock_bh(&pn->l2tp_tunnel_list_lock); 127028f5bfb8SJames Chapman list_del_rcu(&tunnel->list); 127128f5bfb8SJames Chapman spin_unlock_bh(&pn->l2tp_tunnel_list_lock); 127228f5bfb8SJames Chapman 1273d00fa9adSJames Chapman /* drop initial ref */ 1274d00fa9adSJames Chapman l2tp_tunnel_dec_refcount(tunnel); 1275d00fa9adSJames Chapman 1276d00fa9adSJames Chapman /* drop workqueue ref */ 127706a15f51SAlexander Couzens l2tp_tunnel_dec_refcount(tunnel); 1278fd558d18SJames Chapman } 1279fd558d18SJames Chapman 1280789a4a2cSJames Chapman /* Create a socket for the tunnel, if one isn't set up by 1281789a4a2cSJames Chapman * userspace. This is used for static tunnels where there is no 1282789a4a2cSJames Chapman * managing L2TP daemon. 1283167eb17eSTom Parkin * 1284167eb17eSTom Parkin * Since we don't want these sockets to keep a namespace alive by 1285167eb17eSTom Parkin * themselves, we drop the socket's namespace refcount after creation. 1286167eb17eSTom Parkin * These sockets are freed when the namespace exits using the pernet 1287167eb17eSTom Parkin * exit hook. 1288789a4a2cSJames Chapman */ 1289167eb17eSTom Parkin static int l2tp_tunnel_sock_create(struct net *net, 1290167eb17eSTom Parkin u32 tunnel_id, 1291167eb17eSTom Parkin u32 peer_tunnel_id, 1292167eb17eSTom Parkin struct l2tp_tunnel_cfg *cfg, 1293167eb17eSTom Parkin struct socket **sockp) 1294789a4a2cSJames Chapman { 1295789a4a2cSJames Chapman int err = -EINVAL; 12967bddd0dbSEric Dumazet struct socket *sock = NULL; 129785644b4dSTom Herbert struct udp_port_cfg udp_conf; 1298789a4a2cSJames Chapman 1299789a4a2cSJames Chapman switch (cfg->encap) { 1300789a4a2cSJames Chapman case L2TP_ENCAPTYPE_UDP: 130185644b4dSTom Herbert memset(&udp_conf, 0, sizeof(udp_conf)); 130285644b4dSTom Herbert 1303f9bac8dfSChris Elston #if IS_ENABLED(CONFIG_IPV6) 1304f9bac8dfSChris Elston if (cfg->local_ip6 && cfg->peer_ip6) { 130585644b4dSTom Herbert udp_conf.family = AF_INET6; 130685644b4dSTom Herbert memcpy(&udp_conf.local_ip6, cfg->local_ip6, 130785644b4dSTom Herbert sizeof(udp_conf.local_ip6)); 130885644b4dSTom Herbert memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, 130985644b4dSTom Herbert sizeof(udp_conf.peer_ip6)); 131085644b4dSTom Herbert udp_conf.use_udp6_tx_checksums = 1311018f8258SWang Shanker ! cfg->udp6_zero_tx_checksums; 131285644b4dSTom Herbert udp_conf.use_udp6_rx_checksums = 1313018f8258SWang Shanker ! cfg->udp6_zero_rx_checksums; 1314f9bac8dfSChris Elston } else 1315f9bac8dfSChris Elston #endif 1316f9bac8dfSChris Elston { 131785644b4dSTom Herbert udp_conf.family = AF_INET; 131885644b4dSTom Herbert udp_conf.local_ip = cfg->local_ip; 131985644b4dSTom Herbert udp_conf.peer_ip = cfg->peer_ip; 132085644b4dSTom Herbert udp_conf.use_udp_checksums = cfg->use_udp_checksums; 1321f9bac8dfSChris Elston } 1322789a4a2cSJames Chapman 132385644b4dSTom Herbert udp_conf.local_udp_port = htons(cfg->local_udp_port); 132485644b4dSTom Herbert udp_conf.peer_udp_port = htons(cfg->peer_udp_port); 132585644b4dSTom Herbert 132685644b4dSTom Herbert err = udp_sock_create(net, &udp_conf, &sock); 132785644b4dSTom Herbert if (err < 0) 132885644b4dSTom Herbert goto out; 1329789a4a2cSJames Chapman 1330789a4a2cSJames Chapman break; 1331789a4a2cSJames Chapman 1332789a4a2cSJames Chapman case L2TP_ENCAPTYPE_IP: 1333f9bac8dfSChris Elston #if IS_ENABLED(CONFIG_IPV6) 1334f9bac8dfSChris Elston if (cfg->local_ip6 && cfg->peer_ip6) { 133585644b4dSTom Herbert struct sockaddr_l2tpip6 ip6_addr = {0}; 133685644b4dSTom Herbert 133726abe143SEric W. Biederman err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 1338167eb17eSTom Parkin IPPROTO_L2TP, &sock); 13395dac94e1SJames Chapman if (err < 0) 1340f9bac8dfSChris Elston goto out; 13415dac94e1SJames Chapman 13425dac94e1SJames Chapman ip6_addr.l2tp_family = AF_INET6; 13435dac94e1SJames Chapman memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6, 13445dac94e1SJames Chapman sizeof(ip6_addr.l2tp_addr)); 13455dac94e1SJames Chapman ip6_addr.l2tp_conn_id = tunnel_id; 13465dac94e1SJames Chapman err = kernel_bind(sock, (struct sockaddr *) &ip6_addr, 13475dac94e1SJames Chapman sizeof(ip6_addr)); 13485dac94e1SJames Chapman if (err < 0) 13495dac94e1SJames Chapman goto out; 13505dac94e1SJames Chapman 13515dac94e1SJames Chapman ip6_addr.l2tp_family = AF_INET6; 13525dac94e1SJames Chapman memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6, 13535dac94e1SJames Chapman sizeof(ip6_addr.l2tp_addr)); 13545dac94e1SJames Chapman ip6_addr.l2tp_conn_id = peer_tunnel_id; 13555dac94e1SJames Chapman err = kernel_connect(sock, 13565dac94e1SJames Chapman (struct sockaddr *) &ip6_addr, 13575dac94e1SJames Chapman sizeof(ip6_addr), 0); 13585dac94e1SJames Chapman if (err < 0) 13595dac94e1SJames Chapman goto out; 13605dac94e1SJames Chapman } else 1361f9bac8dfSChris Elston #endif 13625dac94e1SJames Chapman { 136385644b4dSTom Herbert struct sockaddr_l2tpip ip_addr = {0}; 136485644b4dSTom Herbert 136526abe143SEric W. Biederman err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 1366167eb17eSTom Parkin IPPROTO_L2TP, &sock); 1367789a4a2cSJames Chapman if (err < 0) 1368789a4a2cSJames Chapman goto out; 1369789a4a2cSJames Chapman 1370789a4a2cSJames Chapman ip_addr.l2tp_family = AF_INET; 1371789a4a2cSJames Chapman ip_addr.l2tp_addr = cfg->local_ip; 1372789a4a2cSJames Chapman ip_addr.l2tp_conn_id = tunnel_id; 13735dac94e1SJames Chapman err = kernel_bind(sock, (struct sockaddr *) &ip_addr, 13745dac94e1SJames Chapman sizeof(ip_addr)); 1375789a4a2cSJames Chapman if (err < 0) 1376789a4a2cSJames Chapman goto out; 1377789a4a2cSJames Chapman 1378789a4a2cSJames Chapman ip_addr.l2tp_family = AF_INET; 1379789a4a2cSJames Chapman ip_addr.l2tp_addr = cfg->peer_ip; 1380789a4a2cSJames Chapman ip_addr.l2tp_conn_id = peer_tunnel_id; 13815dac94e1SJames Chapman err = kernel_connect(sock, (struct sockaddr *) &ip_addr, 13825dac94e1SJames Chapman sizeof(ip_addr), 0); 1383789a4a2cSJames Chapman if (err < 0) 1384789a4a2cSJames Chapman goto out; 13855dac94e1SJames Chapman } 1386789a4a2cSJames Chapman break; 1387789a4a2cSJames Chapman 1388789a4a2cSJames Chapman default: 1389789a4a2cSJames Chapman goto out; 1390789a4a2cSJames Chapman } 1391789a4a2cSJames Chapman 1392789a4a2cSJames Chapman out: 1393167eb17eSTom Parkin *sockp = sock; 1394789a4a2cSJames Chapman if ((err < 0) && sock) { 1395167eb17eSTom Parkin kernel_sock_shutdown(sock, SHUT_RDWR); 139626abe143SEric W. Biederman sock_release(sock); 1397789a4a2cSJames Chapman *sockp = NULL; 1398789a4a2cSJames Chapman } 1399789a4a2cSJames Chapman 1400789a4a2cSJames Chapman return err; 1401789a4a2cSJames Chapman } 1402789a4a2cSJames Chapman 140337159ef2SEric Dumazet static struct lock_class_key l2tp_socket_class; 140437159ef2SEric Dumazet 1405fd558d18SJames Chapman int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp) 1406fd558d18SJames Chapman { 1407fd558d18SJames Chapman struct l2tp_tunnel *tunnel = NULL; 1408fd558d18SJames Chapman int err; 14090d76751fSJames Chapman enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; 1410fd558d18SJames Chapman 14110d76751fSJames Chapman if (cfg != NULL) 14120d76751fSJames Chapman encap = cfg->encap; 14130d76751fSJames Chapman 1414fd558d18SJames Chapman tunnel = kzalloc(sizeof(struct l2tp_tunnel), GFP_KERNEL); 1415fd558d18SJames Chapman if (tunnel == NULL) { 1416fd558d18SJames Chapman err = -ENOMEM; 1417fd558d18SJames Chapman goto err; 1418fd558d18SJames Chapman } 1419fd558d18SJames Chapman 1420fd558d18SJames Chapman tunnel->version = version; 1421fd558d18SJames Chapman tunnel->tunnel_id = tunnel_id; 1422fd558d18SJames Chapman tunnel->peer_tunnel_id = peer_tunnel_id; 1423fd558d18SJames Chapman tunnel->debug = L2TP_DEFAULT_DEBUG_FLAGS; 1424fd558d18SJames Chapman 1425fd558d18SJames Chapman tunnel->magic = L2TP_TUNNEL_MAGIC; 1426fd558d18SJames Chapman sprintf(&tunnel->name[0], "tunl %u", tunnel_id); 1427fd558d18SJames Chapman rwlock_init(&tunnel->hlist_lock); 1428f3c66d4eSGuillaume Nault tunnel->acpt_newsess = true; 1429fd558d18SJames Chapman 14300d76751fSJames Chapman if (cfg != NULL) 1431fd558d18SJames Chapman tunnel->debug = cfg->debug; 1432fd558d18SJames Chapman 14330d76751fSJames Chapman tunnel->encap = encap; 1434fd558d18SJames Chapman 1435d00fa9adSJames Chapman refcount_set(&tunnel->ref_count, 1); 1436d00fa9adSJames Chapman tunnel->fd = fd; 1437d00fa9adSJames Chapman 1438f8ccac0eSTom Parkin /* Init delete workqueue struct */ 1439f8ccac0eSTom Parkin INIT_WORK(&tunnel->del_work, l2tp_tunnel_del_work); 1440f8ccac0eSTom Parkin 1441fd558d18SJames Chapman INIT_LIST_HEAD(&tunnel->list); 1442fd558d18SJames Chapman 1443fd558d18SJames Chapman err = 0; 1444fd558d18SJames Chapman err: 1445fd558d18SJames Chapman if (tunnelp) 1446fd558d18SJames Chapman *tunnelp = tunnel; 1447fd558d18SJames Chapman 1448fd558d18SJames Chapman return err; 1449fd558d18SJames Chapman } 1450fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_tunnel_create); 1451fd558d18SJames Chapman 14526b9f3423SGuillaume Nault static int l2tp_validate_socket(const struct sock *sk, const struct net *net, 14536b9f3423SGuillaume Nault enum l2tp_encap_type encap) 14546b9f3423SGuillaume Nault { 14556b9f3423SGuillaume Nault if (!net_eq(sock_net(sk), net)) 14566b9f3423SGuillaume Nault return -EINVAL; 14576b9f3423SGuillaume Nault 14586b9f3423SGuillaume Nault if (sk->sk_type != SOCK_DGRAM) 14596b9f3423SGuillaume Nault return -EPROTONOSUPPORT; 14606b9f3423SGuillaume Nault 14616b9f3423SGuillaume Nault if ((encap == L2TP_ENCAPTYPE_UDP && sk->sk_protocol != IPPROTO_UDP) || 14626b9f3423SGuillaume Nault (encap == L2TP_ENCAPTYPE_IP && sk->sk_protocol != IPPROTO_L2TP)) 14636b9f3423SGuillaume Nault return -EPROTONOSUPPORT; 14646b9f3423SGuillaume Nault 14656b9f3423SGuillaume Nault if (sk->sk_user_data) 14666b9f3423SGuillaume Nault return -EBUSY; 14676b9f3423SGuillaume Nault 14686b9f3423SGuillaume Nault return 0; 14696b9f3423SGuillaume Nault } 14706b9f3423SGuillaume Nault 14716b9f3423SGuillaume Nault int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net, 14726b9f3423SGuillaume Nault struct l2tp_tunnel_cfg *cfg) 14736b9f3423SGuillaume Nault { 1474f6cd651bSGuillaume Nault struct l2tp_tunnel *tunnel_walk; 14756b9f3423SGuillaume Nault struct l2tp_net *pn; 14766b9f3423SGuillaume Nault struct socket *sock; 14776b9f3423SGuillaume Nault struct sock *sk; 14786b9f3423SGuillaume Nault int ret; 14796b9f3423SGuillaume Nault 14806b9f3423SGuillaume Nault if (tunnel->fd < 0) { 14816b9f3423SGuillaume Nault ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id, 14826b9f3423SGuillaume Nault tunnel->peer_tunnel_id, cfg, 14836b9f3423SGuillaume Nault &sock); 14846b9f3423SGuillaume Nault if (ret < 0) 14856b9f3423SGuillaume Nault goto err; 14866b9f3423SGuillaume Nault } else { 14876b9f3423SGuillaume Nault sock = sockfd_lookup(tunnel->fd, &ret); 14886b9f3423SGuillaume Nault if (!sock) 14896b9f3423SGuillaume Nault goto err; 14906b9f3423SGuillaume Nault 14916b9f3423SGuillaume Nault ret = l2tp_validate_socket(sock->sk, net, tunnel->encap); 14926b9f3423SGuillaume Nault if (ret < 0) 14936b9f3423SGuillaume Nault goto err_sock; 14946b9f3423SGuillaume Nault } 14956b9f3423SGuillaume Nault 14966b9f3423SGuillaume Nault tunnel->l2tp_net = net; 14976b9f3423SGuillaume Nault pn = l2tp_pernet(net); 1498f6cd651bSGuillaume Nault 14996b9f3423SGuillaume Nault spin_lock_bh(&pn->l2tp_tunnel_list_lock); 1500f6cd651bSGuillaume Nault list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) { 1501f6cd651bSGuillaume Nault if (tunnel_walk->tunnel_id == tunnel->tunnel_id) { 1502f6cd651bSGuillaume Nault spin_unlock_bh(&pn->l2tp_tunnel_list_lock); 1503f6cd651bSGuillaume Nault 1504f6cd651bSGuillaume Nault ret = -EEXIST; 1505f6cd651bSGuillaume Nault goto err_sock; 1506f6cd651bSGuillaume Nault } 1507f6cd651bSGuillaume Nault } 15086b9f3423SGuillaume Nault list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); 15096b9f3423SGuillaume Nault spin_unlock_bh(&pn->l2tp_tunnel_list_lock); 15106b9f3423SGuillaume Nault 1511f8504f4cSXin Long sk = sock->sk; 1512f8504f4cSXin Long sock_hold(sk); 1513f8504f4cSXin Long tunnel->sock = sk; 1514f8504f4cSXin Long 15156b9f3423SGuillaume Nault if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 15166b9f3423SGuillaume Nault struct udp_tunnel_sock_cfg udp_cfg = { 15176b9f3423SGuillaume Nault .sk_user_data = tunnel, 15186b9f3423SGuillaume Nault .encap_type = UDP_ENCAP_L2TPINUDP, 15196b9f3423SGuillaume Nault .encap_rcv = l2tp_udp_encap_recv, 15206b9f3423SGuillaume Nault .encap_destroy = l2tp_udp_encap_destroy, 15216b9f3423SGuillaume Nault }; 15226b9f3423SGuillaume Nault 15236b9f3423SGuillaume Nault setup_udp_tunnel_sock(net, sock, &udp_cfg); 15246b9f3423SGuillaume Nault } else { 15256b9f3423SGuillaume Nault sk->sk_user_data = tunnel; 15266b9f3423SGuillaume Nault } 15276b9f3423SGuillaume Nault 15286b9f3423SGuillaume Nault tunnel->old_sk_destruct = sk->sk_destruct; 15296b9f3423SGuillaume Nault sk->sk_destruct = &l2tp_tunnel_destruct; 15306b9f3423SGuillaume Nault lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, 15316b9f3423SGuillaume Nault "l2tp_sock"); 15326b9f3423SGuillaume Nault sk->sk_allocation = GFP_ATOMIC; 15336b9f3423SGuillaume Nault 15346b9f3423SGuillaume Nault if (tunnel->fd >= 0) 15356b9f3423SGuillaume Nault sockfd_put(sock); 15366b9f3423SGuillaume Nault 15376b9f3423SGuillaume Nault return 0; 15386b9f3423SGuillaume Nault 15396b9f3423SGuillaume Nault err_sock: 1540f6cd651bSGuillaume Nault if (tunnel->fd < 0) 1541f6cd651bSGuillaume Nault sock_release(sock); 1542f6cd651bSGuillaume Nault else 15436b9f3423SGuillaume Nault sockfd_put(sock); 15446b9f3423SGuillaume Nault err: 15456b9f3423SGuillaume Nault return ret; 15466b9f3423SGuillaume Nault } 15476b9f3423SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_register); 15486b9f3423SGuillaume Nault 1549309795f4SJames Chapman /* This function is used by the netlink TUNNEL_DELETE command. 1550309795f4SJames Chapman */ 155162b982eeSSabrina Dubroca void l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) 1552309795f4SJames Chapman { 155362b982eeSSabrina Dubroca if (!test_and_set_bit(0, &tunnel->dead)) { 155406a15f51SAlexander Couzens l2tp_tunnel_inc_refcount(tunnel); 155562b982eeSSabrina Dubroca queue_work(l2tp_wq, &tunnel->del_work); 155606a15f51SAlexander Couzens } 1557309795f4SJames Chapman } 1558309795f4SJames Chapman EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); 1559309795f4SJames Chapman 1560fd558d18SJames Chapman /* Really kill the session. 1561fd558d18SJames Chapman */ 1562fd558d18SJames Chapman void l2tp_session_free(struct l2tp_session *session) 1563fd558d18SJames Chapman { 1564f6e16b29STom Parkin struct l2tp_tunnel *tunnel = session->tunnel; 1565fd558d18SJames Chapman 1566fbea9e07SReshetova, Elena BUG_ON(refcount_read(&session->ref_count) != 0); 1567fd558d18SJames Chapman 1568f6e16b29STom Parkin if (tunnel) { 1569fd558d18SJames Chapman BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); 1570fd558d18SJames Chapman l2tp_tunnel_dec_refcount(tunnel); 1571fd558d18SJames Chapman } 1572fd558d18SJames Chapman 1573fd558d18SJames Chapman kfree(session); 1574fd558d18SJames Chapman } 1575fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_session_free); 1576fd558d18SJames Chapman 1577f6e16b29STom Parkin /* Remove an l2tp session from l2tp_core's hash lists. 1578f6e16b29STom Parkin * Provides a tidyup interface for pseudowire code which can't just route all 1579f6e16b29STom Parkin * shutdown via. l2tp_session_delete and a pseudowire-specific session_close 1580f6e16b29STom Parkin * callback. 1581f6e16b29STom Parkin */ 1582f6e16b29STom Parkin void __l2tp_session_unhash(struct l2tp_session *session) 1583f6e16b29STom Parkin { 1584f6e16b29STom Parkin struct l2tp_tunnel *tunnel = session->tunnel; 1585f6e16b29STom Parkin 1586f6e16b29STom Parkin /* Remove the session from core hashes */ 1587f6e16b29STom Parkin if (tunnel) { 1588f6e16b29STom Parkin /* Remove from the per-tunnel hash */ 1589f6e16b29STom Parkin write_lock_bh(&tunnel->hlist_lock); 1590f6e16b29STom Parkin hlist_del_init(&session->hlist); 1591f6e16b29STom Parkin write_unlock_bh(&tunnel->hlist_lock); 1592f6e16b29STom Parkin 1593f6e16b29STom Parkin /* For L2TPv3 we have a per-net hash: remove from there, too */ 1594f6e16b29STom Parkin if (tunnel->version != L2TP_HDR_VER_2) { 1595f6e16b29STom Parkin struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); 1596f6e16b29STom Parkin spin_lock_bh(&pn->l2tp_session_hlist_lock); 1597f6e16b29STom Parkin hlist_del_init_rcu(&session->global_hlist); 1598f6e16b29STom Parkin spin_unlock_bh(&pn->l2tp_session_hlist_lock); 1599f6e16b29STom Parkin synchronize_rcu(); 1600f6e16b29STom Parkin } 1601f6e16b29STom Parkin } 1602f6e16b29STom Parkin } 1603f6e16b29STom Parkin EXPORT_SYMBOL_GPL(__l2tp_session_unhash); 1604f6e16b29STom Parkin 1605309795f4SJames Chapman /* This function is used by the netlink SESSION_DELETE command and by 1606309795f4SJames Chapman pseudowire modules. 1607309795f4SJames Chapman */ 1608309795f4SJames Chapman int l2tp_session_delete(struct l2tp_session *session) 1609309795f4SJames Chapman { 1610b228a940SGuillaume Nault if (test_and_set_bit(0, &session->dead)) 1611b228a940SGuillaume Nault return 0; 1612b228a940SGuillaume Nault 1613f6e16b29STom Parkin __l2tp_session_unhash(session); 16144c6e2fd3STom Parkin l2tp_session_queue_purge(session); 1615309795f4SJames Chapman if (session->session_close != NULL) 1616309795f4SJames Chapman (*session->session_close)(session); 1617a4346210SGuillaume Nault 1618309795f4SJames Chapman l2tp_session_dec_refcount(session); 1619a4346210SGuillaume Nault 1620309795f4SJames Chapman return 0; 1621309795f4SJames Chapman } 1622309795f4SJames Chapman EXPORT_SYMBOL_GPL(l2tp_session_delete); 1623309795f4SJames Chapman 1624f7faffa3SJames Chapman /* We come here whenever a session's send_seq, cookie_len or 162562e7b6a5SLorenzo Bianconi * l2specific_type parameters are set. 1626f7faffa3SJames Chapman */ 1627bb5016eaSGuillaume Nault void l2tp_session_set_header_len(struct l2tp_session *session, int version) 1628f7faffa3SJames Chapman { 1629f7faffa3SJames Chapman if (version == L2TP_HDR_VER_2) { 1630f7faffa3SJames Chapman session->hdr_len = 6; 1631f7faffa3SJames Chapman if (session->send_seq) 1632f7faffa3SJames Chapman session->hdr_len += 4; 1633f7faffa3SJames Chapman } else { 163462e7b6a5SLorenzo Bianconi session->hdr_len = 4 + session->cookie_len; 163562e7b6a5SLorenzo Bianconi session->hdr_len += l2tp_get_l2specific_len(session); 16360d76751fSJames Chapman if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP) 16370d76751fSJames Chapman session->hdr_len += 4; 1638f7faffa3SJames Chapman } 1639f7faffa3SJames Chapman 1640f7faffa3SJames Chapman } 1641bb5016eaSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); 1642f7faffa3SJames Chapman 1643fd558d18SJames Chapman struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) 1644fd558d18SJames Chapman { 1645fd558d18SJames Chapman struct l2tp_session *session; 1646fd558d18SJames Chapman 1647fd558d18SJames Chapman session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); 1648fd558d18SJames Chapman if (session != NULL) { 1649fd558d18SJames Chapman session->magic = L2TP_SESSION_MAGIC; 1650fd558d18SJames Chapman session->tunnel = tunnel; 1651fd558d18SJames Chapman 1652fd558d18SJames Chapman session->session_id = session_id; 1653fd558d18SJames Chapman session->peer_session_id = peer_session_id; 1654d301e325SJames Chapman session->nr = 0; 16558a1631d5SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) 16568a1631d5SJames Chapman session->nr_max = 0xffff; 16578a1631d5SJames Chapman else 16588a1631d5SJames Chapman session->nr_max = 0xffffff; 16598a1631d5SJames Chapman session->nr_window_size = session->nr_max / 2; 1660a0dbd822SJames Chapman session->nr_oos_count_max = 4; 1661a0dbd822SJames Chapman 1662a0dbd822SJames Chapman /* Use NR of first received packet */ 1663a0dbd822SJames Chapman session->reorder_skip = 1; 1664fd558d18SJames Chapman 1665fd558d18SJames Chapman sprintf(&session->name[0], "sess %u/%u", 1666fd558d18SJames Chapman tunnel->tunnel_id, session->session_id); 1667fd558d18SJames Chapman 1668fd558d18SJames Chapman skb_queue_head_init(&session->reorder_q); 1669fd558d18SJames Chapman 1670fd558d18SJames Chapman INIT_HLIST_NODE(&session->hlist); 1671f7faffa3SJames Chapman INIT_HLIST_NODE(&session->global_hlist); 1672fd558d18SJames Chapman 1673fd558d18SJames Chapman /* Inherit debug options from tunnel */ 1674fd558d18SJames Chapman session->debug = tunnel->debug; 1675fd558d18SJames Chapman 1676fd558d18SJames Chapman if (cfg) { 1677f7faffa3SJames Chapman session->pwtype = cfg->pw_type; 1678fd558d18SJames Chapman session->debug = cfg->debug; 1679fd558d18SJames Chapman session->send_seq = cfg->send_seq; 1680fd558d18SJames Chapman session->recv_seq = cfg->recv_seq; 1681fd558d18SJames Chapman session->lns_mode = cfg->lns_mode; 1682f7faffa3SJames Chapman session->reorder_timeout = cfg->reorder_timeout; 1683f7faffa3SJames Chapman session->l2specific_type = cfg->l2specific_type; 1684f7faffa3SJames Chapman session->cookie_len = cfg->cookie_len; 1685f7faffa3SJames Chapman memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len); 1686f7faffa3SJames Chapman session->peer_cookie_len = cfg->peer_cookie_len; 1687f7faffa3SJames Chapman memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len); 1688fd558d18SJames Chapman } 1689fd558d18SJames Chapman 1690f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) 1691f7faffa3SJames Chapman session->build_header = l2tp_build_l2tpv2_header; 1692f7faffa3SJames Chapman else 1693f7faffa3SJames Chapman session->build_header = l2tp_build_l2tpv3_header; 1694f7faffa3SJames Chapman 1695f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version); 1696f7faffa3SJames Chapman 16979ee369a4SGuillaume Nault refcount_set(&session->ref_count, 1); 16989ee369a4SGuillaume Nault 1699fd558d18SJames Chapman return session; 1700fd558d18SJames Chapman } 1701dbdbc73bSGuillaume Nault 1702dbdbc73bSGuillaume Nault return ERR_PTR(-ENOMEM); 1703dbdbc73bSGuillaume Nault } 1704fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_session_create); 1705fd558d18SJames Chapman 1706fd558d18SJames Chapman /***************************************************************************** 1707fd558d18SJames Chapman * Init and cleanup 1708fd558d18SJames Chapman *****************************************************************************/ 1709fd558d18SJames Chapman 1710fd558d18SJames Chapman static __net_init int l2tp_init_net(struct net *net) 1711fd558d18SJames Chapman { 1712e773aaffSJiri Pirko struct l2tp_net *pn = net_generic(net, l2tp_net_id); 1713f7faffa3SJames Chapman int hash; 1714fd558d18SJames Chapman 1715fd558d18SJames Chapman INIT_LIST_HEAD(&pn->l2tp_tunnel_list); 1716e02d494dSJames Chapman spin_lock_init(&pn->l2tp_tunnel_list_lock); 1717fd558d18SJames Chapman 1718f7faffa3SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 1719f7faffa3SJames Chapman INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); 1720f7faffa3SJames Chapman 1721e02d494dSJames Chapman spin_lock_init(&pn->l2tp_session_hlist_lock); 1722f7faffa3SJames Chapman 1723fd558d18SJames Chapman return 0; 1724fd558d18SJames Chapman } 1725fd558d18SJames Chapman 1726167eb17eSTom Parkin static __net_exit void l2tp_exit_net(struct net *net) 1727167eb17eSTom Parkin { 1728167eb17eSTom Parkin struct l2tp_net *pn = l2tp_pernet(net); 1729167eb17eSTom Parkin struct l2tp_tunnel *tunnel = NULL; 17301e7af3b2SVasily Averin int hash; 1731167eb17eSTom Parkin 1732167eb17eSTom Parkin rcu_read_lock_bh(); 1733167eb17eSTom Parkin list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { 17344dc12ffeSJiri Slaby l2tp_tunnel_delete(tunnel); 1735167eb17eSTom Parkin } 1736167eb17eSTom Parkin rcu_read_unlock_bh(); 17372f86953eSSabrina Dubroca 17382f86953eSSabrina Dubroca flush_workqueue(l2tp_wq); 17392f86953eSSabrina Dubroca rcu_barrier(); 17401e7af3b2SVasily Averin 17411e7af3b2SVasily Averin for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) 17421e7af3b2SVasily Averin WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash])); 1743167eb17eSTom Parkin } 1744167eb17eSTom Parkin 1745fd558d18SJames Chapman static struct pernet_operations l2tp_net_ops = { 1746fd558d18SJames Chapman .init = l2tp_init_net, 1747167eb17eSTom Parkin .exit = l2tp_exit_net, 1748fd558d18SJames Chapman .id = &l2tp_net_id, 1749fd558d18SJames Chapman .size = sizeof(struct l2tp_net), 1750fd558d18SJames Chapman }; 1751fd558d18SJames Chapman 1752fd558d18SJames Chapman static int __init l2tp_init(void) 1753fd558d18SJames Chapman { 1754fd558d18SJames Chapman int rc = 0; 1755fd558d18SJames Chapman 1756fd558d18SJames Chapman rc = register_pernet_device(&l2tp_net_ops); 1757fd558d18SJames Chapman if (rc) 1758fd558d18SJames Chapman goto out; 1759fd558d18SJames Chapman 176059ff3eb6SZhangZhen l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); 1761f8ccac0eSTom Parkin if (!l2tp_wq) { 1762f8ccac0eSTom Parkin pr_err("alloc_workqueue failed\n"); 176367e04c29SWANG Cong unregister_pernet_device(&l2tp_net_ops); 1764f8ccac0eSTom Parkin rc = -ENOMEM; 1765f8ccac0eSTom Parkin goto out; 1766f8ccac0eSTom Parkin } 1767f8ccac0eSTom Parkin 1768a4ca44faSJoe Perches pr_info("L2TP core driver, %s\n", L2TP_DRV_VERSION); 1769fd558d18SJames Chapman 1770fd558d18SJames Chapman out: 1771fd558d18SJames Chapman return rc; 1772fd558d18SJames Chapman } 1773fd558d18SJames Chapman 1774fd558d18SJames Chapman static void __exit l2tp_exit(void) 1775fd558d18SJames Chapman { 1776fd558d18SJames Chapman unregister_pernet_device(&l2tp_net_ops); 1777f8ccac0eSTom Parkin if (l2tp_wq) { 1778f8ccac0eSTom Parkin destroy_workqueue(l2tp_wq); 1779f8ccac0eSTom Parkin l2tp_wq = NULL; 1780f8ccac0eSTom Parkin } 1781fd558d18SJames Chapman } 1782fd558d18SJames Chapman 1783fd558d18SJames Chapman module_init(l2tp_init); 1784fd558d18SJames Chapman module_exit(l2tp_exit); 1785fd558d18SJames Chapman 1786fd558d18SJames Chapman MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 1787fd558d18SJames Chapman MODULE_DESCRIPTION("L2TP core"); 1788fd558d18SJames Chapman MODULE_LICENSE("GPL"); 1789fd558d18SJames Chapman MODULE_VERSION(L2TP_DRV_VERSION); 1790