162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* L2TPv3 IP encapsulation support 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008,2009,2010 Katalix Systems Ltd 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/ioctls.h> 1062306a36Sopenharmony_ci#include <linux/icmp.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <linux/random.h> 1462306a36Sopenharmony_ci#include <linux/socket.h> 1562306a36Sopenharmony_ci#include <linux/l2tp.h> 1662306a36Sopenharmony_ci#include <linux/in.h> 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci#include <net/ip.h> 1962306a36Sopenharmony_ci#include <net/icmp.h> 2062306a36Sopenharmony_ci#include <net/udp.h> 2162306a36Sopenharmony_ci#include <net/inet_common.h> 2262306a36Sopenharmony_ci#include <net/tcp_states.h> 2362306a36Sopenharmony_ci#include <net/protocol.h> 2462306a36Sopenharmony_ci#include <net/xfrm.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "l2tp_core.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct l2tp_ip_sock { 2962306a36Sopenharmony_ci /* inet_sock has to be the first member of l2tp_ip_sock */ 3062306a36Sopenharmony_ci struct inet_sock inet; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci u32 conn_id; 3362306a36Sopenharmony_ci u32 peer_conn_id; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic DEFINE_RWLOCK(l2tp_ip_lock); 3762306a36Sopenharmony_cistatic struct hlist_head l2tp_ip_table; 3862306a36Sopenharmony_cistatic struct hlist_head l2tp_ip_bind_table; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci return (struct l2tp_ip_sock *)sk; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct sock *__l2tp_ip_bind_lookup(const struct net *net, __be32 laddr, 4662306a36Sopenharmony_ci __be32 raddr, int dif, u32 tunnel_id) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct sock *sk; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci sk_for_each_bound(sk, &l2tp_ip_bind_table) { 5162306a36Sopenharmony_ci const struct l2tp_ip_sock *l2tp = l2tp_ip_sk(sk); 5262306a36Sopenharmony_ci const struct inet_sock *inet = inet_sk(sk); 5362306a36Sopenharmony_ci int bound_dev_if; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (!net_eq(sock_net(sk), net)) 5662306a36Sopenharmony_ci continue; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); 5962306a36Sopenharmony_ci if (bound_dev_if && dif && bound_dev_if != dif) 6062306a36Sopenharmony_ci continue; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (inet->inet_rcv_saddr && laddr && 6362306a36Sopenharmony_ci inet->inet_rcv_saddr != laddr) 6462306a36Sopenharmony_ci continue; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (inet->inet_daddr && raddr && inet->inet_daddr != raddr) 6762306a36Sopenharmony_ci continue; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (l2tp->conn_id != tunnel_id) 7062306a36Sopenharmony_ci continue; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci goto found; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci sk = NULL; 7662306a36Sopenharmony_cifound: 7762306a36Sopenharmony_ci return sk; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* When processing receive frames, there are two cases to 8162306a36Sopenharmony_ci * consider. Data frames consist of a non-zero session-id and an 8262306a36Sopenharmony_ci * optional cookie. Control frames consist of a regular L2TP header 8362306a36Sopenharmony_ci * preceded by 32-bits of zeros. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * L2TPv3 Session Header Over IP 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * 0 1 2 3 8862306a36Sopenharmony_ci * 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 8962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9062306a36Sopenharmony_ci * | Session ID | 9162306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9262306a36Sopenharmony_ci * | Cookie (optional, maximum 64 bits)... 9362306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9462306a36Sopenharmony_ci * | 9562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * L2TPv3 Control Message Header Over IP 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * 0 1 2 3 10062306a36Sopenharmony_ci * 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 10162306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10262306a36Sopenharmony_ci * | (32 bits of zeros) | 10362306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10462306a36Sopenharmony_ci * |T|L|x|x|S|x|x|x|x|x|x|x| Ver | Length | 10562306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10662306a36Sopenharmony_ci * | Control Connection ID | 10762306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10862306a36Sopenharmony_ci * | Ns | Nr | 10962306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * All control frames are passed to userspace. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic int l2tp_ip_recv(struct sk_buff *skb) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 11662306a36Sopenharmony_ci struct sock *sk; 11762306a36Sopenharmony_ci u32 session_id; 11862306a36Sopenharmony_ci u32 tunnel_id; 11962306a36Sopenharmony_ci unsigned char *ptr, *optr; 12062306a36Sopenharmony_ci struct l2tp_session *session; 12162306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = NULL; 12262306a36Sopenharmony_ci struct iphdr *iph; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (!pskb_may_pull(skb, 4)) 12562306a36Sopenharmony_ci goto discard; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Point to L2TP header */ 12862306a36Sopenharmony_ci optr = skb->data; 12962306a36Sopenharmony_ci ptr = skb->data; 13062306a36Sopenharmony_ci session_id = ntohl(*((__be32 *)ptr)); 13162306a36Sopenharmony_ci ptr += 4; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* RFC3931: L2TP/IP packets have the first 4 bytes containing 13462306a36Sopenharmony_ci * the session_id. If it is 0, the packet is a L2TP control 13562306a36Sopenharmony_ci * frame and the session_id value can be discarded. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci if (session_id == 0) { 13862306a36Sopenharmony_ci __skb_pull(skb, 4); 13962306a36Sopenharmony_ci goto pass_up; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Ok, this is a data packet. Lookup the session. */ 14362306a36Sopenharmony_ci session = l2tp_session_get(net, session_id); 14462306a36Sopenharmony_ci if (!session) 14562306a36Sopenharmony_ci goto discard; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci tunnel = session->tunnel; 14862306a36Sopenharmony_ci if (!tunnel) 14962306a36Sopenharmony_ci goto discard_sess; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) 15262306a36Sopenharmony_ci goto discard_sess; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); 15562306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cipass_up: 16062306a36Sopenharmony_ci /* Get the tunnel_id from the L2TP header */ 16162306a36Sopenharmony_ci if (!pskb_may_pull(skb, 12)) 16262306a36Sopenharmony_ci goto discard; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if ((skb->data[0] & 0xc0) != 0xc0) 16562306a36Sopenharmony_ci goto discard; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci tunnel_id = ntohl(*(__be32 *)&skb->data[4]); 16862306a36Sopenharmony_ci iph = (struct iphdr *)skb_network_header(skb); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci read_lock_bh(&l2tp_ip_lock); 17162306a36Sopenharmony_ci sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr, inet_iif(skb), 17262306a36Sopenharmony_ci tunnel_id); 17362306a36Sopenharmony_ci if (!sk) { 17462306a36Sopenharmony_ci read_unlock_bh(&l2tp_ip_lock); 17562306a36Sopenharmony_ci goto discard; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci sock_hold(sk); 17862306a36Sopenharmony_ci read_unlock_bh(&l2tp_ip_lock); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) 18162306a36Sopenharmony_ci goto discard_put; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci nf_reset_ct(skb); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return sk_receive_skb(sk, skb, 1); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cidiscard_sess: 18862306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 18962306a36Sopenharmony_ci goto discard; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cidiscard_put: 19262306a36Sopenharmony_ci sock_put(sk); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cidiscard: 19562306a36Sopenharmony_ci kfree_skb(skb); 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int l2tp_ip_hash(struct sock *sk) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci if (sk_unhashed(sk)) { 20262306a36Sopenharmony_ci write_lock_bh(&l2tp_ip_lock); 20362306a36Sopenharmony_ci sk_add_node(sk, &l2tp_ip_table); 20462306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void l2tp_ip_unhash(struct sock *sk) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci if (sk_unhashed(sk)) 21262306a36Sopenharmony_ci return; 21362306a36Sopenharmony_ci write_lock_bh(&l2tp_ip_lock); 21462306a36Sopenharmony_ci sk_del_node_init(sk); 21562306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int l2tp_ip_open(struct sock *sk) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci /* Prevent autobind. We don't have ports. */ 22162306a36Sopenharmony_ci inet_sk(sk)->inet_num = IPPROTO_L2TP; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci l2tp_ip_hash(sk); 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void l2tp_ip_close(struct sock *sk, long timeout) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci write_lock_bh(&l2tp_ip_lock); 23062306a36Sopenharmony_ci hlist_del_init(&sk->sk_bind_node); 23162306a36Sopenharmony_ci sk_del_node_init(sk); 23262306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 23362306a36Sopenharmony_ci sk_common_release(sk); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void l2tp_ip_destroy_sock(struct sock *sk) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 23962306a36Sopenharmony_ci struct sk_buff *skb; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) 24262306a36Sopenharmony_ci kfree_skb(skb); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (tunnel) 24562306a36Sopenharmony_ci l2tp_tunnel_delete(tunnel); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 25162306a36Sopenharmony_ci struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *)uaddr; 25262306a36Sopenharmony_ci struct net *net = sock_net(sk); 25362306a36Sopenharmony_ci int ret; 25462306a36Sopenharmony_ci int chk_addr_ret; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (addr_len < sizeof(struct sockaddr_l2tpip)) 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci if (addr->l2tp_family != AF_INET) 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci lock_sock(sk); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ret = -EINVAL; 26462306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_ZAPPED)) 26562306a36Sopenharmony_ci goto out; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (sk->sk_state != TCP_CLOSE) 26862306a36Sopenharmony_ci goto out; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci chk_addr_ret = inet_addr_type(net, addr->l2tp_addr.s_addr); 27162306a36Sopenharmony_ci ret = -EADDRNOTAVAIL; 27262306a36Sopenharmony_ci if (addr->l2tp_addr.s_addr && chk_addr_ret != RTN_LOCAL && 27362306a36Sopenharmony_ci chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) 27462306a36Sopenharmony_ci goto out; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (addr->l2tp_addr.s_addr) { 27762306a36Sopenharmony_ci inet->inet_rcv_saddr = addr->l2tp_addr.s_addr; 27862306a36Sopenharmony_ci inet->inet_saddr = addr->l2tp_addr.s_addr; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) 28162306a36Sopenharmony_ci inet->inet_saddr = 0; /* Use device */ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci write_lock_bh(&l2tp_ip_lock); 28462306a36Sopenharmony_ci if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, 0, 28562306a36Sopenharmony_ci sk->sk_bound_dev_if, addr->l2tp_conn_id)) { 28662306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 28762306a36Sopenharmony_ci ret = -EADDRINUSE; 28862306a36Sopenharmony_ci goto out; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci sk_dst_reset(sk); 29262306a36Sopenharmony_ci l2tp_ip_sk(sk)->conn_id = addr->l2tp_conn_id; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci sk_add_bind_node(sk, &l2tp_ip_bind_table); 29562306a36Sopenharmony_ci sk_del_node_init(sk); 29662306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ret = 0; 29962306a36Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciout: 30262306a36Sopenharmony_ci release_sock(sk); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return ret; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr; 31062306a36Sopenharmony_ci int rc; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (addr_len < sizeof(*lsa)) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) 31662306a36Sopenharmony_ci return -EINVAL; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci lock_sock(sk); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Must bind first - autobinding does not work */ 32162306a36Sopenharmony_ci if (sock_flag(sk, SOCK_ZAPPED)) { 32262306a36Sopenharmony_ci rc = -EINVAL; 32362306a36Sopenharmony_ci goto out_sk; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci rc = __ip4_datagram_connect(sk, uaddr, addr_len); 32762306a36Sopenharmony_ci if (rc < 0) 32862306a36Sopenharmony_ci goto out_sk; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci write_lock_bh(&l2tp_ip_lock); 33362306a36Sopenharmony_ci hlist_del_init(&sk->sk_bind_node); 33462306a36Sopenharmony_ci sk_add_bind_node(sk, &l2tp_ip_bind_table); 33562306a36Sopenharmony_ci write_unlock_bh(&l2tp_ip_lock); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ciout_sk: 33862306a36Sopenharmony_ci release_sock(sk); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return rc; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int l2tp_ip_disconnect(struct sock *sk, int flags) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci if (sock_flag(sk, SOCK_ZAPPED)) 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return __udp_disconnect(sk, flags); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, 35262306a36Sopenharmony_ci int peer) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct sock *sk = sock->sk; 35562306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 35662306a36Sopenharmony_ci struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk); 35762306a36Sopenharmony_ci struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci memset(lsa, 0, sizeof(*lsa)); 36062306a36Sopenharmony_ci lsa->l2tp_family = AF_INET; 36162306a36Sopenharmony_ci if (peer) { 36262306a36Sopenharmony_ci if (!inet->inet_dport) 36362306a36Sopenharmony_ci return -ENOTCONN; 36462306a36Sopenharmony_ci lsa->l2tp_conn_id = lsk->peer_conn_id; 36562306a36Sopenharmony_ci lsa->l2tp_addr.s_addr = inet->inet_daddr; 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci __be32 addr = inet->inet_rcv_saddr; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (!addr) 37062306a36Sopenharmony_ci addr = inet->inet_saddr; 37162306a36Sopenharmony_ci lsa->l2tp_conn_id = lsk->conn_id; 37262306a36Sopenharmony_ci lsa->l2tp_addr.s_addr = addr; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci return sizeof(*lsa); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int rc; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Charge it to the socket, dropping if the queue is full. */ 38262306a36Sopenharmony_ci rc = sock_queue_rcv_skb(sk, skb); 38362306a36Sopenharmony_ci if (rc < 0) 38462306a36Sopenharmony_ci goto drop; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return 0; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cidrop: 38962306a36Sopenharmony_ci IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS); 39062306a36Sopenharmony_ci kfree_skb(skb); 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/* Userspace will call sendmsg() on the tunnel socket to send L2TP 39562306a36Sopenharmony_ci * control frames. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_cistatic int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct sk_buff *skb; 40062306a36Sopenharmony_ci int rc; 40162306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 40262306a36Sopenharmony_ci struct rtable *rt = NULL; 40362306a36Sopenharmony_ci struct flowi4 *fl4; 40462306a36Sopenharmony_ci int connected = 0; 40562306a36Sopenharmony_ci __be32 daddr; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci lock_sock(sk); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci rc = -ENOTCONN; 41062306a36Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) 41162306a36Sopenharmony_ci goto out; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Get and verify the address. */ 41462306a36Sopenharmony_ci if (msg->msg_name) { 41562306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_l2tpip *, lip, msg->msg_name); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rc = -EINVAL; 41862306a36Sopenharmony_ci if (msg->msg_namelen < sizeof(*lip)) 41962306a36Sopenharmony_ci goto out; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (lip->l2tp_family != AF_INET) { 42262306a36Sopenharmony_ci rc = -EAFNOSUPPORT; 42362306a36Sopenharmony_ci if (lip->l2tp_family != AF_UNSPEC) 42462306a36Sopenharmony_ci goto out; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci daddr = lip->l2tp_addr.s_addr; 42862306a36Sopenharmony_ci } else { 42962306a36Sopenharmony_ci rc = -EDESTADDRREQ; 43062306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 43162306a36Sopenharmony_ci goto out; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci daddr = inet->inet_daddr; 43462306a36Sopenharmony_ci connected = 1; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Allocate a socket buffer */ 43862306a36Sopenharmony_ci rc = -ENOMEM; 43962306a36Sopenharmony_ci skb = sock_wmalloc(sk, 2 + NET_SKB_PAD + sizeof(struct iphdr) + 44062306a36Sopenharmony_ci 4 + len, 0, GFP_KERNEL); 44162306a36Sopenharmony_ci if (!skb) 44262306a36Sopenharmony_ci goto error; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Reserve space for headers, putting IP header on 4-byte boundary. */ 44562306a36Sopenharmony_ci skb_reserve(skb, 2 + NET_SKB_PAD); 44662306a36Sopenharmony_ci skb_reset_network_header(skb); 44762306a36Sopenharmony_ci skb_reserve(skb, sizeof(struct iphdr)); 44862306a36Sopenharmony_ci skb_reset_transport_header(skb); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Insert 0 session_id */ 45162306a36Sopenharmony_ci *((__be32 *)skb_put(skb, 4)) = 0; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Copy user data into skb */ 45462306a36Sopenharmony_ci rc = memcpy_from_msg(skb_put(skb, len), msg, len); 45562306a36Sopenharmony_ci if (rc < 0) { 45662306a36Sopenharmony_ci kfree_skb(skb); 45762306a36Sopenharmony_ci goto error; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci fl4 = &inet->cork.fl.u.ip4; 46162306a36Sopenharmony_ci if (connected) 46262306a36Sopenharmony_ci rt = (struct rtable *)__sk_dst_check(sk, 0); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci rcu_read_lock(); 46562306a36Sopenharmony_ci if (!rt) { 46662306a36Sopenharmony_ci const struct ip_options_rcu *inet_opt; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci inet_opt = rcu_dereference(inet->inet_opt); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Use correct destination address if we have options. */ 47162306a36Sopenharmony_ci if (inet_opt && inet_opt->opt.srr) 47262306a36Sopenharmony_ci daddr = inet_opt->opt.faddr; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* If this fails, retransmit mechanism of transport layer will 47562306a36Sopenharmony_ci * keep trying until route appears or the connection times 47662306a36Sopenharmony_ci * itself out. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci rt = ip_route_output_ports(sock_net(sk), fl4, sk, 47962306a36Sopenharmony_ci daddr, inet->inet_saddr, 48062306a36Sopenharmony_ci inet->inet_dport, inet->inet_sport, 48162306a36Sopenharmony_ci sk->sk_protocol, RT_CONN_FLAGS(sk), 48262306a36Sopenharmony_ci sk->sk_bound_dev_if); 48362306a36Sopenharmony_ci if (IS_ERR(rt)) 48462306a36Sopenharmony_ci goto no_route; 48562306a36Sopenharmony_ci if (connected) { 48662306a36Sopenharmony_ci sk_setup_caps(sk, &rt->dst); 48762306a36Sopenharmony_ci } else { 48862306a36Sopenharmony_ci skb_dst_set(skb, &rt->dst); 48962306a36Sopenharmony_ci goto xmit; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* We don't need to clone dst here, it is guaranteed to not disappear. 49462306a36Sopenharmony_ci * __dev_xmit_skb() might force a refcount if needed. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci skb_dst_set_noref(skb, &rt->dst); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cixmit: 49962306a36Sopenharmony_ci /* Queue the packet to IP for output */ 50062306a36Sopenharmony_ci rc = ip_queue_xmit(sk, skb, &inet->cork.fl); 50162306a36Sopenharmony_ci rcu_read_unlock(); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cierror: 50462306a36Sopenharmony_ci if (rc >= 0) 50562306a36Sopenharmony_ci rc = len; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ciout: 50862306a36Sopenharmony_ci release_sock(sk); 50962306a36Sopenharmony_ci return rc; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cino_route: 51262306a36Sopenharmony_ci rcu_read_unlock(); 51362306a36Sopenharmony_ci IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); 51462306a36Sopenharmony_ci kfree_skb(skb); 51562306a36Sopenharmony_ci rc = -EHOSTUNREACH; 51662306a36Sopenharmony_ci goto out; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int l2tp_ip_recvmsg(struct sock *sk, struct msghdr *msg, 52062306a36Sopenharmony_ci size_t len, int flags, int *addr_len) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 52362306a36Sopenharmony_ci size_t copied = 0; 52462306a36Sopenharmony_ci int err = -EOPNOTSUPP; 52562306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); 52662306a36Sopenharmony_ci struct sk_buff *skb; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (flags & MSG_OOB) 52962306a36Sopenharmony_ci goto out; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 53262306a36Sopenharmony_ci if (!skb) 53362306a36Sopenharmony_ci goto out; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci copied = skb->len; 53662306a36Sopenharmony_ci if (len < copied) { 53762306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 53862306a36Sopenharmony_ci copied = len; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 54262306a36Sopenharmony_ci if (err) 54362306a36Sopenharmony_ci goto done; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci sock_recv_timestamp(msg, sk, skb); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Copy the address. */ 54862306a36Sopenharmony_ci if (sin) { 54962306a36Sopenharmony_ci sin->sin_family = AF_INET; 55062306a36Sopenharmony_ci sin->sin_addr.s_addr = ip_hdr(skb)->saddr; 55162306a36Sopenharmony_ci sin->sin_port = 0; 55262306a36Sopenharmony_ci memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 55362306a36Sopenharmony_ci *addr_len = sizeof(*sin); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci if (inet_cmsg_flags(inet)) 55662306a36Sopenharmony_ci ip_cmsg_recv(msg, skb); 55762306a36Sopenharmony_ci if (flags & MSG_TRUNC) 55862306a36Sopenharmony_ci copied = skb->len; 55962306a36Sopenharmony_cidone: 56062306a36Sopenharmony_ci skb_free_datagram(sk, skb); 56162306a36Sopenharmony_ciout: 56262306a36Sopenharmony_ci return err ? err : copied; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciint l2tp_ioctl(struct sock *sk, int cmd, int *karg) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct sk_buff *skb; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci switch (cmd) { 57062306a36Sopenharmony_ci case SIOCOUTQ: 57162306a36Sopenharmony_ci *karg = sk_wmem_alloc_get(sk); 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci case SIOCINQ: 57462306a36Sopenharmony_ci spin_lock_bh(&sk->sk_receive_queue.lock); 57562306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 57662306a36Sopenharmony_ci *karg = skb ? skb->len : 0; 57762306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_receive_queue.lock); 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci default: 58162306a36Sopenharmony_ci return -ENOIOCTLCMD; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(l2tp_ioctl); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic struct proto l2tp_ip_prot = { 58962306a36Sopenharmony_ci .name = "L2TP/IP", 59062306a36Sopenharmony_ci .owner = THIS_MODULE, 59162306a36Sopenharmony_ci .init = l2tp_ip_open, 59262306a36Sopenharmony_ci .close = l2tp_ip_close, 59362306a36Sopenharmony_ci .bind = l2tp_ip_bind, 59462306a36Sopenharmony_ci .connect = l2tp_ip_connect, 59562306a36Sopenharmony_ci .disconnect = l2tp_ip_disconnect, 59662306a36Sopenharmony_ci .ioctl = l2tp_ioctl, 59762306a36Sopenharmony_ci .destroy = l2tp_ip_destroy_sock, 59862306a36Sopenharmony_ci .setsockopt = ip_setsockopt, 59962306a36Sopenharmony_ci .getsockopt = ip_getsockopt, 60062306a36Sopenharmony_ci .sendmsg = l2tp_ip_sendmsg, 60162306a36Sopenharmony_ci .recvmsg = l2tp_ip_recvmsg, 60262306a36Sopenharmony_ci .backlog_rcv = l2tp_ip_backlog_recv, 60362306a36Sopenharmony_ci .hash = l2tp_ip_hash, 60462306a36Sopenharmony_ci .unhash = l2tp_ip_unhash, 60562306a36Sopenharmony_ci .obj_size = sizeof(struct l2tp_ip_sock), 60662306a36Sopenharmony_ci}; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic const struct proto_ops l2tp_ip_ops = { 60962306a36Sopenharmony_ci .family = PF_INET, 61062306a36Sopenharmony_ci .owner = THIS_MODULE, 61162306a36Sopenharmony_ci .release = inet_release, 61262306a36Sopenharmony_ci .bind = inet_bind, 61362306a36Sopenharmony_ci .connect = inet_dgram_connect, 61462306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 61562306a36Sopenharmony_ci .accept = sock_no_accept, 61662306a36Sopenharmony_ci .getname = l2tp_ip_getname, 61762306a36Sopenharmony_ci .poll = datagram_poll, 61862306a36Sopenharmony_ci .ioctl = inet_ioctl, 61962306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 62062306a36Sopenharmony_ci .listen = sock_no_listen, 62162306a36Sopenharmony_ci .shutdown = inet_shutdown, 62262306a36Sopenharmony_ci .setsockopt = sock_common_setsockopt, 62362306a36Sopenharmony_ci .getsockopt = sock_common_getsockopt, 62462306a36Sopenharmony_ci .sendmsg = inet_sendmsg, 62562306a36Sopenharmony_ci .recvmsg = sock_common_recvmsg, 62662306a36Sopenharmony_ci .mmap = sock_no_mmap, 62762306a36Sopenharmony_ci}; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic struct inet_protosw l2tp_ip_protosw = { 63062306a36Sopenharmony_ci .type = SOCK_DGRAM, 63162306a36Sopenharmony_ci .protocol = IPPROTO_L2TP, 63262306a36Sopenharmony_ci .prot = &l2tp_ip_prot, 63362306a36Sopenharmony_ci .ops = &l2tp_ip_ops, 63462306a36Sopenharmony_ci}; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic struct net_protocol l2tp_ip_protocol __read_mostly = { 63762306a36Sopenharmony_ci .handler = l2tp_ip_recv, 63862306a36Sopenharmony_ci}; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int __init l2tp_ip_init(void) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci int err; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci pr_info("L2TP IP encapsulation support (L2TPv3)\n"); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci err = proto_register(&l2tp_ip_prot, 1); 64762306a36Sopenharmony_ci if (err != 0) 64862306a36Sopenharmony_ci goto out; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci err = inet_add_protocol(&l2tp_ip_protocol, IPPROTO_L2TP); 65162306a36Sopenharmony_ci if (err) 65262306a36Sopenharmony_ci goto out1; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci inet_register_protosw(&l2tp_ip_protosw); 65562306a36Sopenharmony_ci return 0; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ciout1: 65862306a36Sopenharmony_ci proto_unregister(&l2tp_ip_prot); 65962306a36Sopenharmony_ciout: 66062306a36Sopenharmony_ci return err; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic void __exit l2tp_ip_exit(void) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci inet_unregister_protosw(&l2tp_ip_protosw); 66662306a36Sopenharmony_ci inet_del_protocol(&l2tp_ip_protocol, IPPROTO_L2TP); 66762306a36Sopenharmony_ci proto_unregister(&l2tp_ip_prot); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cimodule_init(l2tp_ip_init); 67162306a36Sopenharmony_cimodule_exit(l2tp_ip_exit); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 67462306a36Sopenharmony_ciMODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 67562306a36Sopenharmony_ciMODULE_DESCRIPTION("L2TP over IP"); 67662306a36Sopenharmony_ciMODULE_VERSION("1.0"); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* Use the values of SOCK_DGRAM (2) as type and IPPROTO_L2TP (115) as protocol, 67962306a36Sopenharmony_ci * because __stringify doesn't like enums 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 115, 2); 68262306a36Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO(PF_INET, 115); 683