1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
220dcb110STom Parkin /* 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
17a4ca44faSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18a4ca44faSJoe Perches
19fd558d18SJames Chapman #include <linux/module.h>
20fd558d18SJames Chapman #include <linux/string.h>
21fd558d18SJames Chapman #include <linux/list.h>
22e02d494dSJames Chapman #include <linux/rculist.h>
23fd558d18SJames Chapman #include <linux/uaccess.h>
24fd558d18SJames Chapman
25fd558d18SJames Chapman #include <linux/kernel.h>
26fd558d18SJames Chapman #include <linux/spinlock.h>
27fd558d18SJames Chapman #include <linux/kthread.h>
28fd558d18SJames Chapman #include <linux/sched.h>
29fd558d18SJames Chapman #include <linux/slab.h>
30fd558d18SJames Chapman #include <linux/errno.h>
31fd558d18SJames Chapman #include <linux/jiffies.h>
32fd558d18SJames Chapman
33fd558d18SJames Chapman #include <linux/netdevice.h>
34fd558d18SJames Chapman #include <linux/net.h>
35fd558d18SJames Chapman #include <linux/inetdevice.h>
36fd558d18SJames Chapman #include <linux/skbuff.h>
37fd558d18SJames Chapman #include <linux/init.h>
380d76751fSJames Chapman #include <linux/in.h>
39fd558d18SJames Chapman #include <linux/ip.h>
40fd558d18SJames Chapman #include <linux/udp.h>
410d76751fSJames Chapman #include <linux/l2tp.h>
42fd558d18SJames Chapman #include <linux/hash.h>
43fd558d18SJames Chapman #include <linux/sort.h>
44fd558d18SJames Chapman #include <linux/file.h>
45fd558d18SJames Chapman #include <linux/nsproxy.h>
46fd558d18SJames Chapman #include <net/net_namespace.h>
47fd558d18SJames Chapman #include <net/netns/generic.h>
48fd558d18SJames Chapman #include <net/dst.h>
49fd558d18SJames Chapman #include <net/ip.h>
50fd558d18SJames Chapman #include <net/udp.h>
5185644b4dSTom Herbert #include <net/udp_tunnel.h>
52309795f4SJames Chapman #include <net/inet_common.h>
53fd558d18SJames Chapman #include <net/xfrm.h>
540d76751fSJames Chapman #include <net/protocol.h>
55d2cf3361SBenjamin LaHaise #include <net/inet6_connection_sock.h>
56d2cf3361SBenjamin LaHaise #include <net/inet_ecn.h>
57d2cf3361SBenjamin LaHaise #include <net/ip6_route.h>
58d499bd2eSDavid S. Miller #include <net/ip6_checksum.h>
59fd558d18SJames Chapman
60fd558d18SJames Chapman #include <asm/byteorder.h>
6160063497SArun Sharma #include <linux/atomic.h>
62fd558d18SJames Chapman
63fd558d18SJames Chapman #include "l2tp_core.h"
646b7bdcd7STom Parkin #include "trace.h"
65fd558d18SJames Chapman
663f117d6fSTom Parkin #define CREATE_TRACE_POINTS
673f117d6fSTom Parkin #include "trace.h"
683f117d6fSTom Parkin
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
100efcd8c85STom Parkin #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 {
107c4d48a58SCong Wang /* Lock for write access to l2tp_tunnel_idr */
108c4d48a58SCong Wang spinlock_t l2tp_tunnel_idr_lock;
109c4d48a58SCong Wang struct idr l2tp_tunnel_idr;
110f7faffa3SJames Chapman struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
11120dcb110STom Parkin /* Lock for write access to l2tp_session_hlist */
112e02d494dSJames Chapman spinlock_t l2tp_session_hlist_lock;
113fd558d18SJames Chapman };
114fd558d18SJames Chapman
115b954f940SPaolo Abeni #if IS_ENABLED(CONFIG_IPV6)
l2tp_sk_is_v6(struct sock * sk)116b954f940SPaolo Abeni static bool l2tp_sk_is_v6(struct sock *sk)
117b954f940SPaolo Abeni {
118b954f940SPaolo Abeni return sk->sk_family == PF_INET6 &&
119b954f940SPaolo Abeni !ipv6_addr_v4mapped(&sk->sk_v6_daddr);
120b954f940SPaolo Abeni }
121b954f940SPaolo Abeni #endif
122fc130840Sstephen hemminger
l2tp_pernet(const struct net * net)1239aaef50cSGuillaume Nault static inline struct l2tp_net *l2tp_pernet(const struct net *net)
124fd558d18SJames Chapman {
125fd558d18SJames Chapman return net_generic(net, l2tp_net_id);
126fd558d18SJames Chapman }
127fd558d18SJames Chapman
128f7faffa3SJames Chapman /* Session hash global list for L2TPv3.
129f7faffa3SJames Chapman * The session_id SHOULD be random according to RFC3931, but several
130f7faffa3SJames Chapman * L2TP implementations use incrementing session_ids. So we do a real
131f7faffa3SJames Chapman * hash on the session_id, rather than a simple bitmask.
132f7faffa3SJames Chapman */
133f7faffa3SJames Chapman static inline struct hlist_head *
l2tp_session_id_hash_2(struct l2tp_net * pn,u32 session_id)134f7faffa3SJames Chapman l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
135f7faffa3SJames Chapman {
136f7faffa3SJames Chapman return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)];
137f7faffa3SJames Chapman }
138f7faffa3SJames Chapman
139fd558d18SJames Chapman /* Session hash list.
140fd558d18SJames Chapman * The session_id SHOULD be random according to RFC2661, but several
141fd558d18SJames Chapman * L2TP implementations (Cisco and Microsoft) use incrementing
142fd558d18SJames Chapman * session_ids. So we do a real hash on the session_id, rather than a
143fd558d18SJames Chapman * simple bitmask.
144fd558d18SJames Chapman */
145fd558d18SJames Chapman static inline struct hlist_head *
l2tp_session_id_hash(struct l2tp_tunnel * tunnel,u32 session_id)146fd558d18SJames Chapman l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
147fd558d18SJames Chapman {
148fd558d18SJames Chapman return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
149fd558d18SJames Chapman }
150fd558d18SJames Chapman
l2tp_tunnel_free(struct l2tp_tunnel * tunnel)15152016e25STom Parkin static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
152d00fa9adSJames Chapman {
1536b7bdcd7STom Parkin trace_free_tunnel(tunnel);
154d00fa9adSJames Chapman sock_put(tunnel->sock);
155d00fa9adSJames Chapman /* the tunnel is freed in the socket destructor */
156d00fa9adSJames Chapman }
15752016e25STom Parkin
l2tp_session_free(struct l2tp_session * session)15852016e25STom Parkin static void l2tp_session_free(struct l2tp_session *session)
15952016e25STom Parkin {
1606b7bdcd7STom Parkin trace_free_session(session);
16145faeff1STom Parkin if (session->tunnel)
16245faeff1STom Parkin l2tp_tunnel_dec_refcount(session->tunnel);
16352016e25STom Parkin kfree(session);
16452016e25STom Parkin }
16552016e25STom Parkin
l2tp_sk_to_tunnel(struct sock * sk)16645faeff1STom Parkin struct l2tp_tunnel *l2tp_sk_to_tunnel(struct sock *sk)
16745faeff1STom Parkin {
16845faeff1STom Parkin struct l2tp_tunnel *tunnel = sk->sk_user_data;
16945faeff1STom Parkin
17045faeff1STom Parkin if (tunnel)
17145faeff1STom Parkin if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC))
17245faeff1STom Parkin return NULL;
17345faeff1STom Parkin
17445faeff1STom Parkin return tunnel;
17545faeff1STom Parkin }
17645faeff1STom Parkin EXPORT_SYMBOL_GPL(l2tp_sk_to_tunnel);
17745faeff1STom Parkin
l2tp_tunnel_inc_refcount(struct l2tp_tunnel * tunnel)17852016e25STom Parkin void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
17952016e25STom Parkin {
18052016e25STom Parkin refcount_inc(&tunnel->ref_count);
18152016e25STom Parkin }
18252016e25STom Parkin EXPORT_SYMBOL_GPL(l2tp_tunnel_inc_refcount);
18352016e25STom Parkin
l2tp_tunnel_dec_refcount(struct l2tp_tunnel * tunnel)18452016e25STom Parkin void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel)
18552016e25STom Parkin {
18652016e25STom Parkin if (refcount_dec_and_test(&tunnel->ref_count))
18752016e25STom Parkin l2tp_tunnel_free(tunnel);
18852016e25STom Parkin }
18952016e25STom Parkin EXPORT_SYMBOL_GPL(l2tp_tunnel_dec_refcount);
19052016e25STom Parkin
l2tp_session_inc_refcount(struct l2tp_session * session)19152016e25STom Parkin void l2tp_session_inc_refcount(struct l2tp_session *session)
19252016e25STom Parkin {
19352016e25STom Parkin refcount_inc(&session->ref_count);
19452016e25STom Parkin }
19552016e25STom Parkin EXPORT_SYMBOL_GPL(l2tp_session_inc_refcount);
19652016e25STom Parkin
l2tp_session_dec_refcount(struct l2tp_session * session)19752016e25STom Parkin void l2tp_session_dec_refcount(struct l2tp_session *session)
19852016e25STom Parkin {
19952016e25STom Parkin if (refcount_dec_and_test(&session->ref_count))
20052016e25STom Parkin l2tp_session_free(session);
20152016e25STom Parkin }
20252016e25STom Parkin EXPORT_SYMBOL_GPL(l2tp_session_dec_refcount);
203d00fa9adSJames Chapman
20454652eb1SGuillaume Nault /* Lookup a tunnel. A new reference is held on the returned tunnel. */
l2tp_tunnel_get(const struct net * net,u32 tunnel_id)20554652eb1SGuillaume Nault struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
20654652eb1SGuillaume Nault {
20754652eb1SGuillaume Nault const struct l2tp_net *pn = l2tp_pernet(net);
20854652eb1SGuillaume Nault struct l2tp_tunnel *tunnel;
20954652eb1SGuillaume Nault
21054652eb1SGuillaume Nault rcu_read_lock_bh();
211c4d48a58SCong Wang tunnel = idr_find(&pn->l2tp_tunnel_idr, tunnel_id);
212c4d48a58SCong Wang if (tunnel && refcount_inc_not_zero(&tunnel->ref_count)) {
21354652eb1SGuillaume Nault rcu_read_unlock_bh();
21454652eb1SGuillaume Nault return tunnel;
21554652eb1SGuillaume Nault }
21654652eb1SGuillaume Nault rcu_read_unlock_bh();
21754652eb1SGuillaume Nault
21854652eb1SGuillaume Nault return NULL;
21954652eb1SGuillaume Nault }
22054652eb1SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
22154652eb1SGuillaume Nault
l2tp_tunnel_get_nth(const struct net * net,int nth)2225846c131SGuillaume Nault struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
2235846c131SGuillaume Nault {
224c4d48a58SCong Wang struct l2tp_net *pn = l2tp_pernet(net);
225c4d48a58SCong Wang unsigned long tunnel_id, tmp;
2265846c131SGuillaume Nault struct l2tp_tunnel *tunnel;
2275846c131SGuillaume Nault int count = 0;
2285846c131SGuillaume Nault
2295846c131SGuillaume Nault rcu_read_lock_bh();
230c4d48a58SCong Wang idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
231c4d48a58SCong Wang if (tunnel && ++count > nth &&
232a622b400SEric Dumazet refcount_inc_not_zero(&tunnel->ref_count)) {
2335846c131SGuillaume Nault rcu_read_unlock_bh();
2345846c131SGuillaume Nault return tunnel;
2355846c131SGuillaume Nault }
2365846c131SGuillaume Nault }
2375846c131SGuillaume Nault rcu_read_unlock_bh();
2385846c131SGuillaume Nault
2395846c131SGuillaume Nault return NULL;
2405846c131SGuillaume Nault }
2415846c131SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth);
2425846c131SGuillaume Nault
l2tp_tunnel_get_session(struct l2tp_tunnel * tunnel,u32 session_id)24301e28b92SGuillaume Nault struct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel,
244a4346210SGuillaume Nault u32 session_id)
24561b9a047SGuillaume Nault {
24661b9a047SGuillaume Nault struct hlist_head *session_list;
24761b9a047SGuillaume Nault struct l2tp_session *session;
24861b9a047SGuillaume Nault
24901e28b92SGuillaume Nault session_list = l2tp_session_id_hash(tunnel, session_id);
25061b9a047SGuillaume Nault
25107b8ca37STom Parkin rcu_read_lock_bh();
25207b8ca37STom Parkin hlist_for_each_entry_rcu(session, session_list, hlist)
25361b9a047SGuillaume Nault if (session->session_id == session_id) {
25461b9a047SGuillaume Nault l2tp_session_inc_refcount(session);
25507b8ca37STom Parkin rcu_read_unlock_bh();
25661b9a047SGuillaume Nault
25761b9a047SGuillaume Nault return session;
25861b9a047SGuillaume Nault }
25907b8ca37STom Parkin rcu_read_unlock_bh();
26061b9a047SGuillaume Nault
26161b9a047SGuillaume Nault return NULL;
26261b9a047SGuillaume Nault }
26301e28b92SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_get_session);
26461b9a047SGuillaume Nault
l2tp_session_get(const struct net * net,u32 session_id)26501e28b92SGuillaume Nault struct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id)
26601e28b92SGuillaume Nault {
26701e28b92SGuillaume Nault struct hlist_head *session_list;
26801e28b92SGuillaume Nault struct l2tp_session *session;
26901e28b92SGuillaume Nault
27001e28b92SGuillaume Nault session_list = l2tp_session_id_hash_2(l2tp_pernet(net), session_id);
27101e28b92SGuillaume Nault
27201e28b92SGuillaume Nault rcu_read_lock_bh();
27301e28b92SGuillaume Nault hlist_for_each_entry_rcu(session, session_list, global_hlist)
27461b9a047SGuillaume Nault if (session->session_id == session_id) {
27561b9a047SGuillaume Nault l2tp_session_inc_refcount(session);
27601e28b92SGuillaume Nault rcu_read_unlock_bh();
27761b9a047SGuillaume Nault
27861b9a047SGuillaume Nault return session;
27961b9a047SGuillaume Nault }
28001e28b92SGuillaume Nault rcu_read_unlock_bh();
28161b9a047SGuillaume Nault
28261b9a047SGuillaume Nault return NULL;
28361b9a047SGuillaume Nault }
28461b9a047SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get);
28561b9a047SGuillaume Nault
l2tp_session_get_nth(struct l2tp_tunnel * tunnel,int nth)286a4346210SGuillaume Nault struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth)
287fd558d18SJames Chapman {
288fd558d18SJames Chapman int hash;
289fd558d18SJames Chapman struct l2tp_session *session;
290fd558d18SJames Chapman int count = 0;
291fd558d18SJames Chapman
29207b8ca37STom Parkin rcu_read_lock_bh();
293fd558d18SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
29407b8ca37STom Parkin hlist_for_each_entry_rcu(session, &tunnel->session_hlist[hash], hlist) {
295fd558d18SJames Chapman if (++count > nth) {
296e08293a4SGuillaume Nault l2tp_session_inc_refcount(session);
29707b8ca37STom Parkin rcu_read_unlock_bh();
298fd558d18SJames Chapman return session;
299fd558d18SJames Chapman }
300fd558d18SJames Chapman }
301fd558d18SJames Chapman }
302fd558d18SJames Chapman
30307b8ca37STom Parkin rcu_read_unlock_bh();
304fd558d18SJames Chapman
305fd558d18SJames Chapman return NULL;
306fd558d18SJames Chapman }
307e08293a4SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
308fd558d18SJames Chapman
309309795f4SJames Chapman /* Lookup a session by interface name.
310309795f4SJames Chapman * This is very inefficient but is only used by management interfaces.
311309795f4SJames Chapman */
l2tp_session_get_by_ifname(const struct net * net,const char * ifname)3129aaef50cSGuillaume Nault struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
313a4346210SGuillaume Nault const char *ifname)
314309795f4SJames Chapman {
315309795f4SJames Chapman struct l2tp_net *pn = l2tp_pernet(net);
316309795f4SJames Chapman int hash;
317309795f4SJames Chapman struct l2tp_session *session;
318309795f4SJames Chapman
319e02d494dSJames Chapman rcu_read_lock_bh();
320309795f4SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) {
321b67bfe0dSSasha Levin hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) {
322309795f4SJames Chapman if (!strcmp(session->ifname, ifname)) {
3232777e2abSGuillaume Nault l2tp_session_inc_refcount(session);
324e02d494dSJames Chapman rcu_read_unlock_bh();
3252777e2abSGuillaume Nault
326309795f4SJames Chapman return session;
327309795f4SJames Chapman }
328309795f4SJames Chapman }
329309795f4SJames Chapman }
330309795f4SJames Chapman
331e02d494dSJames Chapman rcu_read_unlock_bh();
332309795f4SJames Chapman
333309795f4SJames Chapman return NULL;
334309795f4SJames Chapman }
3352777e2abSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname);
336309795f4SJames Chapman
l2tp_session_register(struct l2tp_session * session,struct l2tp_tunnel * tunnel)3373953ae7bSGuillaume Nault int l2tp_session_register(struct l2tp_session *session,
3383953ae7bSGuillaume Nault struct l2tp_tunnel *tunnel)
339dbdbc73bSGuillaume Nault {
340dbdbc73bSGuillaume Nault struct l2tp_session *session_walk;
341dbdbc73bSGuillaume Nault struct hlist_head *g_head;
342dbdbc73bSGuillaume Nault struct hlist_head *head;
343dbdbc73bSGuillaume Nault struct l2tp_net *pn;
344f3c66d4eSGuillaume Nault int err;
345dbdbc73bSGuillaume Nault
346dbdbc73bSGuillaume Nault head = l2tp_session_id_hash(tunnel, session->session_id);
347dbdbc73bSGuillaume Nault
34807b8ca37STom Parkin spin_lock_bh(&tunnel->hlist_lock);
349f3c66d4eSGuillaume Nault if (!tunnel->acpt_newsess) {
350f3c66d4eSGuillaume Nault err = -ENODEV;
351f3c66d4eSGuillaume Nault goto err_tlock;
352f3c66d4eSGuillaume Nault }
353f3c66d4eSGuillaume Nault
354dbdbc73bSGuillaume Nault hlist_for_each_entry(session_walk, head, hlist)
355f3c66d4eSGuillaume Nault if (session_walk->session_id == session->session_id) {
356f3c66d4eSGuillaume Nault err = -EEXIST;
357f3c66d4eSGuillaume Nault goto err_tlock;
358f3c66d4eSGuillaume Nault }
359dbdbc73bSGuillaume Nault
360dbdbc73bSGuillaume Nault if (tunnel->version == L2TP_HDR_VER_3) {
361dbdbc73bSGuillaume Nault pn = l2tp_pernet(tunnel->l2tp_net);
362363a341dSGuillaume Nault g_head = l2tp_session_id_hash_2(pn, session->session_id);
363dbdbc73bSGuillaume Nault
364dbdbc73bSGuillaume Nault spin_lock_bh(&pn->l2tp_session_hlist_lock);
365dbdbc73bSGuillaume Nault
3660d0d9a38SRidge Kennedy /* IP encap expects session IDs to be globally unique, while
3670d0d9a38SRidge Kennedy * UDP encap doesn't.
3680d0d9a38SRidge Kennedy */
369f3c66d4eSGuillaume Nault hlist_for_each_entry(session_walk, g_head, global_hlist)
3700d0d9a38SRidge Kennedy if (session_walk->session_id == session->session_id &&
3710d0d9a38SRidge Kennedy (session_walk->tunnel->encap == L2TP_ENCAPTYPE_IP ||
3720d0d9a38SRidge Kennedy tunnel->encap == L2TP_ENCAPTYPE_IP)) {
373f3c66d4eSGuillaume Nault err = -EEXIST;
374f3c66d4eSGuillaume Nault goto err_tlock_pnlock;
375f3c66d4eSGuillaume Nault }
376f3c66d4eSGuillaume Nault
377f3c66d4eSGuillaume Nault l2tp_tunnel_inc_refcount(tunnel);
378dbdbc73bSGuillaume Nault hlist_add_head_rcu(&session->global_hlist, g_head);
379f3c66d4eSGuillaume Nault
380dbdbc73bSGuillaume Nault spin_unlock_bh(&pn->l2tp_session_hlist_lock);
381f3c66d4eSGuillaume Nault } else {
382f3c66d4eSGuillaume Nault l2tp_tunnel_inc_refcount(tunnel);
383dbdbc73bSGuillaume Nault }
384dbdbc73bSGuillaume Nault
38507b8ca37STom Parkin hlist_add_head_rcu(&session->hlist, head);
38607b8ca37STom Parkin spin_unlock_bh(&tunnel->hlist_lock);
387dbdbc73bSGuillaume Nault
3886b7bdcd7STom Parkin trace_register_session(session);
3896b7bdcd7STom Parkin
390dbdbc73bSGuillaume Nault return 0;
391dbdbc73bSGuillaume Nault
392f3c66d4eSGuillaume Nault err_tlock_pnlock:
393dbdbc73bSGuillaume Nault spin_unlock_bh(&pn->l2tp_session_hlist_lock);
394f3c66d4eSGuillaume Nault err_tlock:
39507b8ca37STom Parkin spin_unlock_bh(&tunnel->hlist_lock);
396dbdbc73bSGuillaume Nault
397f3c66d4eSGuillaume Nault return err;
398dbdbc73bSGuillaume Nault }
3993953ae7bSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_register);
400dbdbc73bSGuillaume Nault
401fd558d18SJames Chapman /*****************************************************************************
402fd558d18SJames Chapman * Receive data handling
403fd558d18SJames Chapman *****************************************************************************/
404fd558d18SJames Chapman
405fd558d18SJames Chapman /* Queue a skb in order. We come here only if the skb has an L2TP sequence
406fd558d18SJames Chapman * number.
407fd558d18SJames Chapman */
l2tp_recv_queue_skb(struct l2tp_session * session,struct sk_buff * skb)408fd558d18SJames Chapman static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *skb)
409fd558d18SJames Chapman {
410fd558d18SJames Chapman struct sk_buff *skbp;
411fd558d18SJames Chapman struct sk_buff *tmp;
412f7faffa3SJames Chapman u32 ns = L2TP_SKB_CB(skb)->ns;
413fd558d18SJames Chapman
414fd558d18SJames Chapman spin_lock_bh(&session->reorder_q.lock);
415fd558d18SJames Chapman skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
416fd558d18SJames Chapman if (L2TP_SKB_CB(skbp)->ns > ns) {
417fd558d18SJames Chapman __skb_queue_before(&session->reorder_q, skbp, skb);
4187b7c0719STom Parkin atomic_long_inc(&session->stats.rx_oos_packets);
419fd558d18SJames Chapman goto out;
420fd558d18SJames Chapman }
421fd558d18SJames Chapman }
422fd558d18SJames Chapman
423fd558d18SJames Chapman __skb_queue_tail(&session->reorder_q, skb);
424fd558d18SJames Chapman
425fd558d18SJames Chapman out:
426fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock);
427fd558d18SJames Chapman }
428fd558d18SJames Chapman
429fd558d18SJames Chapman /* Dequeue a single skb.
430fd558d18SJames Chapman */
l2tp_recv_dequeue_skb(struct l2tp_session * session,struct sk_buff * skb)431fd558d18SJames Chapman static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *skb)
432fd558d18SJames Chapman {
433fd558d18SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel;
434fd558d18SJames Chapman int length = L2TP_SKB_CB(skb)->length;
435fd558d18SJames Chapman
436fd558d18SJames Chapman /* We're about to requeue the skb, so return resources
437fd558d18SJames Chapman * to its current owner (a socket receive buffer).
438fd558d18SJames Chapman */
439fd558d18SJames Chapman skb_orphan(skb);
440fd558d18SJames Chapman
4417b7c0719STom Parkin atomic_long_inc(&tunnel->stats.rx_packets);
4427b7c0719STom Parkin atomic_long_add(length, &tunnel->stats.rx_bytes);
4437b7c0719STom Parkin atomic_long_inc(&session->stats.rx_packets);
4447b7c0719STom Parkin atomic_long_add(length, &session->stats.rx_bytes);
445fd558d18SJames Chapman
446fd558d18SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) {
447fd558d18SJames Chapman /* Bump our Nr */
448fd558d18SJames Chapman session->nr++;
4498a1631d5SJames Chapman session->nr &= session->nr_max;
4506b7bdcd7STom Parkin trace_session_seqnum_update(session);
451fd558d18SJames Chapman }
452fd558d18SJames Chapman
453fd558d18SJames Chapman /* call private receive handler */
4540febc7b3STom Parkin if (session->recv_skb)
455fd558d18SJames Chapman (*session->recv_skb)(session, skb, L2TP_SKB_CB(skb)->length);
456fd558d18SJames Chapman else
457fd558d18SJames Chapman kfree_skb(skb);
458fd558d18SJames Chapman }
459fd558d18SJames Chapman
460fd558d18SJames Chapman /* Dequeue skbs from the session's reorder_q, subject to packet order.
461fd558d18SJames Chapman * Skbs that have been in the queue for too long are simply discarded.
462fd558d18SJames Chapman */
l2tp_recv_dequeue(struct l2tp_session * session)463fd558d18SJames Chapman static void l2tp_recv_dequeue(struct l2tp_session *session)
464fd558d18SJames Chapman {
465fd558d18SJames Chapman struct sk_buff *skb;
466fd558d18SJames Chapman struct sk_buff *tmp;
467fd558d18SJames Chapman
468fd558d18SJames Chapman /* If the pkt at the head of the queue has the nr that we
469fd558d18SJames Chapman * expect to send up next, dequeue it and any other
470fd558d18SJames Chapman * in-sequence packets behind it.
471fd558d18SJames Chapman */
472e2e210c0SEric Dumazet start:
473fd558d18SJames Chapman spin_lock_bh(&session->reorder_q.lock);
474fd558d18SJames Chapman skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
4756b7bdcd7STom Parkin struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb);
4766b7bdcd7STom Parkin
4776b7bdcd7STom Parkin /* If the packet has been pending on the queue for too long, discard it */
4786b7bdcd7STom Parkin if (time_after(jiffies, cb->expires)) {
4797b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards);
4807b7c0719STom Parkin atomic_long_inc(&session->stats.rx_errors);
4816b7bdcd7STom Parkin trace_session_pkt_expired(session, cb->ns);
48238d40b3fSJames Chapman session->reorder_skip = 1;
483fd558d18SJames Chapman __skb_unlink(skb, &session->reorder_q);
484fd558d18SJames Chapman kfree_skb(skb);
485fd558d18SJames Chapman continue;
486fd558d18SJames Chapman }
487fd558d18SJames Chapman
4886b7bdcd7STom Parkin if (cb->has_seq) {
48938d40b3fSJames Chapman if (session->reorder_skip) {
49038d40b3fSJames Chapman session->reorder_skip = 0;
4916b7bdcd7STom Parkin session->nr = cb->ns;
4926b7bdcd7STom Parkin trace_session_seqnum_reset(session);
49338d40b3fSJames Chapman }
4946b7bdcd7STom Parkin if (cb->ns != session->nr)
495fd558d18SJames Chapman goto out;
496fd558d18SJames Chapman }
497fd558d18SJames Chapman __skb_unlink(skb, &session->reorder_q);
498fd558d18SJames Chapman
499fd558d18SJames Chapman /* Process the skb. We release the queue lock while we
500fd558d18SJames Chapman * do so to let other contexts process the queue.
501fd558d18SJames Chapman */
502fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock);
503fd558d18SJames Chapman l2tp_recv_dequeue_skb(session, skb);
504e2e210c0SEric Dumazet goto start;
505fd558d18SJames Chapman }
506fd558d18SJames Chapman
507fd558d18SJames Chapman out:
508fd558d18SJames Chapman spin_unlock_bh(&session->reorder_q.lock);
509fd558d18SJames Chapman }
510fd558d18SJames Chapman
l2tp_seq_check_rx_window(struct l2tp_session * session,u32 nr)5118a1631d5SJames Chapman static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr)
5128a1631d5SJames Chapman {
5138a1631d5SJames Chapman u32 nws;
5148a1631d5SJames Chapman
5158a1631d5SJames Chapman if (nr >= session->nr)
5168a1631d5SJames Chapman nws = nr - session->nr;
5178a1631d5SJames Chapman else
5188a1631d5SJames Chapman nws = (session->nr_max + 1) - (session->nr - nr);
5198a1631d5SJames Chapman
5208a1631d5SJames Chapman return nws < session->nr_window_size;
5218a1631d5SJames Chapman }
5228a1631d5SJames Chapman
523b6dc01a4SJames Chapman /* If packet has sequence numbers, queue it if acceptable. Returns 0 if
524b6dc01a4SJames Chapman * acceptable, else non-zero.
525b6dc01a4SJames Chapman */
l2tp_recv_data_seq(struct l2tp_session * session,struct sk_buff * skb)526b6dc01a4SJames Chapman static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb)
527b6dc01a4SJames Chapman {
5286b7bdcd7STom Parkin struct l2tp_skb_cb *cb = L2TP_SKB_CB(skb);
5296b7bdcd7STom Parkin
5306b7bdcd7STom Parkin if (!l2tp_seq_check_rx_window(session, cb->ns)) {
5318a1631d5SJames Chapman /* Packet sequence number is outside allowed window.
5328a1631d5SJames Chapman * Discard it.
5338a1631d5SJames Chapman */
5346b7bdcd7STom Parkin trace_session_pkt_outside_rx_window(session, cb->ns);
5358a1631d5SJames Chapman goto discard;
5368a1631d5SJames Chapman }
5378a1631d5SJames Chapman
538b6dc01a4SJames Chapman if (session->reorder_timeout != 0) {
539b6dc01a4SJames Chapman /* Packet reordering enabled. Add skb to session's
540b6dc01a4SJames Chapman * reorder queue, in order of ns.
541b6dc01a4SJames Chapman */
542b6dc01a4SJames Chapman l2tp_recv_queue_skb(session, skb);
543a0dbd822SJames Chapman goto out;
544a0dbd822SJames Chapman }
545a0dbd822SJames Chapman
546a0dbd822SJames Chapman /* Packet reordering disabled. Discard out-of-sequence packets, while
547a0dbd822SJames Chapman * tracking the number if in-sequence packets after the first OOS packet
548a0dbd822SJames Chapman * is seen. After nr_oos_count_max in-sequence packets, reset the
549a0dbd822SJames Chapman * sequence number to re-enable packet reception.
550b6dc01a4SJames Chapman */
5516b7bdcd7STom Parkin if (cb->ns == session->nr) {
552a0dbd822SJames Chapman skb_queue_tail(&session->reorder_q, skb);
553a0dbd822SJames Chapman } else {
5546b7bdcd7STom Parkin u32 nr_oos = cb->ns;
555a0dbd822SJames Chapman u32 nr_next = (session->nr_oos + 1) & session->nr_max;
556a0dbd822SJames Chapman
557a0dbd822SJames Chapman if (nr_oos == nr_next)
558a0dbd822SJames Chapman session->nr_oos_count++;
559a0dbd822SJames Chapman else
560a0dbd822SJames Chapman session->nr_oos_count = 0;
561a0dbd822SJames Chapman
562a0dbd822SJames Chapman session->nr_oos = nr_oos;
563a0dbd822SJames Chapman if (session->nr_oos_count > session->nr_oos_count_max) {
564a0dbd822SJames Chapman session->reorder_skip = 1;
565a0dbd822SJames Chapman }
566a0dbd822SJames Chapman if (!session->reorder_skip) {
567b6dc01a4SJames Chapman atomic_long_inc(&session->stats.rx_seq_discards);
5686b7bdcd7STom Parkin trace_session_pkt_oos(session, cb->ns);
569b6dc01a4SJames Chapman goto discard;
570b6dc01a4SJames Chapman }
571b6dc01a4SJames Chapman skb_queue_tail(&session->reorder_q, skb);
572b6dc01a4SJames Chapman }
573b6dc01a4SJames Chapman
574a0dbd822SJames Chapman out:
575b6dc01a4SJames Chapman return 0;
576b6dc01a4SJames Chapman
577b6dc01a4SJames Chapman discard:
578b6dc01a4SJames Chapman return 1;
579b6dc01a4SJames Chapman }
580b6dc01a4SJames Chapman
581f7faffa3SJames Chapman /* Do receive processing of L2TP data frames. We handle both L2TPv2
582f7faffa3SJames Chapman * and L2TPv3 data frames here.
583f7faffa3SJames Chapman *
584f7faffa3SJames Chapman * L2TPv2 Data Message Header
585f7faffa3SJames Chapman *
586f7faffa3SJames Chapman * 0 1 2 3
587f7faffa3SJames 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
588f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589f7faffa3SJames Chapman * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) |
590f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591f7faffa3SJames Chapman * | Tunnel ID | Session ID |
592f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
593f7faffa3SJames Chapman * | Ns (opt) | Nr (opt) |
594f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595f7faffa3SJames Chapman * | Offset Size (opt) | Offset pad... (opt)
596f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
597f7faffa3SJames Chapman *
598f7faffa3SJames Chapman * Data frames are marked by T=0. All other fields are the same as
599f7faffa3SJames Chapman * those in L2TP control frames.
600f7faffa3SJames Chapman *
601f7faffa3SJames Chapman * L2TPv3 Data Message Header
602f7faffa3SJames Chapman *
603f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
604f7faffa3SJames Chapman * | L2TP Session Header |
605f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
606f7faffa3SJames Chapman * | L2-Specific Sublayer |
607f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
608f7faffa3SJames Chapman * | Tunnel Payload ...
609f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610f7faffa3SJames Chapman *
611f7faffa3SJames Chapman * L2TPv3 Session Header Over IP
612f7faffa3SJames Chapman *
613f7faffa3SJames Chapman * 0 1 2 3
614f7faffa3SJames 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
615f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
616f7faffa3SJames Chapman * | Session ID |
617f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
618f7faffa3SJames Chapman * | Cookie (optional, maximum 64 bits)...
619f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
620f7faffa3SJames Chapman * |
621f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
622f7faffa3SJames Chapman *
623f7faffa3SJames Chapman * L2TPv3 L2-Specific Sublayer Format
624f7faffa3SJames Chapman *
625f7faffa3SJames Chapman * 0 1 2 3
626f7faffa3SJames 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
627f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
628f7faffa3SJames Chapman * |x|S|x|x|x|x|x|x| Sequence Number |
629f7faffa3SJames Chapman * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
630f7faffa3SJames Chapman *
63123fe846fSGuillaume Nault * Cookie value and sublayer format are negotiated with the peer when
63223fe846fSGuillaume Nault * the session is set up. Unlike L2TPv2, we do not need to parse the
63323fe846fSGuillaume Nault * packet header to determine if optional fields are present.
634f7faffa3SJames Chapman *
635f7faffa3SJames Chapman * Caller must already have parsed the frame and determined that it is
636f7faffa3SJames Chapman * a data (not control) frame before coming here. Fields up to the
637f7faffa3SJames Chapman * session-id have already been parsed and ptr points to the data
638f7faffa3SJames Chapman * after the session-id.
639f7faffa3SJames Chapman */
l2tp_recv_common(struct l2tp_session * session,struct sk_buff * skb,unsigned char * ptr,unsigned char * optr,u16 hdrflags,int length)640f7faffa3SJames Chapman void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
641f7faffa3SJames Chapman unsigned char *ptr, unsigned char *optr, u16 hdrflags,
6422b139e6bSGuillaume Nault int length)
643f7faffa3SJames Chapman {
644f7faffa3SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel;
645f7faffa3SJames Chapman int offset;
646f7faffa3SJames Chapman
647f7faffa3SJames Chapman /* Parse and check optional cookie */
648f7faffa3SJames Chapman if (session->peer_cookie_len > 0) {
649f7faffa3SJames Chapman if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
6503e59e885SMatthias Schiffer pr_debug_ratelimited("%s: cookie mismatch (%u/%u). Discarding.\n",
651a4ca44faSJoe Perches tunnel->name, tunnel->tunnel_id,
652a4ca44faSJoe Perches session->session_id);
6537b7c0719STom Parkin atomic_long_inc(&session->stats.rx_cookie_discards);
654f7faffa3SJames Chapman goto discard;
655f7faffa3SJames Chapman }
656f7faffa3SJames Chapman ptr += session->peer_cookie_len;
657f7faffa3SJames Chapman }
658f7faffa3SJames Chapman
659f7faffa3SJames Chapman /* Handle the optional sequence numbers. Sequence numbers are
660f7faffa3SJames Chapman * in different places for L2TPv2 and L2TPv3.
661f7faffa3SJames Chapman *
662f7faffa3SJames Chapman * If we are the LAC, enable/disable sequence numbers under
663f7faffa3SJames Chapman * the control of the LNS. If no sequence numbers present but
664f7faffa3SJames Chapman * we were expecting them, discard frame.
665f7faffa3SJames Chapman */
666f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 0;
667f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) {
668f7faffa3SJames Chapman if (hdrflags & L2TP_HDRFLAG_S) {
669f7faffa3SJames Chapman /* Store L2TP info in the skb */
67012923365STom Parkin L2TP_SKB_CB(skb)->ns = ntohs(*(__be16 *)ptr);
671f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 1;
67212923365STom Parkin ptr += 2;
67312923365STom Parkin /* Skip past nr in the header */
67412923365STom Parkin ptr += 2;
675f7faffa3SJames Chapman
676f7faffa3SJames Chapman }
677f7faffa3SJames Chapman } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
678f7faffa3SJames Chapman u32 l2h = ntohl(*(__be32 *)ptr);
679f7faffa3SJames Chapman
680f7faffa3SJames Chapman if (l2h & 0x40000000) {
681f7faffa3SJames Chapman /* Store L2TP info in the skb */
68212923365STom Parkin L2TP_SKB_CB(skb)->ns = l2h & 0x00ffffff;
683f7faffa3SJames Chapman L2TP_SKB_CB(skb)->has_seq = 1;
684f7faffa3SJames Chapman }
68562e7b6a5SLorenzo Bianconi ptr += 4;
686f7faffa3SJames Chapman }
687f7faffa3SJames Chapman
688f7faffa3SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) {
68920dcb110STom Parkin /* Received a packet with sequence numbers. If we're the LAC,
690f7faffa3SJames Chapman * check if we sre sending sequence numbers and if not,
691f7faffa3SJames Chapman * configure it so.
692f7faffa3SJames Chapman */
6936c0ec37bSTom Parkin if (!session->lns_mode && !session->send_seq) {
6946b7bdcd7STom Parkin trace_session_seqnum_lns_enable(session);
6953f9b9770SAsbjørn Sloth Tønnesen session->send_seq = 1;
696f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version);
697f7faffa3SJames Chapman }
698f7faffa3SJames Chapman } else {
699f7faffa3SJames Chapman /* No sequence numbers.
700f7faffa3SJames Chapman * If user has configured mandatory sequence numbers, discard.
701f7faffa3SJames Chapman */
702f7faffa3SJames Chapman if (session->recv_seq) {
7033e59e885SMatthias Schiffer pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
704a4ca44faSJoe Perches session->name);
7057b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards);
706f7faffa3SJames Chapman goto discard;
707f7faffa3SJames Chapman }
708f7faffa3SJames Chapman
709f7faffa3SJames Chapman /* If we're the LAC and we're sending sequence numbers, the
710f7faffa3SJames Chapman * LNS has requested that we no longer send sequence numbers.
711f7faffa3SJames Chapman * If we're the LNS and we're sending sequence numbers, the
712f7faffa3SJames Chapman * LAC is broken. Discard the frame.
713f7faffa3SJames Chapman */
7146c0ec37bSTom Parkin if (!session->lns_mode && session->send_seq) {
7156b7bdcd7STom Parkin trace_session_seqnum_lns_disable(session);
716f7faffa3SJames Chapman session->send_seq = 0;
717f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version);
718f7faffa3SJames Chapman } else if (session->send_seq) {
7193e59e885SMatthias Schiffer pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
720a4ca44faSJoe Perches session->name);
7217b7c0719STom Parkin atomic_long_inc(&session->stats.rx_seq_discards);
722f7faffa3SJames Chapman goto discard;
723f7faffa3SJames Chapman }
724f7faffa3SJames Chapman }
725f7faffa3SJames Chapman
726900631eeSJames Chapman /* Session data offset is defined only for L2TPv2 and is
727900631eeSJames Chapman * indicated by an optional 16-bit value in the header.
728f7faffa3SJames Chapman */
729f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) {
730f7faffa3SJames Chapman /* If offset bit set, skip it. */
731f7faffa3SJames Chapman if (hdrflags & L2TP_HDRFLAG_O) {
732f7faffa3SJames Chapman offset = ntohs(*(__be16 *)ptr);
733f7faffa3SJames Chapman ptr += 2 + offset;
734f7faffa3SJames Chapman }
735900631eeSJames Chapman }
736f7faffa3SJames Chapman
737f7faffa3SJames Chapman offset = ptr - optr;
738f7faffa3SJames Chapman if (!pskb_may_pull(skb, offset))
739f7faffa3SJames Chapman goto discard;
740f7faffa3SJames Chapman
741f7faffa3SJames Chapman __skb_pull(skb, offset);
742f7faffa3SJames Chapman
743f7faffa3SJames Chapman /* Prepare skb for adding to the session's reorder_q. Hold
744f7faffa3SJames Chapman * packets for max reorder_timeout or 1 second if not
745f7faffa3SJames Chapman * reordering.
746f7faffa3SJames Chapman */
747f7faffa3SJames Chapman L2TP_SKB_CB(skb)->length = length;
748f7faffa3SJames Chapman L2TP_SKB_CB(skb)->expires = jiffies +
749f7faffa3SJames Chapman (session->reorder_timeout ? session->reorder_timeout : HZ);
750f7faffa3SJames Chapman
751f7faffa3SJames Chapman /* Add packet to the session's receive queue. Reordering is done here, if
752f7faffa3SJames Chapman * enabled. Saved L2TP protocol info is stored in skb->sb[].
753f7faffa3SJames Chapman */
754f7faffa3SJames Chapman if (L2TP_SKB_CB(skb)->has_seq) {
755b6dc01a4SJames Chapman if (l2tp_recv_data_seq(session, skb))
756f7faffa3SJames Chapman goto discard;
757f7faffa3SJames Chapman } else {
758f7faffa3SJames Chapman /* No sequence numbers. Add the skb to the tail of the
759f7faffa3SJames Chapman * reorder queue. This ensures that it will be
760f7faffa3SJames Chapman * delivered after all previous sequenced skbs.
761f7faffa3SJames Chapman */
762f7faffa3SJames Chapman skb_queue_tail(&session->reorder_q, skb);
763f7faffa3SJames Chapman }
764f7faffa3SJames Chapman
765f7faffa3SJames Chapman /* Try to dequeue as many skbs from reorder_q as we can. */
766f7faffa3SJames Chapman l2tp_recv_dequeue(session);
767f7faffa3SJames Chapman
768f7faffa3SJames Chapman return;
769f7faffa3SJames Chapman
770f7faffa3SJames Chapman discard:
7717b7c0719STom Parkin atomic_long_inc(&session->stats.rx_errors);
772f7faffa3SJames Chapman kfree_skb(skb);
773f7faffa3SJames Chapman }
774ca7885dbSTom Parkin EXPORT_SYMBOL_GPL(l2tp_recv_common);
775f7faffa3SJames Chapman
77648f72f92STom Parkin /* Drop skbs from the session's reorder_q
77748f72f92STom Parkin */
l2tp_session_queue_purge(struct l2tp_session * session)778493048f5STom Parkin static void l2tp_session_queue_purge(struct l2tp_session *session)
77948f72f92STom Parkin {
78048f72f92STom Parkin struct sk_buff *skb = NULL;
781b71a61ccSTom Parkin
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 }
78748f72f92STom Parkin
788fd558d18SJames Chapman /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame
789fd558d18SJames Chapman * here. The skb is not on a list when we get here.
790fd558d18SJames Chapman * Returns 0 if the packet was a data packet and was successfully passed on.
791fd558d18SJames Chapman * Returns 1 if the packet was not a good data packet and could not be
792fd558d18SJames Chapman * forwarded. All such packets are passed up to userspace to deal with.
793fd558d18SJames Chapman */
l2tp_udp_recv_core(struct l2tp_tunnel * tunnel,struct sk_buff * skb)7942b139e6bSGuillaume Nault static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
795fd558d18SJames Chapman {
796fd558d18SJames Chapman struct l2tp_session *session = NULL;
797fd558d18SJames Chapman unsigned char *ptr, *optr;
798fd558d18SJames Chapman u16 hdrflags;
799fd558d18SJames Chapman u32 tunnel_id, session_id;
800fd558d18SJames Chapman u16 version;
801f7faffa3SJames Chapman int length;
802fd558d18SJames Chapman
803aa785f93SBhaskar Chowdhury /* UDP has verified checksum */
804fd558d18SJames Chapman
805fd558d18SJames Chapman /* UDP always verifies the packet length. */
806fd558d18SJames Chapman __skb_pull(skb, sizeof(struct udphdr));
807fd558d18SJames Chapman
808fd558d18SJames Chapman /* Short packet? */
80991c52470SJacob Wen if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) {
8103e59e885SMatthias Schiffer pr_debug_ratelimited("%s: recv short packet (len=%d)\n",
811a4ca44faSJoe Perches tunnel->name, skb->len);
8123e59e885SMatthias Schiffer goto invalid;
813fd558d18SJames Chapman }
814fd558d18SJames Chapman
815e50e705cSEric Dumazet /* Point to L2TP header */
81695075150STom Parkin optr = skb->data;
81795075150STom Parkin ptr = skb->data;
818e50e705cSEric Dumazet
819fd558d18SJames Chapman /* Get L2TP header flags */
820fd558d18SJames Chapman hdrflags = ntohs(*(__be16 *)ptr);
821fd558d18SJames Chapman
822fd558d18SJames Chapman /* Check protocol version */
823fd558d18SJames Chapman version = hdrflags & L2TP_HDR_VER_MASK;
824fd558d18SJames Chapman if (version != tunnel->version) {
8253e59e885SMatthias Schiffer pr_debug_ratelimited("%s: recv protocol version mismatch: got %d expected %d\n",
826fd558d18SJames Chapman tunnel->name, version, tunnel->version);
8273e59e885SMatthias Schiffer goto invalid;
828fd558d18SJames Chapman }
829fd558d18SJames Chapman
830fd558d18SJames Chapman /* Get length of L2TP packet */
831fd558d18SJames Chapman length = skb->len;
832fd558d18SJames Chapman
833fd558d18SJames Chapman /* If type is control packet, it is handled by userspace. */
83412923365STom Parkin if (hdrflags & L2TP_HDRFLAG_T)
8353e59e885SMatthias Schiffer goto pass;
836fd558d18SJames Chapman
837fd558d18SJames Chapman /* Skip flags */
838fd558d18SJames Chapman ptr += 2;
839fd558d18SJames Chapman
840f7faffa3SJames Chapman if (tunnel->version == L2TP_HDR_VER_2) {
841fd558d18SJames Chapman /* If length is present, skip it */
842fd558d18SJames Chapman if (hdrflags & L2TP_HDRFLAG_L)
843fd558d18SJames Chapman ptr += 2;
844fd558d18SJames Chapman
845fd558d18SJames Chapman /* Extract tunnel and session ID */
846fd558d18SJames Chapman tunnel_id = ntohs(*(__be16 *)ptr);
847fd558d18SJames Chapman ptr += 2;
848fd558d18SJames Chapman session_id = ntohs(*(__be16 *)ptr);
849fd558d18SJames Chapman ptr += 2;
850f7faffa3SJames Chapman } else {
851f7faffa3SJames Chapman ptr += 2; /* skip reserved bits */
852f7faffa3SJames Chapman tunnel_id = tunnel->tunnel_id;
853f7faffa3SJames Chapman session_id = ntohl(*(__be32 *)ptr);
854f7faffa3SJames Chapman ptr += 4;
855f7faffa3SJames Chapman }
856fd558d18SJames Chapman
857fd558d18SJames Chapman /* Find the session context */
85801e28b92SGuillaume Nault session = l2tp_tunnel_get_session(tunnel, session_id);
859309795f4SJames Chapman if (!session || !session->recv_skb) {
860a4346210SGuillaume Nault if (session)
86161b9a047SGuillaume Nault l2tp_session_dec_refcount(session);
86261b9a047SGuillaume Nault
863fd558d18SJames Chapman /* Not found? Pass to userspace to deal with */
8643e59e885SMatthias Schiffer pr_debug_ratelimited("%s: no session found (%u/%u). Passing up.\n",
865fd558d18SJames Chapman tunnel->name, tunnel_id, session_id);
8663e59e885SMatthias Schiffer goto pass;
867fd558d18SJames Chapman }
868fd558d18SJames Chapman
8694522a70dSJacob Wen if (tunnel->version == L2TP_HDR_VER_3 &&
8709b6ff7ebSXiyu Yang l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) {
8719b6ff7ebSXiyu Yang l2tp_session_dec_refcount(session);
8723e59e885SMatthias Schiffer goto invalid;
8739b6ff7ebSXiyu Yang }
8744522a70dSJacob Wen
8752b139e6bSGuillaume Nault l2tp_recv_common(session, skb, ptr, optr, hdrflags, length);
87661b9a047SGuillaume Nault l2tp_session_dec_refcount(session);
877fd558d18SJames Chapman
878fd558d18SJames Chapman return 0;
879fd558d18SJames Chapman
8803e59e885SMatthias Schiffer invalid:
8813e59e885SMatthias Schiffer atomic_long_inc(&tunnel->stats.rx_invalid);
8823e59e885SMatthias Schiffer
8833e59e885SMatthias Schiffer pass:
884fd558d18SJames Chapman /* Put UDP header back */
885fd558d18SJames Chapman __skb_push(skb, sizeof(struct udphdr));
886fd558d18SJames Chapman
887fd558d18SJames Chapman return 1;
888fd558d18SJames Chapman }
889fd558d18SJames Chapman
890fd558d18SJames Chapman /* UDP encapsulation receive handler. See net/ipv4/udp.c.
891fd558d18SJames Chapman * Return codes:
892fd558d18SJames Chapman * 0 : success.
893fd558d18SJames Chapman * <0: error
894fd558d18SJames Chapman * >0: skb should be passed up to userspace as UDP.
895fd558d18SJames Chapman */
l2tp_udp_encap_recv(struct sock * sk,struct sk_buff * skb)896fd558d18SJames Chapman int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
897fd558d18SJames Chapman {
898fd558d18SJames Chapman struct l2tp_tunnel *tunnel;
899fd558d18SJames Chapman
90045faeff1STom Parkin /* Note that this is called from the encap_rcv hook inside an
90145faeff1STom Parkin * RCU-protected region, but without the socket being locked.
90245faeff1STom Parkin * Hence we use rcu_dereference_sk_user_data to access the
90345faeff1STom Parkin * tunnel data structure rather the usual l2tp_sk_to_tunnel
90445faeff1STom Parkin * accessor function.
90545faeff1STom Parkin */
906c1c47721SEric Dumazet tunnel = rcu_dereference_sk_user_data(sk);
9070febc7b3STom Parkin if (!tunnel)
908fd558d18SJames Chapman goto pass_up;
90945faeff1STom Parkin if (WARN_ON(tunnel->magic != L2TP_TUNNEL_MAGIC))
91045faeff1STom Parkin goto pass_up;
911fd558d18SJames Chapman
9122b139e6bSGuillaume Nault if (l2tp_udp_recv_core(tunnel, skb))
913d00fa9adSJames Chapman goto pass_up;
914fd558d18SJames Chapman
915fd558d18SJames Chapman return 0;
916fd558d18SJames Chapman
917fd558d18SJames Chapman pass_up:
918fd558d18SJames Chapman return 1;
919fd558d18SJames Chapman }
920fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_udp_encap_recv);
921fd558d18SJames Chapman
922fd558d18SJames Chapman /************************************************************************
923fd558d18SJames Chapman * Transmit handling
924fd558d18SJames Chapman ***********************************************************************/
925fd558d18SJames Chapman
926fd558d18SJames Chapman /* Build an L2TP header for the session into the buffer provided.
927fd558d18SJames Chapman */
l2tp_build_l2tpv2_header(struct l2tp_session * session,void * buf)928f7faffa3SJames Chapman static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
929fd558d18SJames Chapman {
930f7faffa3SJames Chapman struct l2tp_tunnel *tunnel = session->tunnel;
931fd558d18SJames Chapman __be16 *bufp = buf;
932f7faffa3SJames Chapman __be16 *optr = buf;
933fd558d18SJames Chapman u16 flags = L2TP_HDR_VER_2;
934fd558d18SJames Chapman u32 tunnel_id = tunnel->peer_tunnel_id;
935fd558d18SJames Chapman u32 session_id = session->peer_session_id;
936fd558d18SJames Chapman
937fd558d18SJames Chapman if (session->send_seq)
938fd558d18SJames Chapman flags |= L2TP_HDRFLAG_S;
939fd558d18SJames Chapman
940fd558d18SJames Chapman /* Setup L2TP header. */
941fd558d18SJames Chapman *bufp++ = htons(flags);
942fd558d18SJames Chapman *bufp++ = htons(tunnel_id);
943fd558d18SJames Chapman *bufp++ = htons(session_id);
944fd558d18SJames Chapman if (session->send_seq) {
945fd558d18SJames Chapman *bufp++ = htons(session->ns);
946fd558d18SJames Chapman *bufp++ = 0;
947fd558d18SJames Chapman session->ns++;
948f7faffa3SJames Chapman session->ns &= 0xffff;
9496b7bdcd7STom Parkin trace_session_seqnum_update(session);
950fd558d18SJames Chapman }
951fd558d18SJames Chapman
952f7faffa3SJames Chapman return bufp - optr;
953f7faffa3SJames Chapman }
954f7faffa3SJames Chapman
l2tp_build_l2tpv3_header(struct l2tp_session * session,void * buf)955f7faffa3SJames Chapman static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
956fd558d18SJames Chapman {
9570d76751fSJames Chapman struct l2tp_tunnel *tunnel = session->tunnel;
958f7faffa3SJames Chapman char *bufp = buf;
959f7faffa3SJames Chapman char *optr = bufp;
960fd558d18SJames Chapman
9610d76751fSJames Chapman /* Setup L2TP header. The header differs slightly for UDP and
9620d76751fSJames Chapman * IP encapsulations. For UDP, there is 4 bytes of flags.
9630d76751fSJames Chapman */
9640d76751fSJames Chapman if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
9650d76751fSJames Chapman u16 flags = L2TP_HDR_VER_3;
966f7faffa3SJames Chapman *((__be16 *)bufp) = htons(flags);
967f7faffa3SJames Chapman bufp += 2;
968f7faffa3SJames Chapman *((__be16 *)bufp) = 0;
969f7faffa3SJames Chapman bufp += 2;
9700d76751fSJames Chapman }
9710d76751fSJames Chapman
972f7faffa3SJames Chapman *((__be32 *)bufp) = htonl(session->peer_session_id);
973f7faffa3SJames Chapman bufp += 4;
974f7faffa3SJames Chapman if (session->cookie_len) {
975f7faffa3SJames Chapman memcpy(bufp, &session->cookie[0], session->cookie_len);
976f7faffa3SJames Chapman bufp += session->cookie_len;
977fd558d18SJames Chapman }
978f7faffa3SJames Chapman if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
979f7faffa3SJames Chapman u32 l2h = 0;
98062e7b6a5SLorenzo Bianconi
981f7faffa3SJames Chapman if (session->send_seq) {
982f7faffa3SJames Chapman l2h = 0x40000000 | session->ns;
983f7faffa3SJames Chapman session->ns++;
984f7faffa3SJames Chapman session->ns &= 0xffffff;
9856b7bdcd7STom Parkin trace_session_seqnum_update(session);
986f7faffa3SJames Chapman }
987f7faffa3SJames Chapman
988f7faffa3SJames Chapman *((__be32 *)bufp) = htonl(l2h);
98962e7b6a5SLorenzo Bianconi bufp += 4;
990f7faffa3SJames Chapman }
991f7faffa3SJames Chapman
992f7faffa3SJames Chapman return bufp - optr;
993f7faffa3SJames Chapman }
994fd558d18SJames Chapman
995de68b039STom Parkin /* Queue the packet to IP for output: tunnel socket lock must be held */
l2tp_xmit_queue(struct l2tp_tunnel * tunnel,struct sk_buff * skb,struct flowi * fl)996de68b039STom Parkin static int l2tp_xmit_queue(struct l2tp_tunnel *tunnel, struct sk_buff *skb, struct flowi *fl)
997fd558d18SJames Chapman {
998de68b039STom Parkin int err;
999fd558d18SJames Chapman
100060ff7467SWANG Cong skb->ignore_df = 1;
100127d53323SXin Long skb_dst_drop(skb);
1002d2cf3361SBenjamin LaHaise #if IS_ENABLED(CONFIG_IPV6)
1003b954f940SPaolo Abeni if (l2tp_sk_is_v6(tunnel->sock))
1004de68b039STom Parkin err = inet6_csk_xmit(tunnel->sock, skb, NULL);
1005d2cf3361SBenjamin LaHaise else
1006d2cf3361SBenjamin LaHaise #endif
1007de68b039STom Parkin err = ip_queue_xmit(tunnel->sock, skb, fl);
1008fd558d18SJames Chapman
1009de68b039STom Parkin return err >= 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
1010fd558d18SJames Chapman }
1011fd558d18SJames Chapman
l2tp_xmit_core(struct l2tp_session * session,struct sk_buff * skb,unsigned int * len)1012f52e4b27STom Parkin static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, unsigned int *len)
1013fd558d18SJames Chapman {
10140d76751fSJames Chapman struct l2tp_tunnel *tunnel = session->tunnel;
1015de68b039STom Parkin unsigned int data_len = skb->len;
10160d76751fSJames Chapman struct sock *sk = tunnel->sock;
1017de68b039STom Parkin int headroom, uhlen, udp_len;
1018b8c84307SEric Dumazet int ret = NET_XMIT_SUCCESS;
1019de68b039STom Parkin struct inet_sock *inet;
1020de68b039STom Parkin struct udphdr *uh;
1021fd558d18SJames Chapman
1022fd558d18SJames Chapman /* Check that there's enough headroom in the skb to insert IP,
1023fd558d18SJames Chapman * UDP and L2TP headers. If not enough, expand it to
1024fd558d18SJames Chapman * make room. Adjust truesize.
1025fd558d18SJames Chapman */
1026de68b039STom Parkin uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(*uh) : 0;
1027de68b039STom Parkin headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len;
1028835acf5dSEric Dumazet if (skb_cow_head(skb, headroom)) {
1029b8c84307SEric Dumazet kfree_skb(skb);
1030b8c84307SEric Dumazet return NET_XMIT_DROP;
1031835acf5dSEric Dumazet }
1032fd558d18SJames Chapman
1033fd558d18SJames Chapman /* Setup L2TP header */
10342dedab6fSTom Parkin if (tunnel->version == L2TP_HDR_VER_2)
1035efe05278STom Parkin l2tp_build_l2tpv2_header(session, __skb_push(skb, session->hdr_len));
10362dedab6fSTom Parkin else
1037efe05278STom Parkin l2tp_build_l2tpv3_header(session, __skb_push(skb, session->hdr_len));
1038fd558d18SJames Chapman
10390d76751fSJames Chapman /* Reset skb netfilter state */
1040fd558d18SJames Chapman memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1041de68b039STom Parkin IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
1042895b5c9fSFlorian Westphal nf_reset_ct(skb);
1043fd558d18SJames Chapman
10440b2c5972SCong Wang bh_lock_sock_nested(sk);
10456af88da1SDavid S. Miller if (sock_owned_by_user(sk)) {
1046b8c84307SEric Dumazet kfree_skb(skb);
1047b8c84307SEric Dumazet ret = NET_XMIT_DROP;
10486af88da1SDavid S. Miller goto out_unlock;
10496af88da1SDavid S. Miller }
10506af88da1SDavid S. Miller
1051b954f940SPaolo Abeni /* The user-space may change the connection status for the user-space
1052b954f940SPaolo Abeni * provided socket at run time: we must check it under the socket lock
1053b954f940SPaolo Abeni */
1054b954f940SPaolo Abeni if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) {
1055b954f940SPaolo Abeni kfree_skb(skb);
1056b954f940SPaolo Abeni ret = NET_XMIT_DROP;
1057b954f940SPaolo Abeni goto out_unlock;
1058b954f940SPaolo Abeni }
1059b954f940SPaolo Abeni
1060f52e4b27STom Parkin /* Report transmitted length before we add encap header, which keeps
1061f52e4b27STom Parkin * statistics consistent for both UDP and IP encap tx/rx paths.
1062f52e4b27STom Parkin */
1063f52e4b27STom Parkin *len = skb->len;
1064f52e4b27STom Parkin
1065d9d8da80SDavid S. Miller inet = inet_sk(sk);
10660d76751fSJames Chapman switch (tunnel->encap) {
10670d76751fSJames Chapman case L2TP_ENCAPTYPE_UDP:
10680d76751fSJames Chapman /* Setup UDP header */
10690d76751fSJames Chapman __skb_push(skb, sizeof(*uh));
10700d76751fSJames Chapman skb_reset_transport_header(skb);
10710d76751fSJames Chapman uh = udp_hdr(skb);
10720d76751fSJames Chapman uh->source = inet->inet_sport;
10730d76751fSJames Chapman uh->dest = inet->inet_dport;
1074efe05278STom Parkin udp_len = uhlen + session->hdr_len + data_len;
10750d76751fSJames Chapman uh->len = htons(udp_len);
1076fd558d18SJames Chapman
1077fd558d18SJames Chapman /* Calculate UDP checksum if configured to do so */
1078d2cf3361SBenjamin LaHaise #if IS_ENABLED(CONFIG_IPV6)
1079b954f940SPaolo Abeni if (l2tp_sk_is_v6(sk))
108077157e19STom Herbert udp6_set_csum(udp_get_no_check6_tx(sk),
108177157e19STom Herbert skb, &inet6_sk(sk)->saddr,
108277157e19STom Herbert &sk->sk_v6_daddr, udp_len);
1083d2cf3361SBenjamin LaHaise else
1084d2cf3361SBenjamin LaHaise #endif
108577157e19STom Herbert udp_set_csum(sk->sk_no_check_tx, skb, inet->inet_saddr,
108677157e19STom Herbert inet->inet_daddr, udp_len);
10870d76751fSJames Chapman break;
10880d76751fSJames Chapman
10890d76751fSJames Chapman case L2TP_ENCAPTYPE_IP:
10900d76751fSJames Chapman break;
10910d76751fSJames Chapman }
10920d76751fSJames Chapman
1093de68b039STom Parkin ret = l2tp_xmit_queue(tunnel, skb, &inet->cork.fl);
1094de68b039STom Parkin
10956af88da1SDavid S. Miller out_unlock:
10966af88da1SDavid S. Miller bh_unlock_sock(sk);
1097fd558d18SJames Chapman
1098b8c84307SEric Dumazet return ret;
1099fd558d18SJames Chapman }
1100de68b039STom Parkin
1101de68b039STom Parkin /* If caller requires the skb to have a ppp header, the header must be
1102de68b039STom Parkin * inserted in the skb data before calling this function.
1103de68b039STom Parkin */
l2tp_xmit_skb(struct l2tp_session * session,struct sk_buff * skb)1104de68b039STom Parkin int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb)
1105de68b039STom Parkin {
1106f52e4b27STom Parkin unsigned int len = 0;
1107de68b039STom Parkin int ret;
1108de68b039STom Parkin
1109f52e4b27STom Parkin ret = l2tp_xmit_core(session, skb, &len);
1110de68b039STom Parkin if (ret == NET_XMIT_SUCCESS) {
1111de68b039STom Parkin atomic_long_inc(&session->tunnel->stats.tx_packets);
1112de68b039STom Parkin atomic_long_add(len, &session->tunnel->stats.tx_bytes);
1113de68b039STom Parkin atomic_long_inc(&session->stats.tx_packets);
1114de68b039STom Parkin atomic_long_add(len, &session->stats.tx_bytes);
1115de68b039STom Parkin } else {
1116de68b039STom Parkin atomic_long_inc(&session->tunnel->stats.tx_errors);
1117de68b039STom Parkin atomic_long_inc(&session->stats.tx_errors);
1118de68b039STom Parkin }
1119de68b039STom Parkin return ret;
1120de68b039STom Parkin }
1121fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
1122fd558d18SJames Chapman
1123fd558d18SJames Chapman /*****************************************************************************
1124fd558d18SJames Chapman * Tinnel and session create/destroy.
1125fd558d18SJames Chapman *****************************************************************************/
1126fd558d18SJames Chapman
1127fd558d18SJames Chapman /* Tunnel socket destruct hook.
1128fd558d18SJames Chapman * The tunnel context is deleted only when all session sockets have been
1129fd558d18SJames Chapman * closed.
1130fd558d18SJames Chapman */
l2tp_tunnel_destruct(struct sock * sk)1131fc130840Sstephen hemminger static void l2tp_tunnel_destruct(struct sock *sk)
1132fd558d18SJames Chapman {
113345faeff1STom Parkin struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
1134fd558d18SJames Chapman
11350febc7b3STom Parkin if (!tunnel)
1136fd558d18SJames Chapman goto end;
1137fd558d18SJames Chapman
1138f8ccac0eSTom Parkin /* Disable udp encapsulation */
11390d76751fSJames Chapman switch (tunnel->encap) {
11400d76751fSJames Chapman case L2TP_ENCAPTYPE_UDP:
1141fd558d18SJames Chapman /* No longer an encapsulation socket. See net/ipv4/udp.c */
1142*4781a75dSEric Dumazet WRITE_ONCE(udp_sk(sk)->encap_type, 0);
1143*4781a75dSEric Dumazet udp_sk(sk)->encap_rcv = NULL;
1144*4781a75dSEric Dumazet udp_sk(sk)->encap_destroy = NULL;
11450d76751fSJames Chapman break;
11460d76751fSJames Chapman case L2TP_ENCAPTYPE_IP:
11470d76751fSJames Chapman break;
11480d76751fSJames Chapman }
1149fd558d18SJames Chapman
1150fd558d18SJames Chapman /* Remove hooks into tunnel socket */
1151b68777d5SJakub Sitnicki write_lock_bh(&sk->sk_callback_lock);
1152fd558d18SJames Chapman sk->sk_destruct = tunnel->old_sk_destruct;
1153fd558d18SJames Chapman sk->sk_user_data = NULL;
1154b68777d5SJakub Sitnicki write_unlock_bh(&sk->sk_callback_lock);
1155f8ccac0eSTom Parkin
1156fd558d18SJames Chapman /* Call the original destructor */
1157fd558d18SJames Chapman if (sk->sk_destruct)
1158fd558d18SJames Chapman (*sk->sk_destruct)(sk);
1159d00fa9adSJames Chapman
1160d00fa9adSJames Chapman kfree_rcu(tunnel, rcu);
1161fd558d18SJames Chapman end:
1162fd558d18SJames Chapman return;
1163fd558d18SJames Chapman }
1164fd558d18SJames Chapman
1165b2aecfe8STom Parkin /* Remove an l2tp session from l2tp_core's hash lists. */
l2tp_session_unhash(struct l2tp_session * session)1166b2aecfe8STom Parkin static void l2tp_session_unhash(struct l2tp_session *session)
1167b2aecfe8STom Parkin {
1168b2aecfe8STom Parkin struct l2tp_tunnel *tunnel = session->tunnel;
1169b2aecfe8STom Parkin
1170b2aecfe8STom Parkin /* Remove the session from core hashes */
1171b2aecfe8STom Parkin if (tunnel) {
1172b2aecfe8STom Parkin /* Remove from the per-tunnel hash */
117307b8ca37STom Parkin spin_lock_bh(&tunnel->hlist_lock);
117407b8ca37STom Parkin hlist_del_init_rcu(&session->hlist);
117507b8ca37STom Parkin spin_unlock_bh(&tunnel->hlist_lock);
1176b2aecfe8STom Parkin
1177b2aecfe8STom Parkin /* For L2TPv3 we have a per-net hash: remove from there, too */
1178b2aecfe8STom Parkin if (tunnel->version != L2TP_HDR_VER_2) {
1179b2aecfe8STom Parkin struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
1180b2aecfe8STom Parkin
1181b2aecfe8STom Parkin spin_lock_bh(&pn->l2tp_session_hlist_lock);
1182b2aecfe8STom Parkin hlist_del_init_rcu(&session->global_hlist);
1183b2aecfe8STom Parkin spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1184b2aecfe8STom Parkin }
118507b8ca37STom Parkin
118607b8ca37STom Parkin synchronize_rcu();
1187b2aecfe8STom Parkin }
1188b2aecfe8STom Parkin }
1189b2aecfe8STom Parkin
1190fd558d18SJames Chapman /* When the tunnel is closed, all the attached sessions need to go too.
1191fd558d18SJames Chapman */
l2tp_tunnel_closeall(struct l2tp_tunnel * tunnel)1192d08532bbSGuillaume Nault static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
1193fd558d18SJames Chapman {
1194fd558d18SJames Chapman struct l2tp_session *session;
119507b8ca37STom Parkin int hash;
1196fd558d18SJames Chapman
119707b8ca37STom Parkin spin_lock_bh(&tunnel->hlist_lock);
1198f3c66d4eSGuillaume Nault tunnel->acpt_newsess = false;
1199fd558d18SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
1200fd558d18SJames Chapman again:
120107b8ca37STom Parkin hlist_for_each_entry_rcu(session, &tunnel->session_hlist[hash], hlist) {
120207b8ca37STom Parkin hlist_del_init_rcu(&session->hlist);
1203fd558d18SJames Chapman
120407b8ca37STom Parkin spin_unlock_bh(&tunnel->hlist_lock);
12059d319a8eSTom Parkin l2tp_session_delete(session);
120607b8ca37STom Parkin spin_lock_bh(&tunnel->hlist_lock);
1207fd558d18SJames Chapman
1208fd558d18SJames Chapman /* Now restart from the beginning of this hash
1209fd558d18SJames Chapman * chain. We always remove a session from the
1210fd558d18SJames Chapman * list so we are guaranteed to make forward
1211fd558d18SJames Chapman * progress.
1212fd558d18SJames Chapman */
1213fd558d18SJames Chapman goto again;
1214fd558d18SJames Chapman }
1215fd558d18SJames Chapman }
121607b8ca37STom Parkin spin_unlock_bh(&tunnel->hlist_lock);
1217fd558d18SJames Chapman }
1218fd558d18SJames Chapman
12199980d001STom Parkin /* Tunnel socket destroy hook for UDP encapsulation */
l2tp_udp_encap_destroy(struct sock * sk)12209980d001STom Parkin static void l2tp_udp_encap_destroy(struct sock *sk)
12219980d001STom Parkin {
122245faeff1STom Parkin struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
1223d00fa9adSJames Chapman
1224d00fa9adSJames Chapman if (tunnel)
1225d00fa9adSJames Chapman l2tp_tunnel_delete(tunnel);
12269980d001STom Parkin }
12279980d001STom Parkin
l2tp_tunnel_remove(struct net * net,struct l2tp_tunnel * tunnel)1228c4d48a58SCong Wang static void l2tp_tunnel_remove(struct net *net, struct l2tp_tunnel *tunnel)
1229c4d48a58SCong Wang {
1230c4d48a58SCong Wang struct l2tp_net *pn = l2tp_pernet(net);
1231c4d48a58SCong Wang
1232c4d48a58SCong Wang spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
1233c4d48a58SCong Wang idr_remove(&pn->l2tp_tunnel_idr, tunnel->tunnel_id);
1234c4d48a58SCong Wang spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
1235c4d48a58SCong Wang }
1236c4d48a58SCong Wang
1237f8ccac0eSTom Parkin /* Workqueue tunnel deletion function */
l2tp_tunnel_del_work(struct work_struct * work)1238f8ccac0eSTom Parkin static void l2tp_tunnel_del_work(struct work_struct *work)
1239f8ccac0eSTom Parkin {
1240d00fa9adSJames Chapman struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel,
1241d00fa9adSJames Chapman del_work);
1242d00fa9adSJames Chapman struct sock *sk = tunnel->sock;
1243d00fa9adSJames Chapman struct socket *sock = sk->sk_socket;
124412d656afSRidge Kennedy
124512d656afSRidge Kennedy l2tp_tunnel_closeall(tunnel);
124612d656afSRidge Kennedy
124776a6abdbSJames Chapman /* If the tunnel socket was created within the kernel, use
124802d13ed5STom Parkin * the sk API to release it here.
1249f8ccac0eSTom Parkin */
125076a6abdbSJames Chapman if (tunnel->fd < 0) {
125126abe143SEric W. Biederman if (sock) {
1252167eb17eSTom Parkin kernel_sock_shutdown(sock, SHUT_RDWR);
125326abe143SEric W. Biederman sock_release(sock);
125426abe143SEric W. Biederman }
1255167eb17eSTom Parkin }
1256f8ccac0eSTom Parkin
1257c4d48a58SCong Wang l2tp_tunnel_remove(tunnel->l2tp_net, tunnel);
1258d00fa9adSJames Chapman /* drop initial ref */
1259d00fa9adSJames Chapman l2tp_tunnel_dec_refcount(tunnel);
1260d00fa9adSJames Chapman
1261d00fa9adSJames Chapman /* drop workqueue ref */
126206a15f51SAlexander Couzens l2tp_tunnel_dec_refcount(tunnel);
1263fd558d18SJames Chapman }
1264fd558d18SJames Chapman
1265789a4a2cSJames Chapman /* Create a socket for the tunnel, if one isn't set up by
1266789a4a2cSJames Chapman * userspace. This is used for static tunnels where there is no
1267789a4a2cSJames Chapman * managing L2TP daemon.
1268167eb17eSTom Parkin *
1269167eb17eSTom Parkin * Since we don't want these sockets to keep a namespace alive by
1270167eb17eSTom Parkin * themselves, we drop the socket's namespace refcount after creation.
1271167eb17eSTom Parkin * These sockets are freed when the namespace exits using the pernet
1272167eb17eSTom Parkin * exit hook.
1273789a4a2cSJames Chapman */
l2tp_tunnel_sock_create(struct net * net,u32 tunnel_id,u32 peer_tunnel_id,struct l2tp_tunnel_cfg * cfg,struct socket ** sockp)1274167eb17eSTom Parkin static int l2tp_tunnel_sock_create(struct net *net,
1275167eb17eSTom Parkin u32 tunnel_id,
1276167eb17eSTom Parkin u32 peer_tunnel_id,
1277167eb17eSTom Parkin struct l2tp_tunnel_cfg *cfg,
1278167eb17eSTom Parkin struct socket **sockp)
1279789a4a2cSJames Chapman {
1280789a4a2cSJames Chapman int err = -EINVAL;
12817bddd0dbSEric Dumazet struct socket *sock = NULL;
128285644b4dSTom Herbert struct udp_port_cfg udp_conf;
1283789a4a2cSJames Chapman
1284789a4a2cSJames Chapman switch (cfg->encap) {
1285789a4a2cSJames Chapman case L2TP_ENCAPTYPE_UDP:
128685644b4dSTom Herbert memset(&udp_conf, 0, sizeof(udp_conf));
128785644b4dSTom Herbert
1288f9bac8dfSChris Elston #if IS_ENABLED(CONFIG_IPV6)
1289f9bac8dfSChris Elston if (cfg->local_ip6 && cfg->peer_ip6) {
129085644b4dSTom Herbert udp_conf.family = AF_INET6;
129185644b4dSTom Herbert memcpy(&udp_conf.local_ip6, cfg->local_ip6,
129285644b4dSTom Herbert sizeof(udp_conf.local_ip6));
129385644b4dSTom Herbert memcpy(&udp_conf.peer_ip6, cfg->peer_ip6,
129485644b4dSTom Herbert sizeof(udp_conf.peer_ip6));
129585644b4dSTom Herbert udp_conf.use_udp6_tx_checksums =
1296018f8258SWang Shanker !cfg->udp6_zero_tx_checksums;
129785644b4dSTom Herbert udp_conf.use_udp6_rx_checksums =
1298018f8258SWang Shanker !cfg->udp6_zero_rx_checksums;
1299f9bac8dfSChris Elston } else
1300f9bac8dfSChris Elston #endif
1301f9bac8dfSChris Elston {
130285644b4dSTom Herbert udp_conf.family = AF_INET;
130385644b4dSTom Herbert udp_conf.local_ip = cfg->local_ip;
130485644b4dSTom Herbert udp_conf.peer_ip = cfg->peer_ip;
130585644b4dSTom Herbert udp_conf.use_udp_checksums = cfg->use_udp_checksums;
1306f9bac8dfSChris Elston }
1307789a4a2cSJames Chapman
130885644b4dSTom Herbert udp_conf.local_udp_port = htons(cfg->local_udp_port);
130985644b4dSTom Herbert udp_conf.peer_udp_port = htons(cfg->peer_udp_port);
131085644b4dSTom Herbert
131185644b4dSTom Herbert err = udp_sock_create(net, &udp_conf, &sock);
131285644b4dSTom Herbert if (err < 0)
131385644b4dSTom Herbert goto out;
1314789a4a2cSJames Chapman
1315789a4a2cSJames Chapman break;
1316789a4a2cSJames Chapman
1317789a4a2cSJames Chapman case L2TP_ENCAPTYPE_IP:
1318f9bac8dfSChris Elston #if IS_ENABLED(CONFIG_IPV6)
1319f9bac8dfSChris Elston if (cfg->local_ip6 && cfg->peer_ip6) {
132085644b4dSTom Herbert struct sockaddr_l2tpip6 ip6_addr = {0};
132185644b4dSTom Herbert
132226abe143SEric W. Biederman err = sock_create_kern(net, AF_INET6, SOCK_DGRAM,
1323167eb17eSTom Parkin IPPROTO_L2TP, &sock);
13245dac94e1SJames Chapman if (err < 0)
1325f9bac8dfSChris Elston goto out;
13265dac94e1SJames Chapman
13275dac94e1SJames Chapman ip6_addr.l2tp_family = AF_INET6;
13285dac94e1SJames Chapman memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6,
13295dac94e1SJames Chapman sizeof(ip6_addr.l2tp_addr));
13305dac94e1SJames Chapman ip6_addr.l2tp_conn_id = tunnel_id;
13315dac94e1SJames Chapman err = kernel_bind(sock, (struct sockaddr *)&ip6_addr,
13325dac94e1SJames Chapman sizeof(ip6_addr));
13335dac94e1SJames Chapman if (err < 0)
13345dac94e1SJames Chapman goto out;
13355dac94e1SJames Chapman
13365dac94e1SJames Chapman ip6_addr.l2tp_family = AF_INET6;
13375dac94e1SJames Chapman memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6,
13385dac94e1SJames Chapman sizeof(ip6_addr.l2tp_addr));
13395dac94e1SJames Chapman ip6_addr.l2tp_conn_id = peer_tunnel_id;
13405dac94e1SJames Chapman err = kernel_connect(sock,
13415dac94e1SJames Chapman (struct sockaddr *)&ip6_addr,
13425dac94e1SJames Chapman sizeof(ip6_addr), 0);
13435dac94e1SJames Chapman if (err < 0)
13445dac94e1SJames Chapman goto out;
13455dac94e1SJames Chapman } else
1346f9bac8dfSChris Elston #endif
13475dac94e1SJames Chapman {
134885644b4dSTom Herbert struct sockaddr_l2tpip ip_addr = {0};
134985644b4dSTom Herbert
135026abe143SEric W. Biederman err = sock_create_kern(net, AF_INET, SOCK_DGRAM,
1351167eb17eSTom Parkin IPPROTO_L2TP, &sock);
1352789a4a2cSJames Chapman if (err < 0)
1353789a4a2cSJames Chapman goto out;
1354789a4a2cSJames Chapman
1355789a4a2cSJames Chapman ip_addr.l2tp_family = AF_INET;
1356789a4a2cSJames Chapman ip_addr.l2tp_addr = cfg->local_ip;
1357789a4a2cSJames Chapman ip_addr.l2tp_conn_id = tunnel_id;
13585dac94e1SJames Chapman err = kernel_bind(sock, (struct sockaddr *)&ip_addr,
13595dac94e1SJames Chapman sizeof(ip_addr));
1360789a4a2cSJames Chapman if (err < 0)
1361789a4a2cSJames Chapman goto out;
1362789a4a2cSJames Chapman
1363789a4a2cSJames Chapman ip_addr.l2tp_family = AF_INET;
1364789a4a2cSJames Chapman ip_addr.l2tp_addr = cfg->peer_ip;
1365789a4a2cSJames Chapman ip_addr.l2tp_conn_id = peer_tunnel_id;
13665dac94e1SJames Chapman err = kernel_connect(sock, (struct sockaddr *)&ip_addr,
13675dac94e1SJames Chapman sizeof(ip_addr), 0);
1368789a4a2cSJames Chapman if (err < 0)
1369789a4a2cSJames Chapman goto out;
13705dac94e1SJames Chapman }
1371789a4a2cSJames Chapman break;
1372789a4a2cSJames Chapman
1373789a4a2cSJames Chapman default:
1374789a4a2cSJames Chapman goto out;
1375789a4a2cSJames Chapman }
1376789a4a2cSJames Chapman
1377789a4a2cSJames Chapman out:
1378167eb17eSTom Parkin *sockp = sock;
13796c0ec37bSTom Parkin if (err < 0 && sock) {
1380167eb17eSTom Parkin kernel_sock_shutdown(sock, SHUT_RDWR);
138126abe143SEric W. Biederman sock_release(sock);
1382789a4a2cSJames Chapman *sockp = NULL;
1383789a4a2cSJames Chapman }
1384789a4a2cSJames Chapman
1385789a4a2cSJames Chapman return err;
1386789a4a2cSJames Chapman }
1387789a4a2cSJames Chapman
l2tp_tunnel_create(int fd,int version,u32 tunnel_id,u32 peer_tunnel_id,struct l2tp_tunnel_cfg * cfg,struct l2tp_tunnel ** tunnelp)1388c9ccd4c6STom Parkin int l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id,
1389c0235fb3STom Parkin struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
1390fd558d18SJames Chapman {
1391fd558d18SJames Chapman struct l2tp_tunnel *tunnel = NULL;
1392fd558d18SJames Chapman int err;
13930d76751fSJames Chapman enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
1394fd558d18SJames Chapman
13950febc7b3STom Parkin if (cfg)
13960d76751fSJames Chapman encap = cfg->encap;
13970d76751fSJames Chapman
139870c05bfaSTom Parkin tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL);
13990febc7b3STom Parkin if (!tunnel) {
1400fd558d18SJames Chapman err = -ENOMEM;
1401fd558d18SJames Chapman goto err;
1402fd558d18SJames Chapman }
1403fd558d18SJames Chapman
1404fd558d18SJames Chapman tunnel->version = version;
1405fd558d18SJames Chapman tunnel->tunnel_id = tunnel_id;
1406fd558d18SJames Chapman tunnel->peer_tunnel_id = peer_tunnel_id;
1407fd558d18SJames Chapman
1408fd558d18SJames Chapman tunnel->magic = L2TP_TUNNEL_MAGIC;
1409fd558d18SJames Chapman sprintf(&tunnel->name[0], "tunl %u", tunnel_id);
141007b8ca37STom Parkin spin_lock_init(&tunnel->hlist_lock);
1411f3c66d4eSGuillaume Nault tunnel->acpt_newsess = true;
1412fd558d18SJames Chapman
14130d76751fSJames Chapman tunnel->encap = encap;
1414fd558d18SJames Chapman
1415d00fa9adSJames Chapman refcount_set(&tunnel->ref_count, 1);
1416d00fa9adSJames Chapman tunnel->fd = fd;
1417d00fa9adSJames Chapman
1418f8ccac0eSTom Parkin /* Init delete workqueue struct */
1419f8ccac0eSTom Parkin INIT_WORK(&tunnel->del_work, l2tp_tunnel_del_work);
1420f8ccac0eSTom Parkin
1421fd558d18SJames Chapman INIT_LIST_HEAD(&tunnel->list);
1422fd558d18SJames Chapman
1423fd558d18SJames Chapman err = 0;
1424fd558d18SJames Chapman err:
1425fd558d18SJames Chapman if (tunnelp)
1426fd558d18SJames Chapman *tunnelp = tunnel;
1427fd558d18SJames Chapman
1428fd558d18SJames Chapman return err;
1429fd558d18SJames Chapman }
1430fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
1431fd558d18SJames Chapman
l2tp_validate_socket(const struct sock * sk,const struct net * net,enum l2tp_encap_type encap)14326b9f3423SGuillaume Nault static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
14336b9f3423SGuillaume Nault enum l2tp_encap_type encap)
14346b9f3423SGuillaume Nault {
14356b9f3423SGuillaume Nault if (!net_eq(sock_net(sk), net))
14366b9f3423SGuillaume Nault return -EINVAL;
14376b9f3423SGuillaume Nault
14386b9f3423SGuillaume Nault if (sk->sk_type != SOCK_DGRAM)
14396b9f3423SGuillaume Nault return -EPROTONOSUPPORT;
14406b9f3423SGuillaume Nault
1441d9a81a22SEric Dumazet if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
1442d9a81a22SEric Dumazet return -EPROTONOSUPPORT;
1443d9a81a22SEric Dumazet
14446b9f3423SGuillaume Nault if ((encap == L2TP_ENCAPTYPE_UDP && sk->sk_protocol != IPPROTO_UDP) ||
14456b9f3423SGuillaume Nault (encap == L2TP_ENCAPTYPE_IP && sk->sk_protocol != IPPROTO_L2TP))
14466b9f3423SGuillaume Nault return -EPROTONOSUPPORT;
14476b9f3423SGuillaume Nault
14486b9f3423SGuillaume Nault if (sk->sk_user_data)
14496b9f3423SGuillaume Nault return -EBUSY;
14506b9f3423SGuillaume Nault
14516b9f3423SGuillaume Nault return 0;
14526b9f3423SGuillaume Nault }
14536b9f3423SGuillaume Nault
l2tp_tunnel_register(struct l2tp_tunnel * tunnel,struct net * net,struct l2tp_tunnel_cfg * cfg)14546b9f3423SGuillaume Nault int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14556b9f3423SGuillaume Nault struct l2tp_tunnel_cfg *cfg)
14566b9f3423SGuillaume Nault {
1457c4d48a58SCong Wang struct l2tp_net *pn = l2tp_pernet(net);
1458c4d48a58SCong Wang u32 tunnel_id = tunnel->tunnel_id;
14596b9f3423SGuillaume Nault struct socket *sock;
14606b9f3423SGuillaume Nault struct sock *sk;
14616b9f3423SGuillaume Nault int ret;
14626b9f3423SGuillaume Nault
1463c4d48a58SCong Wang spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
1464c4d48a58SCong Wang ret = idr_alloc_u32(&pn->l2tp_tunnel_idr, NULL, &tunnel_id, tunnel_id,
1465c4d48a58SCong Wang GFP_ATOMIC);
1466c4d48a58SCong Wang spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
1467c4d48a58SCong Wang if (ret)
1468c4d48a58SCong Wang return ret == -ENOSPC ? -EEXIST : ret;
1469c4d48a58SCong Wang
14706b9f3423SGuillaume Nault if (tunnel->fd < 0) {
14716b9f3423SGuillaume Nault ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id,
14726b9f3423SGuillaume Nault tunnel->peer_tunnel_id, cfg,
14736b9f3423SGuillaume Nault &sock);
14746b9f3423SGuillaume Nault if (ret < 0)
14756b9f3423SGuillaume Nault goto err;
14766b9f3423SGuillaume Nault } else {
14776b9f3423SGuillaume Nault sock = sockfd_lookup(tunnel->fd, &ret);
14786b9f3423SGuillaume Nault if (!sock)
14796b9f3423SGuillaume Nault goto err;
1480b68777d5SJakub Sitnicki }
14816b9f3423SGuillaume Nault
1482b68777d5SJakub Sitnicki sk = sock->sk;
14830b2c5972SCong Wang lock_sock(sk);
1484af295e85SJakub Sitnicki write_lock_bh(&sk->sk_callback_lock);
1485b68777d5SJakub Sitnicki ret = l2tp_validate_socket(sk, net, tunnel->encap);
1486b9fb10d1SEric Dumazet if (ret < 0)
1487af295e85SJakub Sitnicki goto err_inval_sock;
1488af295e85SJakub Sitnicki rcu_assign_sk_user_data(sk, tunnel);
1489af295e85SJakub Sitnicki write_unlock_bh(&sk->sk_callback_lock);
14906b9f3423SGuillaume Nault
14916b9f3423SGuillaume Nault if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
14926b9f3423SGuillaume Nault struct udp_tunnel_sock_cfg udp_cfg = {
14936b9f3423SGuillaume Nault .sk_user_data = tunnel,
14946b9f3423SGuillaume Nault .encap_type = UDP_ENCAP_L2TPINUDP,
14956b9f3423SGuillaume Nault .encap_rcv = l2tp_udp_encap_recv,
14966b9f3423SGuillaume Nault .encap_destroy = l2tp_udp_encap_destroy,
14976b9f3423SGuillaume Nault };
14986b9f3423SGuillaume Nault
14996b9f3423SGuillaume Nault setup_udp_tunnel_sock(net, sock, &udp_cfg);
15006b9f3423SGuillaume Nault }
15016b9f3423SGuillaume Nault
15026b9f3423SGuillaume Nault tunnel->old_sk_destruct = sk->sk_destruct;
15036b9f3423SGuillaume Nault sk->sk_destruct = &l2tp_tunnel_destruct;
15046b9f3423SGuillaume Nault sk->sk_allocation = GFP_ATOMIC;
15050b2c5972SCong Wang release_sock(sk);
15060b2c5972SCong Wang
15070b2c5972SCong Wang sock_hold(sk);
15080b2c5972SCong Wang tunnel->sock = sk;
15090b2c5972SCong Wang tunnel->l2tp_net = net;
15100b2c5972SCong Wang
15110b2c5972SCong Wang spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
15120b2c5972SCong Wang idr_replace(&pn->l2tp_tunnel_idr, tunnel, tunnel->tunnel_id);
15130b2c5972SCong Wang spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
15146b9f3423SGuillaume Nault
15156b7bdcd7STom Parkin trace_register_tunnel(tunnel);
15166b7bdcd7STom Parkin
15176b9f3423SGuillaume Nault if (tunnel->fd >= 0)
15186b9f3423SGuillaume Nault sockfd_put(sock);
15196b9f3423SGuillaume Nault
15206b9f3423SGuillaume Nault return 0;
15216b9f3423SGuillaume Nault
1522af295e85SJakub Sitnicki err_inval_sock:
1523af295e85SJakub Sitnicki write_unlock_bh(&sk->sk_callback_lock);
1524b9fb10d1SEric Dumazet release_sock(sk);
1525af295e85SJakub Sitnicki
1526f6cd651bSGuillaume Nault if (tunnel->fd < 0)
1527f6cd651bSGuillaume Nault sock_release(sock);
1528f6cd651bSGuillaume Nault else
15296b9f3423SGuillaume Nault sockfd_put(sock);
15306b9f3423SGuillaume Nault err:
1531c4d48a58SCong Wang l2tp_tunnel_remove(net, tunnel);
15326b9f3423SGuillaume Nault return ret;
15336b9f3423SGuillaume Nault }
15346b9f3423SGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_tunnel_register);
15356b9f3423SGuillaume Nault
1536309795f4SJames Chapman /* This function is used by the netlink TUNNEL_DELETE command.
1537309795f4SJames Chapman */
l2tp_tunnel_delete(struct l2tp_tunnel * tunnel)153862b982eeSSabrina Dubroca void l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
1539309795f4SJames Chapman {
154062b982eeSSabrina Dubroca if (!test_and_set_bit(0, &tunnel->dead)) {
15416b7bdcd7STom Parkin trace_delete_tunnel(tunnel);
154206a15f51SAlexander Couzens l2tp_tunnel_inc_refcount(tunnel);
154362b982eeSSabrina Dubroca queue_work(l2tp_wq, &tunnel->del_work);
154406a15f51SAlexander Couzens }
1545309795f4SJames Chapman }
1546309795f4SJames Chapman EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
1547309795f4SJames Chapman
l2tp_session_delete(struct l2tp_session * session)1548628703f5STom Parkin void l2tp_session_delete(struct l2tp_session *session)
1549309795f4SJames Chapman {
1550b228a940SGuillaume Nault if (test_and_set_bit(0, &session->dead))
1551628703f5STom Parkin return;
1552b228a940SGuillaume Nault
15536b7bdcd7STom Parkin trace_delete_session(session);
1554b2aecfe8STom Parkin l2tp_session_unhash(session);
15554c6e2fd3STom Parkin l2tp_session_queue_purge(session);
15560febc7b3STom Parkin if (session->session_close)
1557309795f4SJames Chapman (*session->session_close)(session);
1558a4346210SGuillaume Nault
1559309795f4SJames Chapman l2tp_session_dec_refcount(session);
1560309795f4SJames Chapman }
1561309795f4SJames Chapman EXPORT_SYMBOL_GPL(l2tp_session_delete);
1562309795f4SJames Chapman
1563f7faffa3SJames Chapman /* We come here whenever a session's send_seq, cookie_len or
156462e7b6a5SLorenzo Bianconi * l2specific_type parameters are set.
1565f7faffa3SJames Chapman */
l2tp_session_set_header_len(struct l2tp_session * session,int version)1566bb5016eaSGuillaume Nault void l2tp_session_set_header_len(struct l2tp_session *session, int version)
1567f7faffa3SJames Chapman {
1568f7faffa3SJames Chapman if (version == L2TP_HDR_VER_2) {
1569f7faffa3SJames Chapman session->hdr_len = 6;
1570f7faffa3SJames Chapman if (session->send_seq)
1571f7faffa3SJames Chapman session->hdr_len += 4;
1572f7faffa3SJames Chapman } else {
157362e7b6a5SLorenzo Bianconi session->hdr_len = 4 + session->cookie_len;
157462e7b6a5SLorenzo Bianconi session->hdr_len += l2tp_get_l2specific_len(session);
15750d76751fSJames Chapman if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP)
15760d76751fSJames Chapman session->hdr_len += 4;
1577f7faffa3SJames Chapman }
1578f7faffa3SJames Chapman }
1579bb5016eaSGuillaume Nault EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
1580f7faffa3SJames Chapman
l2tp_session_create(int priv_size,struct l2tp_tunnel * tunnel,u32 session_id,u32 peer_session_id,struct l2tp_session_cfg * cfg)1581c0235fb3STom Parkin struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id,
1582c0235fb3STom Parkin u32 peer_session_id, struct l2tp_session_cfg *cfg)
1583fd558d18SJames Chapman {
1584fd558d18SJames Chapman struct l2tp_session *session;
1585fd558d18SJames Chapman
158670c05bfaSTom Parkin session = kzalloc(sizeof(*session) + priv_size, GFP_KERNEL);
15870febc7b3STom Parkin if (session) {
1588fd558d18SJames Chapman session->magic = L2TP_SESSION_MAGIC;
1589fd558d18SJames Chapman session->tunnel = tunnel;
1590fd558d18SJames Chapman
1591fd558d18SJames Chapman session->session_id = session_id;
1592fd558d18SJames Chapman session->peer_session_id = peer_session_id;
1593d301e325SJames Chapman session->nr = 0;
15948a1631d5SJames Chapman if (tunnel->version == L2TP_HDR_VER_2)
15958a1631d5SJames Chapman session->nr_max = 0xffff;
15968a1631d5SJames Chapman else
15978a1631d5SJames Chapman session->nr_max = 0xffffff;
15988a1631d5SJames Chapman session->nr_window_size = session->nr_max / 2;
1599a0dbd822SJames Chapman session->nr_oos_count_max = 4;
1600a0dbd822SJames Chapman
1601a0dbd822SJames Chapman /* Use NR of first received packet */
1602a0dbd822SJames Chapman session->reorder_skip = 1;
1603fd558d18SJames Chapman
1604fd558d18SJames Chapman sprintf(&session->name[0], "sess %u/%u",
1605fd558d18SJames Chapman tunnel->tunnel_id, session->session_id);
1606fd558d18SJames Chapman
1607fd558d18SJames Chapman skb_queue_head_init(&session->reorder_q);
1608fd558d18SJames Chapman
1609fd558d18SJames Chapman INIT_HLIST_NODE(&session->hlist);
1610f7faffa3SJames Chapman INIT_HLIST_NODE(&session->global_hlist);
1611fd558d18SJames Chapman
1612fd558d18SJames Chapman if (cfg) {
1613f7faffa3SJames Chapman session->pwtype = cfg->pw_type;
1614fd558d18SJames Chapman session->send_seq = cfg->send_seq;
1615fd558d18SJames Chapman session->recv_seq = cfg->recv_seq;
1616fd558d18SJames Chapman session->lns_mode = cfg->lns_mode;
1617f7faffa3SJames Chapman session->reorder_timeout = cfg->reorder_timeout;
1618f7faffa3SJames Chapman session->l2specific_type = cfg->l2specific_type;
1619f7faffa3SJames Chapman session->cookie_len = cfg->cookie_len;
1620f7faffa3SJames Chapman memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len);
1621f7faffa3SJames Chapman session->peer_cookie_len = cfg->peer_cookie_len;
1622f7faffa3SJames Chapman memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len);
1623fd558d18SJames Chapman }
1624fd558d18SJames Chapman
1625f7faffa3SJames Chapman l2tp_session_set_header_len(session, tunnel->version);
1626f7faffa3SJames Chapman
16279ee369a4SGuillaume Nault refcount_set(&session->ref_count, 1);
16289ee369a4SGuillaume Nault
1629fd558d18SJames Chapman return session;
1630fd558d18SJames Chapman }
1631dbdbc73bSGuillaume Nault
1632dbdbc73bSGuillaume Nault return ERR_PTR(-ENOMEM);
1633dbdbc73bSGuillaume Nault }
1634fd558d18SJames Chapman EXPORT_SYMBOL_GPL(l2tp_session_create);
1635fd558d18SJames Chapman
1636fd558d18SJames Chapman /*****************************************************************************
1637fd558d18SJames Chapman * Init and cleanup
1638fd558d18SJames Chapman *****************************************************************************/
1639fd558d18SJames Chapman
l2tp_init_net(struct net * net)1640fd558d18SJames Chapman static __net_init int l2tp_init_net(struct net *net)
1641fd558d18SJames Chapman {
1642e773aaffSJiri Pirko struct l2tp_net *pn = net_generic(net, l2tp_net_id);
1643f7faffa3SJames Chapman int hash;
1644fd558d18SJames Chapman
1645c4d48a58SCong Wang idr_init(&pn->l2tp_tunnel_idr);
1646c4d48a58SCong Wang spin_lock_init(&pn->l2tp_tunnel_idr_lock);
1647fd558d18SJames Chapman
1648f7faffa3SJames Chapman for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
1649f7faffa3SJames Chapman INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
1650f7faffa3SJames Chapman
1651e02d494dSJames Chapman spin_lock_init(&pn->l2tp_session_hlist_lock);
1652f7faffa3SJames Chapman
1653fd558d18SJames Chapman return 0;
1654fd558d18SJames Chapman }
1655fd558d18SJames Chapman
l2tp_exit_net(struct net * net)1656167eb17eSTom Parkin static __net_exit void l2tp_exit_net(struct net *net)
1657167eb17eSTom Parkin {
1658167eb17eSTom Parkin struct l2tp_net *pn = l2tp_pernet(net);
1659167eb17eSTom Parkin struct l2tp_tunnel *tunnel = NULL;
1660c4d48a58SCong Wang unsigned long tunnel_id, tmp;
16611e7af3b2SVasily Averin int hash;
1662167eb17eSTom Parkin
1663167eb17eSTom Parkin rcu_read_lock_bh();
1664c4d48a58SCong Wang idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
1665c4d48a58SCong Wang if (tunnel)
16664dc12ffeSJiri Slaby l2tp_tunnel_delete(tunnel);
1667167eb17eSTom Parkin }
1668167eb17eSTom Parkin rcu_read_unlock_bh();
16692f86953eSSabrina Dubroca
1670638a3a1eSYueHaibing if (l2tp_wq)
16712f86953eSSabrina Dubroca flush_workqueue(l2tp_wq);
16722f86953eSSabrina Dubroca rcu_barrier();
16731e7af3b2SVasily Averin
16741e7af3b2SVasily Averin for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
16751e7af3b2SVasily Averin WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash]));
1676c4d48a58SCong Wang idr_destroy(&pn->l2tp_tunnel_idr);
1677167eb17eSTom Parkin }
1678167eb17eSTom Parkin
1679fd558d18SJames Chapman static struct pernet_operations l2tp_net_ops = {
1680fd558d18SJames Chapman .init = l2tp_init_net,
1681167eb17eSTom Parkin .exit = l2tp_exit_net,
1682fd558d18SJames Chapman .id = &l2tp_net_id,
1683fd558d18SJames Chapman .size = sizeof(struct l2tp_net),
1684fd558d18SJames Chapman };
1685fd558d18SJames Chapman
l2tp_init(void)1686fd558d18SJames Chapman static int __init l2tp_init(void)
1687fd558d18SJames Chapman {
1688fd558d18SJames Chapman int rc = 0;
1689fd558d18SJames Chapman
1690fd558d18SJames Chapman rc = register_pernet_device(&l2tp_net_ops);
1691fd558d18SJames Chapman if (rc)
1692fd558d18SJames Chapman goto out;
1693fd558d18SJames Chapman
169459ff3eb6SZhangZhen l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
1695f8ccac0eSTom Parkin if (!l2tp_wq) {
1696f8ccac0eSTom Parkin pr_err("alloc_workqueue failed\n");
169767e04c29SWANG Cong unregister_pernet_device(&l2tp_net_ops);
1698f8ccac0eSTom Parkin rc = -ENOMEM;
1699f8ccac0eSTom Parkin goto out;
1700f8ccac0eSTom Parkin }
1701f8ccac0eSTom Parkin
1702a4ca44faSJoe Perches pr_info("L2TP core driver, %s\n", L2TP_DRV_VERSION);
1703fd558d18SJames Chapman
1704fd558d18SJames Chapman out:
1705fd558d18SJames Chapman return rc;
1706fd558d18SJames Chapman }
1707fd558d18SJames Chapman
l2tp_exit(void)1708fd558d18SJames Chapman static void __exit l2tp_exit(void)
1709fd558d18SJames Chapman {
1710fd558d18SJames Chapman unregister_pernet_device(&l2tp_net_ops);
1711f8ccac0eSTom Parkin if (l2tp_wq) {
1712f8ccac0eSTom Parkin destroy_workqueue(l2tp_wq);
1713f8ccac0eSTom Parkin l2tp_wq = NULL;
1714f8ccac0eSTom Parkin }
1715fd558d18SJames Chapman }
1716fd558d18SJames Chapman
1717fd558d18SJames Chapman module_init(l2tp_init);
1718fd558d18SJames Chapman module_exit(l2tp_exit);
1719fd558d18SJames Chapman
1720fd558d18SJames Chapman MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
1721fd558d18SJames Chapman MODULE_DESCRIPTION("L2TP core");
1722fd558d18SJames Chapman MODULE_LICENSE("GPL");
1723fd558d18SJames Chapman MODULE_VERSION(L2TP_DRV_VERSION);
1724