Blame view

net/l2tp/l2tp_ip.c 15.7 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
20dcb1107   Tom Parkin   l2tp: cleanup com...
2
  /* L2TPv3 IP encapsulation support
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
3
4
   *
   * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
5
   */
a4ca44fa5   Joe Perches   net: l2tp: Standa...
6
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
72fb96e7b   Eric Dumazet   l2tp: do not use ...
7
  #include <asm/ioctls.h>
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
8
9
10
11
12
13
14
15
16
17
18
19
  #include <linux/icmp.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/random.h>
  #include <linux/socket.h>
  #include <linux/l2tp.h>
  #include <linux/in.h>
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/icmp.h>
  #include <net/udp.h>
  #include <net/inet_common.h>
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
20
21
22
23
24
25
26
27
28
  #include <net/tcp_states.h>
  #include <net/protocol.h>
  #include <net/xfrm.h>
  
  #include "l2tp_core.h"
  
  struct l2tp_ip_sock {
  	/* inet_sock has to be the first member of l2tp_ip_sock */
  	struct inet_sock	inet;
c8657fd50   James Chapman   l2tp: remove unus...
29
30
  	u32			conn_id;
  	u32			peer_conn_id;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
31
32
33
34
35
36
37
38
39
40
  };
  
  static DEFINE_RWLOCK(l2tp_ip_lock);
  static struct hlist_head l2tp_ip_table;
  static struct hlist_head l2tp_ip_bind_table;
  
  static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk)
  {
  	return (struct l2tp_ip_sock *)sk;
  }
a9b2dff80   Guillaume Nault   l2tp: take remote...
41
42
  static struct sock *__l2tp_ip_bind_lookup(const struct net *net, __be32 laddr,
  					  __be32 raddr, int dif, u32 tunnel_id)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
43
  {
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
44
  	struct sock *sk;
b67bfe0d4   Sasha Levin   hlist: drop the n...
45
  	sk_for_each_bound(sk, &l2tp_ip_bind_table) {
bb39b0bdc   Guillaume Nault   l2tp: make __l2tp...
46
47
  		const struct l2tp_ip_sock *l2tp = l2tp_ip_sk(sk);
  		const struct inet_sock *inet = inet_sk(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
48

c5fdae044   Guillaume Nault   l2tp: rework sock...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  		if (!net_eq(sock_net(sk), net))
  			continue;
  
  		if (sk->sk_bound_dev_if && dif && sk->sk_bound_dev_if != dif)
  			continue;
  
  		if (inet->inet_rcv_saddr && laddr &&
  		    inet->inet_rcv_saddr != laddr)
  			continue;
  
  		if (inet->inet_daddr && raddr && inet->inet_daddr != raddr)
  			continue;
  
  		if (l2tp->conn_id != tunnel_id)
  			continue;
  
  		goto found;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
66
67
68
69
70
71
  	}
  
  	sk = NULL;
  found:
  	return sk;
  }
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  /* When processing receive frames, there are two cases to
   * consider. Data frames consist of a non-zero session-id and an
   * optional cookie. Control frames consist of a regular L2TP header
   * preceded by 32-bits of zeros.
   *
   * L2TPv3 Session Header Over IP
   *
   *  0                   1                   2                   3
   *  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
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |                           Session ID                          |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |               Cookie (optional, maximum 64 bits)...
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *                                                                 |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * L2TPv3 Control Message Header Over IP
   *
   *  0                   1                   2                   3
   *  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
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |                      (32 bits of zeros)                       |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |                     Control Connection ID                     |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |               Ns              |               Nr              |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * All control frames are passed to userspace.
   */
  static int l2tp_ip_recv(struct sk_buff *skb)
  {
9d6ddb199   David S. Miller   l2tp: Make ipv4 p...
107
  	struct net *net = dev_net(skb->dev);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
108
109
110
111
112
113
  	struct sock *sk;
  	u32 session_id;
  	u32 tunnel_id;
  	unsigned char *ptr, *optr;
  	struct l2tp_session *session;
  	struct l2tp_tunnel *tunnel = NULL;
8f7dc9ae4   Guillaume Nault   l2tp: don't use l...
114
  	struct iphdr *iph;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
115

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
116
117
  	if (!pskb_may_pull(skb, 4))
  		goto discard;
5745b8232   Haishuang Yan   ipv4: l2tp: fix a...
118
  	/* Point to L2TP header */
95075150d   Tom Parkin   l2tp: avoid multi...
119
120
  	optr = skb->data;
  	ptr = skb->data;
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
121
  	session_id = ntohl(*((__be32 *)ptr));
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
122
123
124
125
126
127
128
129
130
131
132
133
  	ptr += 4;
  
  	/* RFC3931: L2TP/IP packets have the first 4 bytes containing
  	 * the session_id. If it is 0, the packet is a L2TP control
  	 * frame and the session_id value can be discarded.
  	 */
  	if (session_id == 0) {
  		__skb_pull(skb, 4);
  		goto pass_up;
  	}
  
  	/* Ok, this is a data packet. Lookup the session. */
01e28b921   Guillaume Nault   l2tp: split l2tp_...
134
  	session = l2tp_session_get(net, session_id);
61b9a0477   Guillaume Nault   l2tp: fix race in...
135
  	if (!session)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
136
137
138
  		goto discard;
  
  	tunnel = session->tunnel;
61b9a0477   Guillaume Nault   l2tp: fix race in...
139
140
  	if (!tunnel)
  		goto discard_sess;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
141

4522a70db   Jacob Wen   l2tp: fix reading...
142
143
  	if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr))
  		goto discard_sess;
