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