xref: /openbmc/linux/net/l2tp/l2tp_ip.c (revision c274af22)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
220dcb110STom Parkin /* L2TPv3 IP encapsulation support
30d76751fSJames Chapman  *
40d76751fSJames Chapman  * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
50d76751fSJames Chapman  */
60d76751fSJames Chapman 
7a4ca44faSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8a4ca44faSJoe Perches 
972fb96e7SEric Dumazet #include <asm/ioctls.h>
100d76751fSJames Chapman #include <linux/icmp.h>
110d76751fSJames Chapman #include <linux/module.h>
120d76751fSJames Chapman #include <linux/skbuff.h>
130d76751fSJames Chapman #include <linux/random.h>
140d76751fSJames Chapman #include <linux/socket.h>
150d76751fSJames Chapman #include <linux/l2tp.h>
160d76751fSJames Chapman #include <linux/in.h>
170d76751fSJames Chapman #include <net/sock.h>
180d76751fSJames Chapman #include <net/ip.h>
190d76751fSJames Chapman #include <net/icmp.h>
200d76751fSJames Chapman #include <net/udp.h>
210d76751fSJames Chapman #include <net/inet_common.h>
220d76751fSJames Chapman #include <net/tcp_states.h>
230d76751fSJames Chapman #include <net/protocol.h>
240d76751fSJames Chapman #include <net/xfrm.h>
250d76751fSJames Chapman 
260d76751fSJames Chapman #include "l2tp_core.h"
270d76751fSJames Chapman 
280d76751fSJames Chapman struct l2tp_ip_sock {
290d76751fSJames Chapman 	/* inet_sock has to be the first member of l2tp_ip_sock */
300d76751fSJames Chapman 	struct inet_sock	inet;
310d76751fSJames Chapman 
32c8657fd5SJames Chapman 	u32			conn_id;
33c8657fd5SJames Chapman 	u32			peer_conn_id;
340d76751fSJames Chapman };
350d76751fSJames Chapman 
360d76751fSJames Chapman static DEFINE_RWLOCK(l2tp_ip_lock);
370d76751fSJames Chapman static struct hlist_head l2tp_ip_table;
380d76751fSJames Chapman static struct hlist_head l2tp_ip_bind_table;
390d76751fSJames Chapman 
l2tp_ip_sk(const struct sock * sk)400d76751fSJames Chapman static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk)
410d76751fSJames Chapman {
420d76751fSJames Chapman 	return (struct l2tp_ip_sock *)sk;
430d76751fSJames Chapman }
440d76751fSJames Chapman 
__l2tp_ip_bind_lookup(const struct net * net,__be32 laddr,__be32 raddr,int dif,u32 tunnel_id)45a9b2dff8SGuillaume Nault static struct sock *__l2tp_ip_bind_lookup(const struct net *net, __be32 laddr,
46a9b2dff8SGuillaume Nault 					  __be32 raddr, int dif, u32 tunnel_id)
470d76751fSJames Chapman {
480d76751fSJames Chapman 	struct sock *sk;
490d76751fSJames Chapman 
50b67bfe0dSSasha Levin 	sk_for_each_bound(sk, &l2tp_ip_bind_table) {
51bb39b0bdSGuillaume Nault 		const struct l2tp_ip_sock *l2tp = l2tp_ip_sk(sk);
52bb39b0bdSGuillaume Nault 		const struct inet_sock *inet = inet_sk(sk);
53ff009403SEric Dumazet 		int bound_dev_if;
540d76751fSJames Chapman 
55c5fdae04SGuillaume Nault 		if (!net_eq(sock_net(sk), net))
56c5fdae04SGuillaume Nault 			continue;
57c5fdae04SGuillaume Nault 
58ff009403SEric Dumazet 		bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
59ff009403SEric Dumazet 		if (bound_dev_if && dif && bound_dev_if != dif)
60c5fdae04SGuillaume Nault 			continue;
61c5fdae04SGuillaume Nault 
62c5fdae04SGuillaume Nault 		if (inet->inet_rcv_saddr && laddr &&
63c5fdae04SGuillaume Nault 		    inet->inet_rcv_saddr != laddr)
64c5fdae04SGuillaume Nault 			continue;
65c5fdae04SGuillaume Nault 
66c5fdae04SGuillaume Nault 		if (inet->inet_daddr && raddr && inet->inet_daddr != raddr)
67c5fdae04SGuillaume Nault 			continue;
68c5fdae04SGuillaume Nault 
69c5fdae04SGuillaume Nault 		if (l2tp->conn_id != tunnel_id)
70c5fdae04SGuillaume Nault 			continue;
71c5fdae04SGuillaume Nault 
720d76751fSJames Chapman 		goto found;
730d76751fSJames Chapman 	}
740d76751fSJames Chapman 
750d76751fSJames Chapman 	sk = NULL;
760d76751fSJames Chapman found:
770d76751fSJames Chapman 	return sk;
780d76751fSJames Chapman }
790d76751fSJames Chapman 
800d76751fSJames Chapman /* When processing receive frames, there are two cases to
810d76751fSJames Chapman  * consider. Data frames consist of a non-zero session-id and an
820d76751fSJames Chapman  * optional cookie. Control frames consist of a regular L2TP header
830d76751fSJames Chapman  * preceded by 32-bits of zeros.
840d76751fSJames Chapman  *
850d76751fSJames Chapman  * L2TPv3 Session Header Over IP
860d76751fSJames Chapman  *
870d76751fSJames Chapman  *  0                   1                   2                   3
880d76751fSJames 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
890d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
900d76751fSJames Chapman  * |                           Session ID                          |
910d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920d76751fSJames Chapman  * |               Cookie (optional, maximum 64 bits)...
930d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
940d76751fSJames Chapman  *                                                                 |
950d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
960d76751fSJames Chapman  *
970d76751fSJames Chapman  * L2TPv3 Control Message Header Over IP
980d76751fSJames Chapman  *
990d76751fSJames Chapman  *  0                   1                   2                   3
1000d76751fSJames 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
1010d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1020d76751fSJames Chapman  * |                      (32 bits of zeros)                       |
1030d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1040d76751fSJames Chapman  * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
1050d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1060d76751fSJames Chapman  * |                     Control Connection ID                     |
1070d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1080d76751fSJames Chapman  * |               Ns              |               Nr              |
1090d76751fSJames Chapman  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1100d76751fSJames Chapman  *
1110d76751fSJames Chapman  * All control frames are passed to userspace.
1120d76751fSJames Chapman  */
l2tp_ip_recv(struct sk_buff * skb)1130d76751fSJames Chapman static int l2tp_ip_recv(struct sk_buff *skb)
1140d76751fSJames Chapman {
1159d6ddb19SDavid S. Miller 	struct net *net = dev_net(skb->dev);
1160d76751fSJames Chapman 	struct sock *sk;
1170d76751fSJames Chapman 	u32 session_id;
1180d76751fSJames Chapman 	u32 tunnel_id;
1190d76751fSJames Chapman 	unsigned char *ptr, *optr;
1200d76751fSJames Chapman 	struct l2tp_session *session;
1210d76751fSJames Chapman 	struct l2tp_tunnel *tunnel = NULL;
1228f7dc9aeSGuillaume Nault 	struct iphdr *iph;
1230d76751fSJames Chapman 
1240d76751fSJames Chapman 	if (!pskb_may_pull(skb, 4))
1250d76751fSJames Chapman 		goto discard;
1260d76751fSJames Chapman 
1275745b823SHaishuang Yan 	/* Point to L2TP header */
12895075150STom Parkin 	optr = skb->data;
12995075150STom Parkin 	ptr = skb->data;
1300d76751fSJames Chapman 	session_id = ntohl(*((__be32 *)ptr));
1310d76751fSJames Chapman 	ptr += 4;
1320d76751fSJames Chapman 
1330d76751fSJames Chapman 	/* RFC3931: L2TP/IP packets have the first 4 bytes containing
1340d76751fSJames Chapman 	 * the session_id. If it is 0, the packet is a L2TP control
1350d76751fSJames Chapman 	 * frame and the session_id value can be discarded.
1360d76751fSJames Chapman 	 */
1370d76751fSJames Chapman 	if (session_id == 0) {
1380d76751fSJames Chapman 		__skb_pull(skb, 4);
1390d76751fSJames Chapman 		goto pass_up;
1400d76751fSJames Chapman 	}
1410d76751fSJames Chapman 
1420d76751fSJames Chapman 	/* Ok, this is a data packet. Lookup the session. */
14301e28b92SGuillaume Nault 	session = l2tp_session_get(net, session_id);
14461b9a047SGuillaume Nault 	if (!session)
1450d76751fSJames Chapman 		goto discard;
1460d76751fSJames Chapman 
1470d76751fSJames Chapman 	tunnel = session->tunnel;
14861b9a047SGuillaume Nault 	if (!tunnel)
14961b9a047SGuillaume Nault 		goto discard_sess;
1500d76751fSJames Chapman 
1514522a70dSJacob Wen 	if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr))
1524522a70dSJacob Wen 		goto discard_sess;
1534522a70dSJacob Wen 
1542b139e6bSGuillaume Nault 	l2tp_recv_common(session, skb, ptr, optr, 0, skb->len);
15561b9a047SGuillaume Nault 	l2tp_session_dec_refcount(session);
1560d76751fSJames Chapman 
1570d76751fSJames Chapman 	return 0;
1580d76751fSJames Chapman 
1590d76751fSJames Chapman pass_up:
1600d76751fSJames Chapman 	/* Get the tunnel_id from the L2TP header */
1610d76751fSJames Chapman 	if (!pskb_may_pull(skb, 12))
1620d76751fSJames Chapman 		goto discard;
1630d76751fSJames Chapman 
1640d76751fSJames Chapman 	if ((skb->data[0] & 0xc0) != 0xc0)
1650d76751fSJames Chapman 		goto discard;
1660d76751fSJames Chapman 
1670d76751fSJames Chapman 	tunnel_id = ntohl(*(__be32 *)&skb->data[4]);
1688f7dc9aeSGuillaume Nault 	iph = (struct iphdr *)skb_network_header(skb);
1690d76751fSJames Chapman 
1700d76751fSJames Chapman 	read_lock_bh(&l2tp_ip_lock);
1718f7dc9aeSGuillaume Nault 	sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr, inet_iif(skb),
1728f7dc9aeSGuillaume Nault 				   tunnel_id);
173a3c18422SGuillaume Nault 	if (!sk) {
1740d76751fSJames Chapman 		read_unlock_bh(&l2tp_ip_lock);
175a3c18422SGuillaume Nault 		goto discard;
1760d76751fSJames Chapman 	}
1770d76751fSJames Chapman 	sock_hold(sk);
178a3c18422SGuillaume Nault 	read_unlock_bh(&l2tp_ip_lock);
1790d76751fSJames Chapman 
1800d76751fSJames Chapman 	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
1810d76751fSJames Chapman 		goto discard_put;
1820d76751fSJames Chapman 
183895b5c9fSFlorian Westphal 	nf_reset_ct(skb);
1840d76751fSJames Chapman 
1850d76751fSJames Chapman 	return sk_receive_skb(sk, skb, 1);
1860d76751fSJames Chapman 
18761b9a047SGuillaume Nault discard_sess:
18861b9a047SGuillaume Nault 	l2tp_session_dec_refcount(session);
18961b9a047SGuillaume Nault 	goto discard;
19061b9a047SGuillaume Nault 
1910d76751fSJames Chapman discard_put:
1920d76751fSJames Chapman 	sock_put(sk);
1930d76751fSJames Chapman 
1940d76751fSJames Chapman discard:
1950d76751fSJames Chapman 	kfree_skb(skb);
1960d76751fSJames Chapman 	return 0;
1970d76751fSJames Chapman }
1980d76751fSJames Chapman 
l2tp_ip_hash(struct sock * sk)19902c71b14SEric Dumazet static int l2tp_ip_hash(struct sock *sk)
20002c71b14SEric Dumazet {
20102c71b14SEric Dumazet 	if (sk_unhashed(sk)) {
20202c71b14SEric Dumazet 		write_lock_bh(&l2tp_ip_lock);
20302c71b14SEric Dumazet 		sk_add_node(sk, &l2tp_ip_table);
20402c71b14SEric Dumazet 		write_unlock_bh(&l2tp_ip_lock);
20502c71b14SEric Dumazet 	}
20602c71b14SEric Dumazet 	return 0;
20702c71b14SEric Dumazet }
20802c71b14SEric Dumazet 
l2tp_ip_unhash(struct sock * sk)20902c71b14SEric Dumazet static void l2tp_ip_unhash(struct sock *sk)
21002c71b14SEric Dumazet {
21102c71b14SEric Dumazet 	if (sk_unhashed(sk))
21202c71b14SEric Dumazet 		return;
21302c71b14SEric Dumazet 	write_lock_bh(&l2tp_ip_lock);
21402c71b14SEric Dumazet 	sk_del_node_init(sk);
21502c71b14SEric Dumazet 	write_unlock_bh(&l2tp_ip_lock);
21602c71b14SEric Dumazet }
21702c71b14SEric Dumazet 
l2tp_ip_open(struct sock * sk)2180d76751fSJames Chapman static int l2tp_ip_open(struct sock *sk)
2190d76751fSJames Chapman {
2200d76751fSJames Chapman 	/* Prevent autobind. We don't have ports. */
2210d76751fSJames Chapman 	inet_sk(sk)->inet_num = IPPROTO_L2TP;
2220d76751fSJames Chapman 
22302c71b14SEric Dumazet 	l2tp_ip_hash(sk);
2240d76751fSJames Chapman 	return 0;
2250d76751fSJames Chapman }
2260d76751fSJames Chapman 
l2tp_ip_close(struct sock * sk,long timeout)2270d76751fSJames Chapman static void l2tp_ip_close(struct sock *sk, long timeout)
2280d76751fSJames Chapman {
2290d76751fSJames Chapman 	write_lock_bh(&l2tp_ip_lock);
2300d76751fSJames Chapman 	hlist_del_init(&sk->sk_bind_node);
231d1f224aeSJames Chapman 	sk_del_node_init(sk);
2320d76751fSJames Chapman 	write_unlock_bh(&l2tp_ip_lock);
2330d76751fSJames Chapman 	sk_common_release(sk);
2340d76751fSJames Chapman }
2350d76751fSJames Chapman 
l2tp_ip_destroy_sock(struct sock * sk)2360d76751fSJames Chapman static void l2tp_ip_destroy_sock(struct sock *sk)
2370d76751fSJames Chapman {
23845faeff1STom Parkin 	struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk);
2390d76751fSJames Chapman 	struct sk_buff *skb;
2400d76751fSJames Chapman 
2410d76751fSJames Chapman 	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
2420d76751fSJames Chapman 		kfree_skb(skb);
2430d76751fSJames Chapman 
244d00fa9adSJames Chapman 	if (tunnel)
245d00fa9adSJames Chapman 		l2tp_tunnel_delete(tunnel);
2460d76751fSJames Chapman }
2470d76751fSJames Chapman 
l2tp_ip_bind(struct sock * sk,struct sockaddr * uaddr,int addr_len)2480d76751fSJames Chapman static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
2490d76751fSJames Chapman {
2500d76751fSJames Chapman 	struct inet_sock *inet = inet_sk(sk);
2510d76751fSJames Chapman 	struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *)uaddr;
2529d6ddb19SDavid S. Miller 	struct net *net = sock_net(sk);
253c51ce497SJames Chapman 	int ret;
2540d76751fSJames Chapman 	int chk_addr_ret;
2550d76751fSJames Chapman 
256c51ce497SJames Chapman 	if (addr_len < sizeof(struct sockaddr_l2tpip))
257c51ce497SJames Chapman 		return -EINVAL;
258c51ce497SJames Chapman 	if (addr->l2tp_family != AF_INET)
259c51ce497SJames Chapman 		return -EINVAL;
260c51ce497SJames Chapman 
2610d76751fSJames Chapman 	lock_sock(sk);
262d5e3a190SGuillaume Nault 
263d5e3a190SGuillaume Nault 	ret = -EINVAL;
26432c23116SGuillaume Nault 	if (!sock_flag(sk, SOCK_ZAPPED))
26532c23116SGuillaume Nault 		goto out;
26632c23116SGuillaume Nault 
2678cf2f704SGuillaume Nault 	if (sk->sk_state != TCP_CLOSE)
2680d76751fSJames Chapman 		goto out;
2690d76751fSJames Chapman 
2709d6ddb19SDavid S. Miller 	chk_addr_ret = inet_addr_type(net, addr->l2tp_addr.s_addr);
2710d76751fSJames Chapman 	ret = -EADDRNOTAVAIL;
2720d76751fSJames Chapman 	if (addr->l2tp_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
2730d76751fSJames Chapman 	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
2740d76751fSJames Chapman 		goto out;
2750d76751fSJames Chapman 
27695075150STom Parkin 	if (addr->l2tp_addr.s_addr) {
27795075150STom Parkin 		inet->inet_rcv_saddr = addr->l2tp_addr.s_addr;
27895075150STom Parkin 		inet->inet_saddr = addr->l2tp_addr.s_addr;
27995075150STom Parkin 	}
2800d76751fSJames Chapman 	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
2810d76751fSJames Chapman 		inet->inet_saddr = 0;  /* Use device */
2820d76751fSJames Chapman 
2830d76751fSJames Chapman 	write_lock_bh(&l2tp_ip_lock);
284a9b2dff8SGuillaume Nault 	if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, 0,
285d5e3a190SGuillaume Nault 				  sk->sk_bound_dev_if, addr->l2tp_conn_id)) {
286d5e3a190SGuillaume Nault 		write_unlock_bh(&l2tp_ip_lock);
287d5e3a190SGuillaume Nault 		ret = -EADDRINUSE;
288d5e3a190SGuillaume Nault 		goto out;
289d5e3a190SGuillaume Nault 	}
290d5e3a190SGuillaume Nault 
291d5e3a190SGuillaume Nault 	sk_dst_reset(sk);
292d5e3a190SGuillaume Nault 	l2tp_ip_sk(sk)->conn_id = addr->l2tp_conn_id;
293d5e3a190SGuillaume Nault 
2940d76751fSJames Chapman 	sk_add_bind_node(sk, &l2tp_ip_bind_table);
2950d76751fSJames Chapman 	sk_del_node_init(sk);
2960d76751fSJames Chapman 	write_unlock_bh(&l2tp_ip_lock);
297d5e3a190SGuillaume Nault 
2980d76751fSJames Chapman 	ret = 0;
299c51ce497SJames Chapman 	sock_reset_flag(sk, SOCK_ZAPPED);
300c51ce497SJames Chapman 
3010d76751fSJames Chapman out:
3020d76751fSJames Chapman 	release_sock(sk);
3030d76751fSJames Chapman 
3040d76751fSJames Chapman 	return ret;
3050d76751fSJames Chapman }
3060d76751fSJames Chapman 
l2tp_ip_connect(struct sock * sk,struct sockaddr * uaddr,int addr_len)3070d76751fSJames Chapman static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
3080d76751fSJames Chapman {
3090d76751fSJames Chapman 	struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
310de3c7a18SJames Chapman 	int rc;
3110d76751fSJames Chapman 
3120d76751fSJames Chapman 	if (addr_len < sizeof(*lsa))
313de3c7a18SJames Chapman 		return -EINVAL;
3140d76751fSJames Chapman 
315de3c7a18SJames Chapman 	if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
316de3c7a18SJames Chapman 		return -EINVAL;
317de3c7a18SJames Chapman 
3182f16270fSDavid S. Miller 	lock_sock(sk);
3192f16270fSDavid S. Miller 
3200382a25aSGuillaume Nault 	/* Must bind first - autobinding does not work */
3210382a25aSGuillaume Nault 	if (sock_flag(sk, SOCK_ZAPPED)) {
3220382a25aSGuillaume Nault 		rc = -EINVAL;
3230382a25aSGuillaume Nault 		goto out_sk;
3240382a25aSGuillaume Nault 	}
3250382a25aSGuillaume Nault 
3260382a25aSGuillaume Nault 	rc = __ip4_datagram_connect(sk, uaddr, addr_len);
3270382a25aSGuillaume Nault 	if (rc < 0)
3280382a25aSGuillaume Nault 		goto out_sk;
3290382a25aSGuillaume Nault 
3300d76751fSJames Chapman 	l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
3310d76751fSJames Chapman 
3320d76751fSJames Chapman 	write_lock_bh(&l2tp_ip_lock);
3330d76751fSJames Chapman 	hlist_del_init(&sk->sk_bind_node);
3340d76751fSJames Chapman 	sk_add_bind_node(sk, &l2tp_ip_bind_table);
3350d76751fSJames Chapman 	write_unlock_bh(&l2tp_ip_lock);
3360d76751fSJames Chapman 
3370382a25aSGuillaume Nault out_sk:
3382f16270fSDavid S. Miller 	release_sock(sk);
3390382a25aSGuillaume Nault 
3400d76751fSJames Chapman 	return rc;
3410d76751fSJames Chapman }
3420d76751fSJames Chapman 
l2tp_ip_disconnect(struct sock * sk,int flags)343c51ce497SJames Chapman static int l2tp_ip_disconnect(struct sock *sk, int flags)
344c51ce497SJames Chapman {
345c51ce497SJames Chapman 	if (sock_flag(sk, SOCK_ZAPPED))
346c51ce497SJames Chapman 		return 0;
347c51ce497SJames Chapman 
348286c72deSEric Dumazet 	return __udp_disconnect(sk, flags);
349c51ce497SJames Chapman }
350c51ce497SJames Chapman 
l2tp_ip_getname(struct socket * sock,struct sockaddr * uaddr,int peer)3510d76751fSJames Chapman static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
3529b2c45d4SDenys Vlasenko 			   int peer)
3530d76751fSJames Chapman {
3540d76751fSJames Chapman 	struct sock *sk		= sock->sk;
3550d76751fSJames Chapman 	struct inet_sock *inet	= inet_sk(sk);
3560d76751fSJames Chapman 	struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk);
3570d76751fSJames Chapman 	struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
3580d76751fSJames Chapman 
3590d76751fSJames Chapman 	memset(lsa, 0, sizeof(*lsa));
3600d76751fSJames Chapman 	lsa->l2tp_family = AF_INET;
3610d76751fSJames Chapman 	if (peer) {
3620d76751fSJames Chapman 		if (!inet->inet_dport)
3630d76751fSJames Chapman 			return -ENOTCONN;
3640d76751fSJames Chapman 		lsa->l2tp_conn_id = lsk->peer_conn_id;
3650d76751fSJames Chapman 		lsa->l2tp_addr.s_addr = inet->inet_daddr;
3660d76751fSJames Chapman 	} else {
3670d76751fSJames Chapman 		__be32 addr = inet->inet_rcv_saddr;
368b71a61ccSTom Parkin 
3690d76751fSJames Chapman 		if (!addr)
3700d76751fSJames Chapman 			addr = inet->inet_saddr;
3710d76751fSJames Chapman 		lsa->l2tp_conn_id = lsk->conn_id;
3720d76751fSJames Chapman 		lsa->l2tp_addr.s_addr = addr;
3730d76751fSJames Chapman 	}
3749b2c45d4SDenys Vlasenko 	return sizeof(*lsa);
3750d76751fSJames Chapman }
3760d76751fSJames Chapman 
l2tp_ip_backlog_recv(struct sock * sk,struct sk_buff * skb)3770d76751fSJames Chapman static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)
3780d76751fSJames Chapman {
3790d76751fSJames Chapman 	int rc;
3800d76751fSJames Chapman 
3810d76751fSJames Chapman 	/* Charge it to the socket, dropping if the queue is full. */
3820d76751fSJames Chapman 	rc = sock_queue_rcv_skb(sk, skb);
3830d76751fSJames Chapman 	if (rc < 0)
3840d76751fSJames Chapman 		goto drop;
3850d76751fSJames Chapman 
3860d76751fSJames Chapman 	return 0;
3870d76751fSJames Chapman 
3880d76751fSJames Chapman drop:
3899d6ddb19SDavid S. Miller 	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);
3900d76751fSJames Chapman 	kfree_skb(skb);
39151fb60ebSPaul Hüber 	return 0;
3920d76751fSJames Chapman }
3930d76751fSJames Chapman 
3940d76751fSJames Chapman /* Userspace will call sendmsg() on the tunnel socket to send L2TP
3950d76751fSJames Chapman  * control frames.
3960d76751fSJames Chapman  */
l2tp_ip_sendmsg(struct sock * sk,struct msghdr * msg,size_t len)3971b784140SYing Xue static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
3980d76751fSJames Chapman {
3990d76751fSJames Chapman 	struct sk_buff *skb;
4000d76751fSJames Chapman 	int rc;
4010d76751fSJames Chapman 	struct inet_sock *inet = inet_sk(sk);
4020d76751fSJames Chapman 	struct rtable *rt = NULL;
403fdbb0f07SDavid S. Miller 	struct flowi4 *fl4;
4040d76751fSJames Chapman 	int connected = 0;
4050d76751fSJames Chapman 	__be32 daddr;
4060d76751fSJames Chapman 
4072f16270fSDavid S. Miller 	lock_sock(sk);
4082f16270fSDavid S. Miller 
4092f16270fSDavid S. Miller 	rc = -ENOTCONN;
4100d76751fSJames Chapman 	if (sock_flag(sk, SOCK_DEAD))
4112f16270fSDavid S. Miller 		goto out;
4120d76751fSJames Chapman 
4130d76751fSJames Chapman 	/* Get and verify the address. */
4140d76751fSJames Chapman 	if (msg->msg_name) {
415342dfc30SSteffen Hurrle 		DECLARE_SOCKADDR(struct sockaddr_l2tpip *, lip, msg->msg_name);
416b71a61ccSTom Parkin 
4172f16270fSDavid S. Miller 		rc = -EINVAL;
4180d76751fSJames Chapman 		if (msg->msg_namelen < sizeof(*lip))
4192f16270fSDavid S. Miller 			goto out;
4200d76751fSJames Chapman 
4210d76751fSJames Chapman 		if (lip->l2tp_family != AF_INET) {
4222f16270fSDavid S. Miller 			rc = -EAFNOSUPPORT;
4230d76751fSJames Chapman 			if (lip->l2tp_family != AF_UNSPEC)
4242f16270fSDavid S. Miller 				goto out;
4250d76751fSJames Chapman 		}
4260d76751fSJames Chapman 
4270d76751fSJames Chapman 		daddr = lip->l2tp_addr.s_addr;
4280d76751fSJames Chapman 	} else {
42984768edbSSasha Levin 		rc = -EDESTADDRREQ;
4300d76751fSJames Chapman 		if (sk->sk_state != TCP_ESTABLISHED)
43184768edbSSasha Levin 			goto out;
4320d76751fSJames Chapman 
4330d76751fSJames Chapman 		daddr = inet->inet_daddr;
4340d76751fSJames Chapman 		connected = 1;
4350d76751fSJames Chapman 	}
4360d76751fSJames Chapman 
4370d76751fSJames Chapman 	/* Allocate a socket buffer */
4380d76751fSJames Chapman 	rc = -ENOMEM;
4390d76751fSJames Chapman 	skb = sock_wmalloc(sk, 2 + NET_SKB_PAD + sizeof(struct iphdr) +
4400d76751fSJames Chapman 			   4 + len, 0, GFP_KERNEL);
4410d76751fSJames Chapman 	if (!skb)
4420d76751fSJames Chapman 		goto error;
4430d76751fSJames Chapman 
4440d76751fSJames Chapman 	/* Reserve space for headers, putting IP header on 4-byte boundary. */
4450d76751fSJames Chapman 	skb_reserve(skb, 2 + NET_SKB_PAD);
4460d76751fSJames Chapman 	skb_reset_network_header(skb);
4470d76751fSJames Chapman 	skb_reserve(skb, sizeof(struct iphdr));
4480d76751fSJames Chapman 	skb_reset_transport_header(skb);
4490d76751fSJames Chapman 
4500d76751fSJames Chapman 	/* Insert 0 session_id */
4510d76751fSJames Chapman 	*((__be32 *)skb_put(skb, 4)) = 0;
4520d76751fSJames Chapman 
4530d76751fSJames Chapman 	/* Copy user data into skb */
4546ce8e9ceSAl Viro 	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
4550d76751fSJames Chapman 	if (rc < 0) {
4560d76751fSJames Chapman 		kfree_skb(skb);
4570d76751fSJames Chapman 		goto error;
4580d76751fSJames Chapman 	}
4590d76751fSJames Chapman 
460fdbb0f07SDavid S. Miller 	fl4 = &inet->cork.fl.u.ip4;
4610d76751fSJames Chapman 	if (connected)
4620d76751fSJames Chapman 		rt = (struct rtable *)__sk_dst_check(sk, 0);
4630d76751fSJames Chapman 
464778865a5SDavid S. Miller 	rcu_read_lock();
4650febc7b3STom Parkin 	if (!rt) {
466081b1b1bSEric Dumazet 		const struct ip_options_rcu *inet_opt;
467081b1b1bSEric Dumazet 
468778865a5SDavid S. Miller 		inet_opt = rcu_dereference(inet->inet_opt);
469f6d8bd05SEric Dumazet 
4700d76751fSJames Chapman 		/* Use correct destination address if we have options. */
471f6d8bd05SEric Dumazet 		if (inet_opt && inet_opt->opt.srr)
472f6d8bd05SEric Dumazet 			daddr = inet_opt->opt.faddr;
4730d76751fSJames Chapman 
4740d76751fSJames Chapman 		/* If this fails, retransmit mechanism of transport layer will
4750d76751fSJames Chapman 		 * keep trying until route appears or the connection times
4760d76751fSJames Chapman 		 * itself out.
4770d76751fSJames Chapman 		 */
478fdbb0f07SDavid S. Miller 		rt = ip_route_output_ports(sock_net(sk), fl4, sk,
47978fbfd8aSDavid S. Miller 					   daddr, inet->inet_saddr,
48078fbfd8aSDavid S. Miller 					   inet->inet_dport, inet->inet_sport,
48178fbfd8aSDavid S. Miller 					   sk->sk_protocol, RT_CONN_FLAGS(sk),
48278fbfd8aSDavid S. Miller 					   sk->sk_bound_dev_if);
483b23dd4feSDavid S. Miller 		if (IS_ERR(rt))
4840d76751fSJames Chapman 			goto no_route;
4854399a4dfSEric Dumazet 		if (connected) {
486d8d1f30bSChangli Gao 			sk_setup_caps(sk, &rt->dst);
4874399a4dfSEric Dumazet 		} else {
4884399a4dfSEric Dumazet 			skb_dst_set(skb, &rt->dst);
4894399a4dfSEric Dumazet 			goto xmit;
4904399a4dfSEric Dumazet 		}
4910d76751fSJames Chapman 	}
492081b1b1bSEric Dumazet 
4937f553ff2SZheng Yongjun 	/* We don't need to clone dst here, it is guaranteed to not disappear.
494081b1b1bSEric Dumazet 	 *  __dev_xmit_skb() might force a refcount if needed.
495081b1b1bSEric Dumazet 	 */
496081b1b1bSEric Dumazet 	skb_dst_set_noref(skb, &rt->dst);
4970d76751fSJames Chapman 
4984399a4dfSEric Dumazet xmit:
4990d76751fSJames Chapman 	/* Queue the packet to IP for output */
500b0270e91SEric Dumazet 	rc = ip_queue_xmit(sk, skb, &inet->cork.fl);
501081b1b1bSEric Dumazet 	rcu_read_unlock();
5020d76751fSJames Chapman 
5030d76751fSJames Chapman error:
504c8657fd5SJames Chapman 	if (rc >= 0)
5050d76751fSJames Chapman 		rc = len;
5060d76751fSJames Chapman 
5072f16270fSDavid S. Miller out:
5082f16270fSDavid S. Miller 	release_sock(sk);
5090d76751fSJames Chapman 	return rc;
5100d76751fSJames Chapman 
5110d76751fSJames Chapman no_route:
512081b1b1bSEric Dumazet 	rcu_read_unlock();
5130d76751fSJames Chapman 	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
5140d76751fSJames Chapman 	kfree_skb(skb);
5152f16270fSDavid S. Miller 	rc = -EHOSTUNREACH;
5162f16270fSDavid S. Miller 	goto out;
5170d76751fSJames Chapman }
5180d76751fSJames Chapman 
l2tp_ip_recvmsg(struct sock * sk,struct msghdr * msg,size_t len,int flags,int * addr_len)5191b784140SYing Xue static int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg,
520ec095263SOliver Hartkopp 			   size_t len, int flags, int *addr_len)
5210d76751fSJames Chapman {
5220d76751fSJames Chapman 	struct inet_sock *inet = inet_sk(sk);
5230d76751fSJames Chapman 	size_t copied = 0;
5240d76751fSJames Chapman 	int err = -EOPNOTSUPP;
525342dfc30SSteffen Hurrle 	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
5260d76751fSJames Chapman 	struct sk_buff *skb;
5270d76751fSJames Chapman 
5280d76751fSJames Chapman 	if (flags & MSG_OOB)
5290d76751fSJames Chapman 		goto out;
5300d76751fSJames Chapman 
531f4b41f06SOliver Hartkopp 	skb = skb_recv_datagram(sk, flags, &err);
5320d76751fSJames Chapman 	if (!skb)
5330d76751fSJames Chapman 		goto out;
5340d76751fSJames Chapman 
5350d76751fSJames Chapman 	copied = skb->len;
5360d76751fSJames Chapman 	if (len < copied) {
5370d76751fSJames Chapman 		msg->msg_flags |= MSG_TRUNC;
5380d76751fSJames Chapman 		copied = len;
5390d76751fSJames Chapman 	}
5400d76751fSJames Chapman 
54151f3d02bSDavid S. Miller 	err = skb_copy_datagram_msg(skb, 0, msg, copied);
5420d76751fSJames Chapman 	if (err)
5430d76751fSJames Chapman 		goto done;
5440d76751fSJames Chapman 
5450d76751fSJames Chapman 	sock_recv_timestamp(msg, sk, skb);
5460d76751fSJames Chapman 
5470d76751fSJames Chapman 	/* Copy the address. */
5480d76751fSJames Chapman 	if (sin) {
5490d76751fSJames Chapman 		sin->sin_family = AF_INET;
5500d76751fSJames Chapman 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
5510d76751fSJames Chapman 		sin->sin_port = 0;
5520d76751fSJames Chapman 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
553bceaa902SHannes Frederic Sowa 		*addr_len = sizeof(*sin);
5540d76751fSJames Chapman 	}
555*c274af22SEric Dumazet 	if (inet_cmsg_flags(inet))
5560d76751fSJames Chapman 		ip_cmsg_recv(msg, skb);
5570d76751fSJames Chapman 	if (flags & MSG_TRUNC)
5580d76751fSJames Chapman 		copied = skb->len;
5590d76751fSJames Chapman done:
5600d76751fSJames Chapman 	skb_free_datagram(sk, skb);
5610d76751fSJames Chapman out:
562c8657fd5SJames Chapman 	return err ? err : copied;
5630d76751fSJames Chapman }
5640d76751fSJames Chapman 
l2tp_ioctl(struct sock * sk,int cmd,int * karg)565e1d001faSBreno Leitao int l2tp_ioctl(struct sock *sk, int cmd, int *karg)
56672fb96e7SEric Dumazet {
56772fb96e7SEric Dumazet 	struct sk_buff *skb;
56872fb96e7SEric Dumazet 
56972fb96e7SEric Dumazet 	switch (cmd) {
57072fb96e7SEric Dumazet 	case SIOCOUTQ:
571e1d001faSBreno Leitao 		*karg = sk_wmem_alloc_get(sk);
57272fb96e7SEric Dumazet 		break;
57372fb96e7SEric Dumazet 	case SIOCINQ:
57472fb96e7SEric Dumazet 		spin_lock_bh(&sk->sk_receive_queue.lock);
57572fb96e7SEric Dumazet 		skb = skb_peek(&sk->sk_receive_queue);
576e1d001faSBreno Leitao 		*karg = skb ? skb->len : 0;
57772fb96e7SEric Dumazet 		spin_unlock_bh(&sk->sk_receive_queue.lock);
57872fb96e7SEric Dumazet 		break;
57972fb96e7SEric Dumazet 
58072fb96e7SEric Dumazet 	default:
58172fb96e7SEric Dumazet 		return -ENOIOCTLCMD;
58272fb96e7SEric Dumazet 	}
58372fb96e7SEric Dumazet 
584e1d001faSBreno Leitao 	return 0;
58572fb96e7SEric Dumazet }
586ca7885dbSTom Parkin EXPORT_SYMBOL_GPL(l2tp_ioctl);
58772fb96e7SEric Dumazet 
588fc130840Sstephen hemminger static struct proto l2tp_ip_prot = {
5890d76751fSJames Chapman 	.name		   = "L2TP/IP",
5900d76751fSJames Chapman 	.owner		   = THIS_MODULE,
5910d76751fSJames Chapman 	.init		   = l2tp_ip_open,
5920d76751fSJames Chapman 	.close		   = l2tp_ip_close,
5930d76751fSJames Chapman 	.bind		   = l2tp_ip_bind,
5940d76751fSJames Chapman 	.connect	   = l2tp_ip_connect,
595c51ce497SJames Chapman 	.disconnect	   = l2tp_ip_disconnect,
59672fb96e7SEric Dumazet 	.ioctl		   = l2tp_ioctl,
5970d76751fSJames Chapman 	.destroy	   = l2tp_ip_destroy_sock,
5980d76751fSJames Chapman 	.setsockopt	   = ip_setsockopt,
5990d76751fSJames Chapman 	.getsockopt	   = ip_getsockopt,
6000d76751fSJames Chapman 	.sendmsg	   = l2tp_ip_sendmsg,
6010d76751fSJames Chapman 	.recvmsg	   = l2tp_ip_recvmsg,
6020d76751fSJames Chapman 	.backlog_rcv	   = l2tp_ip_backlog_recv,
60302c71b14SEric Dumazet 	.hash		   = l2tp_ip_hash,
60402c71b14SEric Dumazet 	.unhash		   = l2tp_ip_unhash,
6050d76751fSJames Chapman 	.obj_size	   = sizeof(struct l2tp_ip_sock),
6060d76751fSJames Chapman };
6070d76751fSJames Chapman 
6080d76751fSJames Chapman static const struct proto_ops l2tp_ip_ops = {
6090d76751fSJames Chapman 	.family		   = PF_INET,
6100d76751fSJames Chapman 	.owner		   = THIS_MODULE,
6110d76751fSJames Chapman 	.release	   = inet_release,
6120d76751fSJames Chapman 	.bind		   = inet_bind,
6130d76751fSJames Chapman 	.connect	   = inet_dgram_connect,
6140d76751fSJames Chapman 	.socketpair	   = sock_no_socketpair,
6150d76751fSJames Chapman 	.accept		   = sock_no_accept,
6160d76751fSJames Chapman 	.getname	   = l2tp_ip_getname,
617a11e1d43SLinus Torvalds 	.poll		   = datagram_poll,
6180d76751fSJames Chapman 	.ioctl		   = inet_ioctl,
619c7cbdbf2SArnd Bergmann 	.gettstamp	   = sock_gettstamp,
6200d76751fSJames Chapman 	.listen		   = sock_no_listen,
6210d76751fSJames Chapman 	.shutdown	   = inet_shutdown,
6220d76751fSJames Chapman 	.setsockopt	   = sock_common_setsockopt,
6230d76751fSJames Chapman 	.getsockopt	   = sock_common_getsockopt,
6240d76751fSJames Chapman 	.sendmsg	   = inet_sendmsg,
6250d76751fSJames Chapman 	.recvmsg	   = sock_common_recvmsg,
6260d76751fSJames Chapman 	.mmap		   = sock_no_mmap,
6270d76751fSJames Chapman };
6280d76751fSJames Chapman 
6290d76751fSJames Chapman static struct inet_protosw l2tp_ip_protosw = {
6300d76751fSJames Chapman 	.type		= SOCK_DGRAM,
6310d76751fSJames Chapman 	.protocol	= IPPROTO_L2TP,
6320d76751fSJames Chapman 	.prot		= &l2tp_ip_prot,
6330d76751fSJames Chapman 	.ops		= &l2tp_ip_ops,
6340d76751fSJames Chapman };
6350d76751fSJames Chapman 
6360d76751fSJames Chapman static struct net_protocol l2tp_ip_protocol __read_mostly = {
6370d76751fSJames Chapman 	.handler	= l2tp_ip_recv,
6380d76751fSJames Chapman };
6390d76751fSJames Chapman 
l2tp_ip_init(void)6400d76751fSJames Chapman static int __init l2tp_ip_init(void)
6410d76751fSJames Chapman {
6420d76751fSJames Chapman 	int err;
6430d76751fSJames Chapman 
644a4ca44faSJoe Perches 	pr_info("L2TP IP encapsulation support (L2TPv3)\n");
6450d76751fSJames Chapman 
6460d76751fSJames Chapman 	err = proto_register(&l2tp_ip_prot, 1);
6470d76751fSJames Chapman 	if (err != 0)
6480d76751fSJames Chapman 		goto out;
6490d76751fSJames Chapman 
6500d76751fSJames Chapman 	err = inet_add_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
6510d76751fSJames Chapman 	if (err)
6520d76751fSJames Chapman 		goto out1;
6530d76751fSJames Chapman 
6540d76751fSJames Chapman 	inet_register_protosw(&l2tp_ip_protosw);
6550d76751fSJames Chapman 	return 0;
6560d76751fSJames Chapman 
6570d76751fSJames Chapman out1:
6580d76751fSJames Chapman 	proto_unregister(&l2tp_ip_prot);
6590d76751fSJames Chapman out:
6600d76751fSJames Chapman 	return err;
6610d76751fSJames Chapman }
6620d76751fSJames Chapman 
l2tp_ip_exit(void)6630d76751fSJames Chapman static void __exit l2tp_ip_exit(void)
6640d76751fSJames Chapman {
6650d76751fSJames Chapman 	inet_unregister_protosw(&l2tp_ip_protosw);
6660d76751fSJames Chapman 	inet_del_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
6670d76751fSJames Chapman 	proto_unregister(&l2tp_ip_prot);
6680d76751fSJames Chapman }
6690d76751fSJames Chapman 
6700d76751fSJames Chapman module_init(l2tp_ip_init);
6710d76751fSJames Chapman module_exit(l2tp_ip_exit);
6720d76751fSJames Chapman 
6730d76751fSJames Chapman MODULE_LICENSE("GPL");
6740d76751fSJames Chapman MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
6750d76751fSJames Chapman MODULE_DESCRIPTION("L2TP over IP");
6760d76751fSJames Chapman MODULE_VERSION("1.0");
677e8d34a88SMichal Marek 
678154e07c1SAndrea Righi /* Use the values of SOCK_DGRAM (2) as type and IPPROTO_L2TP (115) as protocol,
679154e07c1SAndrea Righi  * because __stringify doesn't like enums
680e8d34a88SMichal Marek  */
681154e07c1SAndrea Righi MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 115, 2);
682154e07c1SAndrea Righi MODULE_ALIAS_NET_PF_PROTO(PF_INET, 115);
683