2b139e6b1   Guillaume Nault   l2tp: remove ->re...
144
  	l2tp_recv_common(session, skb, ptr, optr, 0, skb->len);
61b9a0477   Guillaume Nault   l2tp: fix race in...
145
  	l2tp_session_dec_refcount(session);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
146
147
148
149
150
151
152
153
154
155
  
  	return 0;
  
  pass_up:
  	/* Get the tunnel_id from the L2TP header */
  	if (!pskb_may_pull(skb, 12))
  		goto discard;
  
  	if ((skb->data[0] & 0xc0) != 0xc0)
  		goto discard;
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
156
  	tunnel_id = ntohl(*(__be32 *)&skb->data[4]);
8f7dc9ae4   Guillaume Nault   l2tp: don't use l...
157
158
159
160
161
162
  	iph = (struct iphdr *)skb_network_header(skb);
  
  	read_lock_bh(&l2tp_ip_lock);
  	sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr, inet_iif(skb),
  				   tunnel_id);
  	if (!sk) {
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
163
  		read_unlock_bh(&l2tp_ip_lock);
8f7dc9ae4   Guillaume Nault   l2tp: don't use l...
164
  		goto discard;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
165
  	}
8f7dc9ae4   Guillaume Nault   l2tp: don't use l...
166
167
  	sock_hold(sk);
  	read_unlock_bh(&l2tp_ip_lock);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
168

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
169
170
  	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
  		goto discard_put;
895b5c9f2   Florian Westphal   netfilter: drop b...
171
  	nf_reset_ct(skb);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
172
173
  
  	return sk_receive_skb(sk, skb, 1);
61b9a0477   Guillaume Nault   l2tp: fix race in...
174
  discard_sess:
61b9a0477   Guillaume Nault   l2tp: fix race in...
175
176
  	l2tp_session_dec_refcount(session);
  	goto discard;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
177
178
179
180
181
182
183
  discard_put:
  	sock_put(sk);
  
  discard:
  	kfree_skb(skb);
  	return 0;
  }
02c71b144   Eric Dumazet   l2tp: do not use ...
184
  static int l2tp_ip_hash(struct sock *sk)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
185
  {
02c71b144   Eric Dumazet   l2tp: do not use ...
186
187
188
189
190
191
192
  	if (sk_unhashed(sk)) {
  		write_lock_bh(&l2tp_ip_lock);
  		sk_add_node(sk, &l2tp_ip_table);
  		write_unlock_bh(&l2tp_ip_lock);
  	}
  	return 0;
  }
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
193

02c71b144   Eric Dumazet   l2tp: do not use ...
194
195
196
197
  static void l2tp_ip_unhash(struct sock *sk)
  {
  	if (sk_unhashed(sk))
  		return;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
198
  	write_lock_bh(&l2tp_ip_lock);
02c71b144   Eric Dumazet   l2tp: do not use ...
199
  	sk_del_node_init(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
200
  	write_unlock_bh(&l2tp_ip_lock);
02c71b144   Eric Dumazet   l2tp: do not use ...
201
202
203
204
205
206
  }
  
  static int l2tp_ip_open(struct sock *sk)
  {
  	/* Prevent autobind. We don't have ports. */
  	inet_sk(sk)->inet_num = IPPROTO_L2TP;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
207

02c71b144   Eric Dumazet   l2tp: do not use ...
208
  	l2tp_ip_hash(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
209
210
211
212
213
214
215
  	return 0;
  }
  
  static void l2tp_ip_close(struct sock *sk, long timeout)
  {
  	write_lock_bh(&l2tp_ip_lock);
  	hlist_del_init(&sk->sk_bind_node);
d1f224ae1   James Chapman   l2tp: fix refcoun...
216
  	sk_del_node_init(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
217
218
219
220
221
222
  	write_unlock_bh(&l2tp_ip_lock);
  	sk_common_release(sk);
  }
  
  static void l2tp_ip_destroy_sock(struct sock *sk)
  {
45faeff11   Tom Parkin   l2tp: make magic ...
223
  	struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
224
225
226
227
  	struct sk_buff *skb;
  
  	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
  		kfree_skb(skb);
d00fa9adc   James Chapman   l2tp: fix races w...
228
229
  	if (tunnel)
  		l2tp_tunnel_delete(tunnel);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
230
231
232
233
234
  }
  
  static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
  	struct inet_sock *inet = inet_sk(sk);
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
235
  	struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *)uaddr;
9d6ddb199   David S. Miller   l2tp: Make ipv4 p...
236
  	struct net *net = sock_net(sk);
c51ce4973   James Chapman   l2tp: fix oops in...
237
  	int ret;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
238
  	int chk_addr_ret;
c51ce4973   James Chapman   l2tp: fix oops in...
239
240
241
242
  	if (addr_len < sizeof(struct sockaddr_l2tpip))
  		return -EINVAL;
  	if (addr->l2tp_family != AF_INET)
  		return -EINVAL;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
243
  	lock_sock(sk);
d5e3a1909   Guillaume Nault   l2tp: fix racy so...
244
245
  
  	ret = -EINVAL;
32c231164   Guillaume Nault   l2tp: fix racy SO...
246
247
  	if (!sock_flag(sk, SOCK_ZAPPED))
  		goto out;
8cf2f7045   Guillaume Nault   l2tp: remove redu...
248
  	if (sk->sk_state != TCP_CLOSE)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
249
  		goto out;
9d6ddb199   David S. Miller   l2tp: Make ipv4 p...
250
  	chk_addr_ret = inet_addr_type(net, addr->l2tp_addr.s_addr);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
251
252
253
254
  	ret = -EADDRNOTAVAIL;
  	if (addr->l2tp_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
  	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
  		goto out;
95075150d   Tom Parkin   l2tp: avoid multi...
255
256
257
258
  	if (addr->l2tp_addr.s_addr) {
  		inet->inet_rcv_saddr = addr->l2tp_addr.s_addr;
  		inet->inet_saddr = addr->l2tp_addr.s_addr;
  	}
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
259
260
  	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
  		inet->inet_saddr = 0;  /* Use device */
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
261

d5e3a1909   Guillaume Nault   l2tp: fix racy so...
262
  	write_lock_bh(&l2tp_ip_lock);
a9b2dff80   Guillaume Nault   l2tp: take remote...
263
  	if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, 0,
d5e3a1909   Guillaume Nault   l2tp: fix racy so...
264
265
266
267
268
269
270
  				  sk->sk_bound_dev_if, addr->l2tp_conn_id)) {
  		write_unlock_bh(&l2tp_ip_lock);
  		ret = -EADDRINUSE;
  		goto out;
  	}
  
  	sk_dst_reset(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
271
  	l2tp_ip_sk(sk)->conn_id = addr->l2tp_conn_id;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
272
273
274
  	sk_add_bind_node(sk, &l2tp_ip_bind_table);
  	sk_del_node_init(sk);
  	write_unlock_bh(&l2tp_ip_lock);
d5e3a1909   Guillaume Nault   l2tp: fix racy so...
275

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
276
  	ret = 0;
c51ce4973   James Chapman   l2tp: fix oops in...
277
  	sock_reset_flag(sk, SOCK_ZAPPED);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
278
279
280
281
  out:
  	release_sock(sk);
  
  	return ret;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
282
283
284
285
  }
  
  static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
286
  	struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
de3c7a182   James Chapman   l2tp: Use ip4_dat...
287
  	int rc;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
288

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
289
  	if (addr_len < sizeof(*lsa))
de3c7a182   James Chapman   l2tp: Use ip4_dat...
290
  		return -EINVAL;
2f16270f4   David S. Miller   l2tp: Fix locking...
291

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
292
  	if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
de3c7a182   James Chapman   l2tp: Use ip4_dat...
293
  		return -EINVAL;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
294

de3c7a182   James Chapman   l2tp: Use ip4_dat...
295
  	lock_sock(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
296

0382a25af   Guillaume Nault   l2tp: lock socket...
297
298
299
300
301
302
303
304
305
  	/* Must bind first - autobinding does not work */
  	if (sock_flag(sk, SOCK_ZAPPED)) {
  		rc = -EINVAL;
  		goto out_sk;
  	}
  
  	rc = __ip4_datagram_connect(sk, uaddr, addr_len);
  	if (rc < 0)
  		goto out_sk;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
306
  	l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
307
308
309
310
  	write_lock_bh(&l2tp_ip_lock);
  	hlist_del_init(&sk->sk_bind_node);
  	sk_add_bind_node(sk, &l2tp_ip_bind_table);
  	write_unlock_bh(&l2tp_ip_lock);
0382a25af   Guillaume Nault   l2tp: lock socket...
311
  out_sk:
2f16270f4   David S. Miller   l2tp: Fix locking...
312
  	release_sock(sk);
0382a25af   Guillaume Nault   l2tp: lock socket...
313

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
314
315
  	return rc;
  }
c51ce4973   James Chapman   l2tp: fix oops in...
316
317
318
319
  static int l2tp_ip_disconnect(struct sock *sk, int flags)
  {
  	if (sock_flag(sk, SOCK_ZAPPED))
  		return 0;
286c72dea   Eric Dumazet   udp: must lock th...
320
  	return __udp_disconnect(sk, flags);
c51ce4973   James Chapman   l2tp: fix oops in...
321
  }
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
322
  static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
9b2c45d47   Denys Vlasenko   net: make getname...
323
  			   int peer)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  {
  	struct sock *sk		= sock->sk;
  	struct inet_sock *inet	= inet_sk(sk);
  	struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk);
  	struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
  
  	memset(lsa, 0, sizeof(*lsa));
  	lsa->l2tp_family = AF_INET;
  	if (peer) {
  		if (!inet->inet_dport)
  			return -ENOTCONN;
  		lsa->l2tp_conn_id = lsk->peer_conn_id;
  		lsa->l2tp_addr.s_addr = inet->inet_daddr;
  	} else {
  		__be32 addr = inet->inet_rcv_saddr;
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
339

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
340
341
342
343
344
  		if (!addr)
  			addr = inet->inet_saddr;
  		lsa->l2tp_conn_id = lsk->conn_id;
  		lsa->l2tp_addr.s_addr = addr;
  	}
9b2c45d47   Denys Vlasenko   net: make getname...
345
  	return sizeof(*lsa);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
346
347
348
349
350
  }
  
  static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)
  {
  	int rc;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
351
352
353
354
355
356
357
358
  	/* Charge it to the socket, dropping if the queue is full. */
  	rc = sock_queue_rcv_skb(sk, skb);
  	if (rc < 0)
  		goto drop;
  
  	return 0;
  
  drop:
9d6ddb199   David S. Miller   l2tp: Make ipv4 p...
359
  	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
360
  	kfree_skb(skb);
51fb60eb1   Paul Hüber   l2tp: avoid use-a...
361
  	return 0;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
362
363
364
365
366
  }
  
  /* Userspace will call sendmsg() on the tunnel socket to send L2TP
   * control frames.
   */
1b7841404   Ying Xue   net: Remove iocb ...
367
  static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
368
369
370
  {
  	struct sk_buff *skb;
  	int rc;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
371
  	struct inet_sock *inet = inet_sk(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
372
  	struct rtable *rt = NULL;
fdbb0f076   David S. Miller   l2tp: Use cork fl...
373
  	struct flowi4 *fl4;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
374
375
  	int connected = 0;
  	__be32 daddr;
2f16270f4   David S. Miller   l2tp: Fix locking...
376
377
378
  	lock_sock(sk);
  
  	rc = -ENOTCONN;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
379
  	if (sock_flag(sk, SOCK_DEAD))
2f16270f4   David S. Miller   l2tp: Fix locking...
380
  		goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
381
382
383
  
  	/* Get and verify the address. */
  	if (msg->msg_name) {
342dfc306   Steffen Hurrle   net: add build-ti...
384
  		DECLARE_SOCKADDR(struct sockaddr_l2tpip *, lip, msg->msg_name);
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
385

2f16270f4   David S. Miller   l2tp: Fix locking...
386
  		rc = -EINVAL;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
387
  		if (msg->msg_namelen < sizeof(*lip))
2f16270f4   David S. Miller   l2tp: Fix locking...
388
  			goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
389
390
  
  		if (lip->l2tp_family != AF_INET) {
2f16270f4   David S. Miller   l2tp: Fix locking...
391
  			rc = -EAFNOSUPPORT;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
392
  			if (lip->l2tp_family != AF_UNSPEC)
2f16270f4   David S. Miller   l2tp: Fix locking...
393
  				goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
394
395
396
397
  		}
  
  		daddr = lip->l2tp_addr.s_addr;
  	} else {
84768edbb   Sasha Levin   net: l2tp: unlock...
398
  		rc = -EDESTADDRREQ;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
399
  		if (sk->sk_state != TCP_ESTABLISHED)
84768edbb   Sasha Levin   net: l2tp: unlock...
400
  			goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  
  		daddr = inet->inet_daddr;
  		connected = 1;
  	}
  
  	/* Allocate a socket buffer */
  	rc = -ENOMEM;
  	skb = sock_wmalloc(sk, 2 + NET_SKB_PAD + sizeof(struct iphdr) +
  			   4 + len, 0, GFP_KERNEL);
  	if (!skb)
  		goto error;
  
  	/* Reserve space for headers, putting IP header on 4-byte boundary. */
  	skb_reserve(skb, 2 + NET_SKB_PAD);
  	skb_reset_network_header(skb);
  	skb_reserve(skb, sizeof(struct iphdr));
  	skb_reset_transport_header(skb);
  
  	/* Insert 0 session_id */
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
420
  	*((__be32 *)skb_put(skb, 4)) = 0;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
421
422
  
  	/* Copy user data into skb */
6ce8e9ce5   Al Viro   new helper: memcp...
423
  	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
424
425
426
427
  	if (rc < 0) {
  		kfree_skb(skb);
  		goto error;
  	}
fdbb0f076   David S. Miller   l2tp: Use cork fl...
428
  	fl4 = &inet->cork.fl.u.ip4;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
429
  	if (connected)
b71a61ccf   Tom Parkin   l2tp: cleanup whi...
430
  		rt = (struct rtable *)__sk_dst_check(sk, 0);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
431

081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
432
  	rcu_read_lock();
0febc7b3c   Tom Parkin   l2tp: cleanup com...
433
  	if (!rt) {
081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
434
  		const struct ip_options_rcu *inet_opt;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
435

778865a55   David S. Miller   l2tp: Fix inet_op...
436
  		inet_opt = rcu_dereference(inet->inet_opt);
f6d8bd051   Eric Dumazet   inet: add RCU pro...
437

0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
438
  		/* Use correct destination address if we have options. */
f6d8bd051   Eric Dumazet   inet: add RCU pro...
439
440
  		if (inet_opt && inet_opt->opt.srr)
  			daddr = inet_opt->opt.faddr;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
441

78fbfd8a6   David S. Miller   ipv4: Create and ...
442
443
444
445
  		/* If this fails, retransmit mechanism of transport layer will
  		 * keep trying until route appears or the connection times
  		 * itself out.
  		 */
fdbb0f076   David S. Miller   l2tp: Use cork fl...
446
  		rt = ip_route_output_ports(sock_net(sk), fl4, sk,
78fbfd8a6   David S. Miller   ipv4: Create and ...
447
448
449
450
451
452
  					   daddr, inet->inet_saddr,
  					   inet->inet_dport, inet->inet_sport,
  					   sk->sk_protocol, RT_CONN_FLAGS(sk),
  					   sk->sk_bound_dev_if);
  		if (IS_ERR(rt))
  			goto no_route;
4399a4df9   Eric Dumazet   l2tp: fix a race ...
453
  		if (connected) {
081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
454
  			sk_setup_caps(sk, &rt->dst);
4399a4df9   Eric Dumazet   l2tp: fix a race ...
455
456
457
458
  		} else {
  			skb_dst_set(skb, &rt->dst);
  			goto xmit;
  		}
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
459
  	}
081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
460
461
462
463
464
  
  	/* We dont need to clone dst here, it is guaranteed to not disappear.
  	 *  __dev_xmit_skb() might force a refcount if needed.
  	 */
  	skb_dst_set_noref(skb, &rt->dst);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
465

4399a4df9   Eric Dumazet   l2tp: fix a race ...
466
  xmit:
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
467
  	/* Queue the packet to IP for output */
b0270e910   Eric Dumazet   ipv4: add a sock ...
468
  	rc = ip_queue_xmit(sk, skb, &inet->cork.fl);
081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
469
  	rcu_read_unlock();
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
470
471
  
  error:
c8657fd50   James Chapman   l2tp: remove unus...
472
  	if (rc >= 0)
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
473
  		rc = len;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
474

2f16270f4   David S. Miller   l2tp: Fix locking...
475
476
  out:
  	release_sock(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
477
478
479
  	return rc;
  
  no_route:
081b1b1bb   Eric Dumazet   l2tp: fix l2tp_ip...
480
  	rcu_read_unlock();
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
481
482
  	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
  	kfree_skb(skb);
2f16270f4   David S. Miller   l2tp: Fix locking...
483
484
  	rc = -EHOSTUNREACH;
  	goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
485
  }
1b7841404   Ying Xue   net: Remove iocb ...
486
  static int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
487
488
489
  			   size_t len, int noblock, int flags, int *addr_len)
  {
  	struct inet_sock *inet = inet_sk(sk);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
490
491
  	size_t copied = 0;
  	int err = -EOPNOTSUPP;
342dfc306   Steffen Hurrle   net: add build-ti...
492
  	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
493
494
495
496
  	struct sk_buff *skb;
  
  	if (flags & MSG_OOB)
  		goto out;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
497
498
499
500
501
502
503
504
505
  	skb = skb_recv_datagram(sk, flags, noblock, &err);
  	if (!skb)
  		goto out;
  
  	copied = skb->len;
  	if (len < copied) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
506
  	err = skb_copy_datagram_msg(skb, 0, msg, copied);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
507
508
509
510
511
512
513
514
515
516
517
  	if (err)
  		goto done;
  
  	sock_recv_timestamp(msg, sk, skb);
  
  	/* Copy the address. */
  	if (sin) {
  		sin->sin_family = AF_INET;
  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
  		sin->sin_port = 0;
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
bceaa9024   Hannes Frederic Sowa   inet: prevent lea...
518
  		*addr_len = sizeof(*sin);
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
519
520
521
522
523
524
525
526
  	}
  	if (inet->cmsg_flags)
  		ip_cmsg_recv(msg, skb);
  	if (flags & MSG_TRUNC)
  		copied = skb->len;
  done:
  	skb_free_datagram(sk, skb);
  out:
c8657fd50   James Chapman   l2tp: remove unus...
527
  	return err ? err : copied;
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
528
  }
72fb96e7b   Eric Dumazet   l2tp: do not use ...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
  	struct sk_buff *skb;
  	int amount;
  
  	switch (cmd) {
  	case SIOCOUTQ:
  		amount = sk_wmem_alloc_get(sk);
  		break;
  	case SIOCINQ:
  		spin_lock_bh(&sk->sk_receive_queue.lock);
  		skb = skb_peek(&sk->sk_receive_queue);
  		amount = skb ? skb->len : 0;
  		spin_unlock_bh(&sk->sk_receive_queue.lock);
  		break;
  
  	default:
  		return -ENOIOCTLCMD;
  	}
  
  	return put_user(amount, (int __user *)arg);
  }
ca7885dbc   Tom Parkin   l2tp: tweak expor...
551
  EXPORT_SYMBOL_GPL(l2tp_ioctl);
72fb96e7b   Eric Dumazet   l2tp: do not use ...
552

fc130840d   stephen hemminger   l2tp: make local ...
553
  static struct proto l2tp_ip_prot = {
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
554
555
556
557
558
559
  	.name		   = "L2TP/IP",
  	.owner		   = THIS_MODULE,
  	.init		   = l2tp_ip_open,
  	.close		   = l2tp_ip_close,
  	.bind		   = l2tp_ip_bind,
  	.connect	   = l2tp_ip_connect,
c51ce4973   James Chapman   l2tp: fix oops in...
560
  	.disconnect	   = l2tp_ip_disconnect,
72fb96e7b   Eric Dumazet   l2tp: do not use ...
561
  	.ioctl		   = l2tp_ioctl,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
562
563
564
565
566
567
  	.destroy	   = l2tp_ip_destroy_sock,
  	.setsockopt	   = ip_setsockopt,
  	.getsockopt	   = ip_getsockopt,
  	.sendmsg	   = l2tp_ip_sendmsg,
  	.recvmsg	   = l2tp_ip_recvmsg,
  	.backlog_rcv	   = l2tp_ip_backlog_recv,
02c71b144   Eric Dumazet   l2tp: do not use ...
568
569
  	.hash		   = l2tp_ip_hash,
  	.unhash		   = l2tp_ip_unhash,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
570
  	.obj_size	   = sizeof(struct l2tp_ip_sock),
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
571
572
573
574
575
576
577
578
579
580
581
  };
  
  static const struct proto_ops l2tp_ip_ops = {
  	.family		   = PF_INET,
  	.owner		   = THIS_MODULE,
  	.release	   = inet_release,
  	.bind		   = inet_bind,
  	.connect	   = inet_dgram_connect,
  	.socketpair	   = sock_no_socketpair,
  	.accept		   = sock_no_accept,
  	.getname	   = l2tp_ip_getname,
a11e1d432   Linus Torvalds   Revert changes to...
582
  	.poll		   = datagram_poll,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
583
  	.ioctl		   = inet_ioctl,
c7cbdbf29   Arnd Bergmann   net: rework SIOCG...
584
  	.gettstamp	   = sock_gettstamp,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
585
586
587
588
589
590
591
592
  	.listen		   = sock_no_listen,
  	.shutdown	   = inet_shutdown,
  	.setsockopt	   = sock_common_setsockopt,
  	.getsockopt	   = sock_common_getsockopt,
  	.sendmsg	   = inet_sendmsg,
  	.recvmsg	   = sock_common_recvmsg,
  	.mmap		   = sock_no_mmap,
  	.sendpage	   = sock_no_sendpage,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
593
594
595
596
597
598
599
  };
  
  static struct inet_protosw l2tp_ip_protosw = {
  	.type		= SOCK_DGRAM,
  	.protocol	= IPPROTO_L2TP,
  	.prot		= &l2tp_ip_prot,
  	.ops		= &l2tp_ip_ops,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
600
601
602
603
  };
  
  static struct net_protocol l2tp_ip_protocol __read_mostly = {
  	.handler	= l2tp_ip_recv,
9d6ddb199   David S. Miller   l2tp: Make ipv4 p...
604
  	.netns_ok	= 1,
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
605
606
607
608
609
  };
  
  static int __init l2tp_ip_init(void)
  {
  	int err;
a4ca44fa5   Joe Perches   net: l2tp: Standa...
610
611
  	pr_info("L2TP IP encapsulation support (L2TPv3)
  ");
0d76751fa   James Chapman   l2tp: Add L2TPv3 ...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  
  	err = proto_register(&l2tp_ip_prot, 1);
  	if (err != 0)
  		goto out;
  
  	err = inet_add_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
  	if (err)
  		goto out1;
  
  	inet_register_protosw(&l2tp_ip_protosw);
  	return 0;
  
  out1:
  	proto_unregister(&l2tp_ip_prot);
  out:
  	return err;
  }
  
  static void __exit l2tp_ip_exit(void)
  {
  	inet_unregister_protosw(&l2tp_ip_protosw);
  	inet_del_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
  	proto_unregister(&l2tp_ip_prot);
  }
  
  module_init(l2tp_ip_init);
  module_exit(l2tp_ip_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
  MODULE_DESCRIPTION("L2TP over IP");
  MODULE_VERSION("1.0");
e8d34a884   Michal Marek   l2tp: Fix modalia...
644

e9c549998   Lucas De Marchi   Revert wrong fixe...
645
  /* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
e8d34a884   Michal Marek   l2tp: Fix modalia...
646
647
648
   * enums
   */
  MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
163c2e252   stephen hemminger   l2tp: auto load I...
649
  MODULE_ALIAS_NET_PF_PROTO(PF_INET, IPPROTO_L2TP);