2019-05-27 14:55:01 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2012-04-30 05:48:54 +08:00
|
|
|
/*
|
|
|
|
* L2TPv3 IP encapsulation support for IPv6
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012 Katalix Systems Ltd
|
|
|
|
*/
|
|
|
|
|
2012-05-16 17:55:56 +08:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
#include <linux/icmp.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/random.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/l2tp.h>
|
|
|
|
#include <linux/in.h>
|
|
|
|
#include <linux/in6.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/ip.h>
|
|
|
|
#include <net/icmp.h>
|
|
|
|
#include <net/udp.h>
|
|
|
|
#include <net/inet_common.h>
|
|
|
|
#include <net/inet_hashtables.h>
|
2016-02-11 00:50:36 +08:00
|
|
|
#include <net/inet6_hashtables.h>
|
2012-04-30 05:48:54 +08:00
|
|
|
#include <net/tcp_states.h>
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <net/xfrm.h>
|
|
|
|
|
|
|
|
#include <net/transp_v6.h>
|
|
|
|
#include <net/addrconf.h>
|
|
|
|
#include <net/ip6_route.h>
|
|
|
|
|
|
|
|
#include "l2tp_core.h"
|
|
|
|
|
|
|
|
struct l2tp_ip6_sock {
|
|
|
|
/* inet_sock has to be the first member of l2tp_ip6_sock */
|
|
|
|
struct inet_sock inet;
|
|
|
|
|
|
|
|
u32 conn_id;
|
|
|
|
u32 peer_conn_id;
|
|
|
|
|
|
|
|
/* ipv6_pinfo has to be the last member of l2tp_ip6_sock, see
|
|
|
|
inet6_sk_generic */
|
|
|
|
struct ipv6_pinfo inet6;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DEFINE_RWLOCK(l2tp_ip6_lock);
|
|
|
|
static struct hlist_head l2tp_ip6_table;
|
|
|
|
static struct hlist_head l2tp_ip6_bind_table;
|
|
|
|
|
|
|
|
static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk)
|
|
|
|
{
|
|
|
|
return (struct l2tp_ip6_sock *)sk;
|
|
|
|
}
|
|
|
|
|
2017-01-07 03:03:55 +08:00
|
|
|
static struct sock *__l2tp_ip6_bind_lookup(const struct net *net,
|
|
|
|
const struct in6_addr *laddr,
|
2016-12-31 02:48:20 +08:00
|
|
|
const struct in6_addr *raddr,
|
2012-04-30 05:48:54 +08:00
|
|
|
int dif, u32 tunnel_id)
|
|
|
|
{
|
|
|
|
struct sock *sk;
|
|
|
|
|
hlist: drop the node parameter from iterators
I'm not sure why, but the hlist for each entry iterators were conceived
list_for_each_entry(pos, head, member)
The hlist ones were greedy and wanted an extra parameter:
hlist_for_each_entry(tpos, pos, head, member)
Why did they need an extra pos parameter? I'm not quite sure. Not only
they don't really need it, it also prevents the iterator from looking
exactly like the list iterator, which is unfortunate.
Besides the semantic patch, there was some manual work required:
- Fix up the actual hlist iterators in linux/list.h
- Fix up the declaration of other iterators based on the hlist ones.
- A very small amount of places were using the 'node' parameter, this
was modified to use 'obj->member' instead.
- Coccinelle didn't handle the hlist_for_each_entry_safe iterator
properly, so those had to be fixed up manually.
The semantic patch which is mostly the work of Peter Senna Tschudin is here:
@@
iterator name hlist_for_each_entry, hlist_for_each_entry_continue, hlist_for_each_entry_from, hlist_for_each_entry_rcu, hlist_for_each_entry_rcu_bh, hlist_for_each_entry_continue_rcu_bh, for_each_busy_worker, ax25_uid_for_each, ax25_for_each, inet_bind_bucket_for_each, sctp_for_each_hentry, sk_for_each, sk_for_each_rcu, sk_for_each_from, sk_for_each_safe, sk_for_each_bound, hlist_for_each_entry_safe, hlist_for_each_entry_continue_rcu, nr_neigh_for_each, nr_neigh_for_each_safe, nr_node_for_each, nr_node_for_each_safe, for_each_gfn_indirect_valid_sp, for_each_gfn_sp, for_each_host;
type T;
expression a,c,d,e;
identifier b;
statement S;
@@
-T b;
<+... when != b
(
hlist_for_each_entry(a,
- b,
c, d) S
|
hlist_for_each_entry_continue(a,
- b,
c) S
|
hlist_for_each_entry_from(a,
- b,
c) S
|
hlist_for_each_entry_rcu(a,
- b,
c, d) S
|
hlist_for_each_entry_rcu_bh(a,
- b,
c, d) S
|
hlist_for_each_entry_continue_rcu_bh(a,
- b,
c) S
|
for_each_busy_worker(a, c,
- b,
d) S
|
ax25_uid_for_each(a,
- b,
c) S
|
ax25_for_each(a,
- b,
c) S
|
inet_bind_bucket_for_each(a,
- b,
c) S
|
sctp_for_each_hentry(a,
- b,
c) S
|
sk_for_each(a,
- b,
c) S
|
sk_for_each_rcu(a,
- b,
c) S
|
sk_for_each_from
-(a, b)
+(a)
S
+ sk_for_each_from(a) S
|
sk_for_each_safe(a,
- b,
c, d) S
|
sk_for_each_bound(a,
- b,
c) S
|
hlist_for_each_entry_safe(a,
- b,
c, d, e) S
|
hlist_for_each_entry_continue_rcu(a,
- b,
c) S
|
nr_neigh_for_each(a,
- b,
c) S
|
nr_neigh_for_each_safe(a,
- b,
c, d) S
|
nr_node_for_each(a,
- b,
c) S
|
nr_node_for_each_safe(a,
- b,
c, d) S
|
- for_each_gfn_sp(a, c, d, b) S
+ for_each_gfn_sp(a, c, d) S
|
- for_each_gfn_indirect_valid_sp(a, c, d, b) S
+ for_each_gfn_indirect_valid_sp(a, c, d) S
|
for_each_host(a,
- b,
c) S
|
for_each_host_safe(a,
- b,
c, d) S
|
for_each_mesh_entry(a,
- b,
c, d) S
)
...+>
[akpm@linux-foundation.org: drop bogus change from net/ipv4/raw.c]
[akpm@linux-foundation.org: drop bogus hunk from net/ipv6/raw.c]
[akpm@linux-foundation.org: checkpatch fixes]
[akpm@linux-foundation.org: fix warnings]
[akpm@linux-foudnation.org: redo intrusive kvm changes]
Tested-by: Peter Senna Tschudin <peter.senna@gmail.com>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-28 09:06:00 +08:00
|
|
|
sk_for_each_bound(sk, &l2tp_ip6_bind_table) {
|
2016-12-31 02:48:19 +08:00
|
|
|
const struct in6_addr *sk_laddr = inet6_rcv_saddr(sk);
|
2016-12-31 02:48:20 +08:00
|
|
|
const struct in6_addr *sk_raddr = &sk->sk_v6_daddr;
|
2017-01-07 03:03:55 +08:00
|
|
|
const struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
2017-01-07 03:03:57 +08:00
|
|
|
if (!net_eq(sock_net(sk), net))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (sk->sk_bound_dev_if && dif && sk->sk_bound_dev_if != dif)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (sk_laddr && !ipv6_addr_any(sk_laddr) &&
|
|
|
|
!ipv6_addr_any(laddr) && !ipv6_addr_equal(sk_laddr, laddr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!ipv6_addr_any(sk_raddr) && raddr &&
|
|
|
|
!ipv6_addr_any(raddr) && !ipv6_addr_equal(sk_raddr, raddr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (l2tp->conn_id != tunnel_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
goto found;
|
2012-04-30 05:48:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
sk = NULL;
|
|
|
|
found:
|
|
|
|
return sk;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When processing receive frames, there are two cases to
|
|
|
|
* consider. Data frames consist of a non-zero session-id and an
|
|
|
|
* optional cookie. Control frames consist of a regular L2TP header
|
|
|
|
* preceded by 32-bits of zeros.
|
|
|
|
*
|
|
|
|
* L2TPv3 Session Header Over IP
|
|
|
|
*
|
|
|
|
* 0 1 2 3
|
|
|
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* | Session ID |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* | Cookie (optional, maximum 64 bits)...
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
*
|
|
|
|
* L2TPv3 Control Message Header Over IP
|
|
|
|
*
|
|
|
|
* 0 1 2 3
|
|
|
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* | (32 bits of zeros) |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* |T|L|x|x|S|x|x|x|x|x|x|x| Ver | Length |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* | Control Connection ID |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
* | Ns | Nr |
|
|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
*
|
|
|
|
* All control frames are passed to userspace.
|
|
|
|
*/
|
|
|
|
static int l2tp_ip6_recv(struct sk_buff *skb)
|
|
|
|
{
|
2016-05-27 01:16:36 +08:00
|
|
|
struct net *net = dev_net(skb->dev);
|
2012-04-30 05:48:54 +08:00
|
|
|
struct sock *sk;
|
|
|
|
u32 session_id;
|
|
|
|
u32 tunnel_id;
|
|
|
|
unsigned char *ptr, *optr;
|
|
|
|
struct l2tp_session *session;
|
|
|
|
struct l2tp_tunnel *tunnel = NULL;
|
2017-11-03 23:49:00 +08:00
|
|
|
struct ipv6hdr *iph;
|
2012-04-30 05:48:54 +08:00
|
|
|
int length;
|
|
|
|
|
|
|
|
if (!pskb_may_pull(skb, 4))
|
|
|
|
goto discard;
|
|
|
|
|
2016-04-03 22:09:24 +08:00
|
|
|
/* Point to L2TP header */
|
|
|
|
optr = ptr = skb->data;
|
2012-04-30 05:48:54 +08:00
|
|
|
session_id = ntohl(*((__be32 *) ptr));
|
|
|
|
ptr += 4;
|
|
|
|
|
|
|
|
/* RFC3931: L2TP/IP packets have the first 4 bytes containing
|
|
|
|
* the session_id. If it is 0, the packet is a L2TP control
|
|
|
|
* frame and the session_id value can be discarded.
|
|
|
|
*/
|
|
|
|
if (session_id == 0) {
|
|
|
|
__skb_pull(skb, 4);
|
|
|
|
goto pass_up;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, this is a data packet. Lookup the session. */
|
2018-08-10 19:21:57 +08:00
|
|
|
session = l2tp_session_get(net, session_id);
|
2017-03-31 19:02:25 +08:00
|
|
|
if (!session)
|
2012-04-30 05:48:54 +08:00
|
|
|
goto discard;
|
|
|
|
|
|
|
|
tunnel = session->tunnel;
|
2017-03-31 19:02:25 +08:00
|
|
|
if (!tunnel)
|
|
|
|
goto discard_sess;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
/* Trace packet contents, if enabled */
|
|
|
|
if (tunnel->debug & L2TP_MSG_DATA) {
|
|
|
|
length = min(32u, skb->len);
|
|
|
|
if (!pskb_may_pull(skb, length))
|
2017-03-31 19:02:25 +08:00
|
|
|
goto discard_sess;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
2016-04-03 22:09:24 +08:00
|
|
|
/* Point to L2TP header */
|
|
|
|
optr = ptr = skb->data;
|
|
|
|
ptr += 4;
|
2012-05-16 17:55:56 +08:00
|
|
|
pr_debug("%s: ip recv\n", tunnel->name);
|
|
|
|
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length);
|
2012-04-30 05:48:54 +08:00
|
|
|
}
|
|
|
|
|
2019-01-30 14:55:14 +08:00
|
|
|
if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr))
|
|
|
|
goto discard_sess;
|
|
|
|
|
2018-07-25 20:53:33 +08:00
|
|
|
l2tp_recv_common(session, skb, ptr, optr, 0, skb->len);
|
2017-03-31 19:02:25 +08:00
|
|
|
l2tp_session_dec_refcount(session);
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
pass_up:
|
|
|
|
/* Get the tunnel_id from the L2TP header */
|
|
|
|
if (!pskb_may_pull(skb, 12))
|
|
|
|
goto discard;
|
|
|
|
|
|
|
|
if ((skb->data[0] & 0xc0) != 0xc0)
|
|
|
|
goto discard;
|
|
|
|
|
|
|
|
tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
|
2017-11-03 23:49:00 +08:00
|
|
|
iph = ipv6_hdr(skb);
|
|
|
|
|
|
|
|
read_lock_bh(&l2tp_ip6_lock);
|
|
|
|
sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr,
|
|
|
|
inet6_iif(skb), tunnel_id);
|
|
|
|
if (!sk) {
|
2012-04-30 05:48:54 +08:00
|
|
|
read_unlock_bh(&l2tp_ip6_lock);
|
2017-11-03 23:49:00 +08:00
|
|
|
goto discard;
|
2012-04-30 05:48:54 +08:00
|
|
|
}
|
2017-11-03 23:49:00 +08:00
|
|
|
sock_hold(sk);
|
|
|
|
read_unlock_bh(&l2tp_ip6_lock);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
|
|
|
|
goto discard_put;
|
|
|
|
|
|
|
|
nf_reset(skb);
|
|
|
|
|
|
|
|
return sk_receive_skb(sk, skb, 1);
|
|
|
|
|
2017-03-31 19:02:25 +08:00
|
|
|
discard_sess:
|
|
|
|
l2tp_session_dec_refcount(session);
|
|
|
|
goto discard;
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
discard_put:
|
|
|
|
sock_put(sk);
|
|
|
|
|
|
|
|
discard:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l2tp_ip6_open(struct sock *sk)
|
|
|
|
{
|
|
|
|
/* Prevent autobind. We don't have ports. */
|
|
|
|
inet_sk(sk)->inet_num = IPPROTO_L2TP;
|
|
|
|
|
|
|
|
write_lock_bh(&l2tp_ip6_lock);
|
|
|
|
sk_add_node(sk, &l2tp_ip6_table);
|
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void l2tp_ip6_close(struct sock *sk, long timeout)
|
|
|
|
{
|
|
|
|
write_lock_bh(&l2tp_ip6_lock);
|
|
|
|
hlist_del_init(&sk->sk_bind_node);
|
|
|
|
sk_del_node_init(sk);
|
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
|
|
|
|
|
sk_common_release(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void l2tp_ip6_destroy_sock(struct sock *sk)
|
|
|
|
{
|
l2tp: fix races with tunnel socket close
The tunnel socket tunnel->sock (struct sock) is accessed when
preparing a new ppp session on a tunnel at pppol2tp_session_init. If
the socket is closed by a thread while another is creating a new
session, the threads race. In pppol2tp_connect, the tunnel object may
be created if the pppol2tp socket is associated with the special
session_id 0 and the tunnel socket is looked up using the provided
fd. When handling this, pppol2tp_connect cannot sock_hold the tunnel
socket to prevent it being destroyed during pppol2tp_connect since
this may itself may race with the socket being destroyed. Doing
sockfd_lookup in pppol2tp_connect isn't sufficient to prevent
tunnel->sock going away either because a given tunnel socket fd may be
reused between calls to pppol2tp_connect. Instead, have
l2tp_tunnel_create sock_hold the tunnel socket before it does
sockfd_put. This ensures that the tunnel's socket is always extant
while the tunnel object exists. Hold a ref on the socket until the
tunnel is destroyed and ensure that all tunnel destroy paths go
through a common function (l2tp_tunnel_delete) since this will do the
final sock_put to release the tunnel socket.
Since the tunnel's socket is now guaranteed to exist if the tunnel
exists, we no longer need to use sockfd_lookup via l2tp_sock_to_tunnel
to derive the tunnel from the socket since this is always
sk_user_data.
Also, sessions no longer sock_hold the tunnel socket since sessions
already hold a tunnel ref and the tunnel sock will not be freed until
the tunnel is freed. Removing these sock_holds in
l2tp_session_register avoids a possible sock leak in the
pppol2tp_connect error path if l2tp_session_register succeeds but
attaching a ppp channel fails. The pppol2tp_connect error path could
have been fixed instead and have the sock ref dropped when the session
is freed, but doing a sock_put of the tunnel socket when the session
is freed would require a new session_free callback. It is simpler to
just remove the sock_hold of the tunnel socket in
l2tp_session_register, now that the tunnel socket lifetime is
guaranteed.
Finally, some init code in l2tp_tunnel_create is reordered to ensure
that the new tunnel object's refcount is set and the tunnel socket ref
is taken before the tunnel socket destructor callbacks are set.
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] SMP KASAN
Modules linked in:
CPU: 0 PID: 4360 Comm: syzbot_19c09769 Not tainted 4.16.0-rc2+ #34
Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
RIP: 0010:pppol2tp_session_init+0x1d6/0x500
RSP: 0018:ffff88001377fb40 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: ffff88001636a940 RCX: ffffffff84836c1d
RDX: 0000000000000045 RSI: 0000000055976744 RDI: 0000000000000228
RBP: ffff88001377fb60 R08: ffffffff84836bc8 R09: 0000000000000002
R10: ffff88001377fab8 R11: 0000000000000001 R12: 0000000000000000
R13: ffff88001636aac8 R14: ffff8800160f81c0 R15: 1ffff100026eff76
FS: 00007ffb3ea66700(0000) GS:ffff88001a400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020e77000 CR3: 0000000016261000 CR4: 00000000000006f0
Call Trace:
pppol2tp_connect+0xd18/0x13c0
? pppol2tp_session_create+0x170/0x170
? __might_fault+0x115/0x1d0
? lock_downgrade+0x860/0x860
? __might_fault+0xe5/0x1d0
? security_socket_connect+0x8e/0xc0
SYSC_connect+0x1b6/0x310
? SYSC_bind+0x280/0x280
? __do_page_fault+0x5d1/0xca0
? up_read+0x1f/0x40
? __do_page_fault+0x3c8/0xca0
SyS_connect+0x29/0x30
? SyS_accept+0x40/0x40
do_syscall_64+0x1e0/0x730
? trace_hardirqs_off_thunk+0x1a/0x1c
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x7ffb3e376259
RSP: 002b:00007ffeda4f6508 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000020e77012 RCX: 00007ffb3e376259
RDX: 000000000000002e RSI: 0000000020e77000 RDI: 0000000000000004
RBP: 00007ffeda4f6540 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400b60
R13: 00007ffeda4f6660 R14: 0000000000000000 R15: 0000000000000000
Code: 80 3d b0 ff 06 02 00 0f 84 07 02 00 00 e8 13 d6 db fc 49 8d bc 24 28 02 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 f
a 48 c1 ea 03 <80> 3c 02 00 0f 85 ed 02 00 00 4d 8b a4 24 28 02 00 00 e8 13 16
Fixes: 80d84ef3ff1dd ("l2tp: prevent l2tp_tunnel_delete racing with userspace close")
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-24 01:45:45 +08:00
|
|
|
struct l2tp_tunnel *tunnel = sk->sk_user_data;
|
2013-03-19 14:11:15 +08:00
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
lock_sock(sk);
|
|
|
|
ip6_flush_pending_frames(sk);
|
|
|
|
release_sock(sk);
|
|
|
|
|
l2tp: fix races with tunnel socket close
The tunnel socket tunnel->sock (struct sock) is accessed when
preparing a new ppp session on a tunnel at pppol2tp_session_init. If
the socket is closed by a thread while another is creating a new
session, the threads race. In pppol2tp_connect, the tunnel object may
be created if the pppol2tp socket is associated with the special
session_id 0 and the tunnel socket is looked up using the provided
fd. When handling this, pppol2tp_connect cannot sock_hold the tunnel
socket to prevent it being destroyed during pppol2tp_connect since
this may itself may race with the socket being destroyed. Doing
sockfd_lookup in pppol2tp_connect isn't sufficient to prevent
tunnel->sock going away either because a given tunnel socket fd may be
reused between calls to pppol2tp_connect. Instead, have
l2tp_tunnel_create sock_hold the tunnel socket before it does
sockfd_put. This ensures that the tunnel's socket is always extant
while the tunnel object exists. Hold a ref on the socket until the
tunnel is destroyed and ensure that all tunnel destroy paths go
through a common function (l2tp_tunnel_delete) since this will do the
final sock_put to release the tunnel socket.
Since the tunnel's socket is now guaranteed to exist if the tunnel
exists, we no longer need to use sockfd_lookup via l2tp_sock_to_tunnel
to derive the tunnel from the socket since this is always
sk_user_data.
Also, sessions no longer sock_hold the tunnel socket since sessions
already hold a tunnel ref and the tunnel sock will not be freed until
the tunnel is freed. Removing these sock_holds in
l2tp_session_register avoids a possible sock leak in the
pppol2tp_connect error path if l2tp_session_register succeeds but
attaching a ppp channel fails. The pppol2tp_connect error path could
have been fixed instead and have the sock ref dropped when the session
is freed, but doing a sock_put of the tunnel socket when the session
is freed would require a new session_free callback. It is simpler to
just remove the sock_hold of the tunnel socket in
l2tp_session_register, now that the tunnel socket lifetime is
guaranteed.
Finally, some init code in l2tp_tunnel_create is reordered to ensure
that the new tunnel object's refcount is set and the tunnel socket ref
is taken before the tunnel socket destructor callbacks are set.
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] SMP KASAN
Modules linked in:
CPU: 0 PID: 4360 Comm: syzbot_19c09769 Not tainted 4.16.0-rc2+ #34
Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
RIP: 0010:pppol2tp_session_init+0x1d6/0x500
RSP: 0018:ffff88001377fb40 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: ffff88001636a940 RCX: ffffffff84836c1d
RDX: 0000000000000045 RSI: 0000000055976744 RDI: 0000000000000228
RBP: ffff88001377fb60 R08: ffffffff84836bc8 R09: 0000000000000002
R10: ffff88001377fab8 R11: 0000000000000001 R12: 0000000000000000
R13: ffff88001636aac8 R14: ffff8800160f81c0 R15: 1ffff100026eff76
FS: 00007ffb3ea66700(0000) GS:ffff88001a400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020e77000 CR3: 0000000016261000 CR4: 00000000000006f0
Call Trace:
pppol2tp_connect+0xd18/0x13c0
? pppol2tp_session_create+0x170/0x170
? __might_fault+0x115/0x1d0
? lock_downgrade+0x860/0x860
? __might_fault+0xe5/0x1d0
? security_socket_connect+0x8e/0xc0
SYSC_connect+0x1b6/0x310
? SYSC_bind+0x280/0x280
? __do_page_fault+0x5d1/0xca0
? up_read+0x1f/0x40
? __do_page_fault+0x3c8/0xca0
SyS_connect+0x29/0x30
? SyS_accept+0x40/0x40
do_syscall_64+0x1e0/0x730
? trace_hardirqs_off_thunk+0x1a/0x1c
entry_SYSCALL_64_after_hwframe+0x42/0xb7
RIP: 0033:0x7ffb3e376259
RSP: 002b:00007ffeda4f6508 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000020e77012 RCX: 00007ffb3e376259
RDX: 000000000000002e RSI: 0000000020e77000 RDI: 0000000000000004
RBP: 00007ffeda4f6540 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400b60
R13: 00007ffeda4f6660 R14: 0000000000000000 R15: 0000000000000000
Code: 80 3d b0 ff 06 02 00 0f 84 07 02 00 00 e8 13 d6 db fc 49 8d bc 24 28 02 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 f
a 48 c1 ea 03 <80> 3c 02 00 0f 85 ed 02 00 00 4d 8b a4 24 28 02 00 00 e8 13 16
Fixes: 80d84ef3ff1dd ("l2tp: prevent l2tp_tunnel_delete racing with userspace close")
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-02-24 01:45:45 +08:00
|
|
|
if (tunnel)
|
|
|
|
l2tp_tunnel_delete(tunnel);
|
2013-03-19 14:11:15 +08:00
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
inet6_destroy_sock(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|
|
|
{
|
|
|
|
struct inet_sock *inet = inet_sk(sk);
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
|
2016-05-27 01:16:36 +08:00
|
|
|
struct net *net = sock_net(sk);
|
2012-04-30 05:48:54 +08:00
|
|
|
__be32 v4addr = 0;
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
int bound_dev_if;
|
2012-04-30 05:48:54 +08:00
|
|
|
int addr_type;
|
|
|
|
int err;
|
|
|
|
|
2012-05-29 11:30:42 +08:00
|
|
|
if (addr->l2tp_family != AF_INET6)
|
|
|
|
return -EINVAL;
|
2012-04-30 05:48:54 +08:00
|
|
|
if (addr_len < sizeof(*addr))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
addr_type = ipv6_addr_type(&addr->l2tp_addr);
|
|
|
|
|
|
|
|
/* l2tp_ip6 sockets are IPv6 only */
|
|
|
|
if (addr_type == IPV6_ADDR_MAPPED)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
/* L2TP is point-point, not multicast */
|
|
|
|
if (addr_type & IPV6_ADDR_MULTICAST)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
err = -EINVAL;
|
2016-11-19 05:13:00 +08:00
|
|
|
if (!sock_flag(sk, SOCK_ZAPPED))
|
|
|
|
goto out_unlock;
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
if (sk->sk_state != TCP_CLOSE)
|
|
|
|
goto out_unlock;
|
|
|
|
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
bound_dev_if = sk->sk_bound_dev_if;
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
/* Check if the address belongs to the host. */
|
|
|
|
rcu_read_lock();
|
|
|
|
if (addr_type != IPV6_ADDR_ANY) {
|
|
|
|
struct net_device *dev = NULL;
|
|
|
|
|
|
|
|
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
if (addr->l2tp_scope_id)
|
|
|
|
bound_dev_if = addr->l2tp_scope_id;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
/* Binding to link-local address requires an
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
* interface.
|
|
|
|
*/
|
|
|
|
if (!bound_dev_if)
|
2012-04-30 05:48:54 +08:00
|
|
|
goto out_unlock_rcu;
|
|
|
|
|
|
|
|
err = -ENODEV;
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if);
|
2012-04-30 05:48:54 +08:00
|
|
|
if (!dev)
|
|
|
|
goto out_unlock_rcu;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ipv4 addr of the socket is invalid. Only the
|
|
|
|
* unspecified and mapped address have a v4 equivalent.
|
|
|
|
*/
|
|
|
|
v4addr = LOOPBACK4_IPV6;
|
|
|
|
err = -EADDRNOTAVAIL;
|
|
|
|
if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0))
|
|
|
|
goto out_unlock_rcu;
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
write_lock_bh(&l2tp_ip6_lock);
|
2016-12-31 02:48:20 +08:00
|
|
|
if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, NULL, bound_dev_if,
|
l2tp: fix racy socket lookup in l2tp_ip and l2tp_ip6 bind()
It's not enough to check for sockets bound to same address at the
beginning of l2tp_ip{,6}_bind(): even if no socket is found at that
time, a socket with the same address could be bound before we take
the l2tp lock again.
This patch moves the lookup right before inserting the new socket, so
that no change can ever happen to the list between address lookup and
socket insertion.
Care is taken to avoid side effects on the socket in case of failure.
That is, modifications of the socket are done after the lookup, when
binding is guaranteed to succeed, and before releasing the l2tp lock,
so that concurrent lookups will always see fully initialised sockets.
For l2tp_ip, 'ret' is set to -EINVAL before checking the SOCK_ZAPPED
bit. Error code was mistakenly set to -EADDRINUSE on error by commit
32c231164b76 ("l2tp: fix racy SOCK_ZAPPED flag check in l2tp_ip{,6}_bind()").
Using -EINVAL restores original behaviour.
For l2tp_ip6, the lookup is now always done with the correct bound
device. Before this patch, when binding to a link-local address, the
lookup was done with the original sk->sk_bound_dev_if, which was later
overwritten with addr->l2tp_scope_id. Lookup is now performed with the
final sk->sk_bound_dev_if value.
Finally, the (addr_len >= sizeof(struct sockaddr_in6)) check has been
dropped: addr is a sockaddr_l2tpip6 not sockaddr_in6 and addr_len has
already been checked at this point (this part of the code seems to have
been copy-pasted from net/ipv6/raw.c).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-29 20:09:46 +08:00
|
|
|
addr->l2tp_conn_id)) {
|
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
|
err = -EADDRINUSE;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
inet->inet_saddr = v4addr;
|
|
|
|
inet->inet_rcv_saddr = v4addr;
|
|
|
|
sk->sk_bound_dev_if = bound_dev_if;
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
sk->sk_v6_rcv_saddr = addr->l2tp_addr;
|
2012-04-30 05:48:54 +08:00
|
|
|
np->saddr = addr->l2tp_addr;
|
|
|
|
|
|
|
|
l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id;
|
|
|
|
|
|
|
|
sk_add_bind_node(sk, &l2tp_ip6_bind_table);
|
|
|
|
sk_del_node_init(sk);
|
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
|
|
2012-05-29 11:30:42 +08:00
|
|
|
sock_reset_flag(sk, SOCK_ZAPPED);
|
2012-04-30 05:48:54 +08:00
|
|
|
release_sock(sk);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_unlock_rcu:
|
|
|
|
rcu_read_unlock();
|
|
|
|
out_unlock:
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
|
int addr_len)
|
|
|
|
{
|
|
|
|
struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *) uaddr;
|
|
|
|
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
|
|
|
|
struct in6_addr *daddr;
|
|
|
|
int addr_type;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (addr_len < sizeof(*lsa))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-01-20 12:16:39 +08:00
|
|
|
if (usin->sin6_family != AF_INET6)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
addr_type = ipv6_addr_type(&usin->sin6_addr);
|
|
|
|
if (addr_type & IPV6_ADDR_MULTICAST)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (addr_type & IPV6_ADDR_MAPPED) {
|
|
|
|
daddr = &usin->sin6_addr;
|
|
|
|
if (ipv4_is_multicast(daddr->s6_addr32[3]))
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
2016-11-29 20:09:44 +08:00
|
|
|
/* Must bind first - autobinding does not work */
|
|
|
|
if (sock_flag(sk, SOCK_ZAPPED)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out_sk;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = __ip6_datagram_connect(sk, uaddr, addr_len);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out_sk;
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
|
|
|
|
|
|
|
|
write_lock_bh(&l2tp_ip6_lock);
|
|
|
|
hlist_del_init(&sk->sk_bind_node);
|
|
|
|
sk_add_bind_node(sk, &l2tp_ip6_bind_table);
|
|
|
|
write_unlock_bh(&l2tp_ip6_lock);
|
|
|
|
|
2016-11-29 20:09:44 +08:00
|
|
|
out_sk:
|
2012-04-30 05:48:54 +08:00
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-05-29 11:30:42 +08:00
|
|
|
static int l2tp_ip6_disconnect(struct sock *sk, int flags)
|
|
|
|
{
|
|
|
|
if (sock_flag(sk, SOCK_ZAPPED))
|
|
|
|
return 0;
|
|
|
|
|
2016-10-21 00:39:40 +08:00
|
|
|
return __udp_disconnect(sk, flags);
|
2012-05-29 11:30:42 +08:00
|
|
|
}
|
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
|
2018-02-13 03:00:20 +08:00
|
|
|
int peer)
|
2012-04-30 05:48:54 +08:00
|
|
|
{
|
|
|
|
struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr;
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk);
|
|
|
|
|
|
|
|
lsa->l2tp_family = AF_INET6;
|
|
|
|
lsa->l2tp_flowinfo = 0;
|
|
|
|
lsa->l2tp_scope_id = 0;
|
2012-08-15 19:31:52 +08:00
|
|
|
lsa->l2tp_unused = 0;
|
2012-04-30 05:48:54 +08:00
|
|
|
if (peer) {
|
|
|
|
if (!lsk->peer_conn_id)
|
|
|
|
return -ENOTCONN;
|
|
|
|
lsa->l2tp_conn_id = lsk->peer_conn_id;
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
lsa->l2tp_addr = sk->sk_v6_daddr;
|
2012-04-30 05:48:54 +08:00
|
|
|
if (np->sndflow)
|
|
|
|
lsa->l2tp_flowinfo = np->flow_label;
|
|
|
|
} else {
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
if (ipv6_addr_any(&sk->sk_v6_rcv_saddr))
|
2012-04-30 05:48:54 +08:00
|
|
|
lsa->l2tp_addr = np->saddr;
|
|
|
|
else
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
lsa->l2tp_addr = sk->sk_v6_rcv_saddr;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
lsa->l2tp_conn_id = lsk->conn_id;
|
|
|
|
}
|
|
|
|
if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
|
|
|
|
lsa->l2tp_scope_id = sk->sk_bound_dev_if;
|
2018-02-13 03:00:20 +08:00
|
|
|
return sizeof(*lsa);
|
2012-04-30 05:48:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Charge it to the socket, dropping if the queue is full. */
|
|
|
|
rc = sock_queue_rcv_skb(sk, skb);
|
|
|
|
if (rc < 0)
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
drop:
|
2016-05-27 01:16:36 +08:00
|
|
|
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);
|
2012-04-30 05:48:54 +08:00
|
|
|
kfree_skb(skb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l2tp_ip6_push_pending_frames(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
__be32 *transhdr = NULL;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
skb = skb_peek(&sk->sk_write_queue);
|
|
|
|
if (skb == NULL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
transhdr = (__be32 *)skb_transport_header(skb);
|
|
|
|
*transhdr = 0;
|
|
|
|
|
|
|
|
err = ip6_push_pending_frames(sk);
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Userspace will call sendmsg() on the tunnel socket to send L2TP
|
|
|
|
* control frames.
|
|
|
|
*/
|
2015-03-02 15:37:48 +08:00
|
|
|
static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
2012-04-30 05:48:54 +08:00
|
|
|
{
|
|
|
|
struct ipv6_txoptions opt_space;
|
2014-01-18 05:53:15 +08:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
|
2012-04-30 05:48:54 +08:00
|
|
|
struct in6_addr *daddr, *final_p, final;
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
2015-11-30 11:37:57 +08:00
|
|
|
struct ipv6_txoptions *opt_to_free = NULL;
|
2012-04-30 05:48:54 +08:00
|
|
|
struct ipv6_txoptions *opt = NULL;
|
|
|
|
struct ip6_flowlabel *flowlabel = NULL;
|
|
|
|
struct dst_entry *dst = NULL;
|
|
|
|
struct flowi6 fl6;
|
2016-05-03 12:40:07 +08:00
|
|
|
struct ipcm6_cookie ipc6;
|
2012-04-30 05:48:54 +08:00
|
|
|
int addr_len = msg->msg_namelen;
|
|
|
|
int transhdrlen = 4; /* zero session-id */
|
|
|
|
int ulen = len + transhdrlen;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Rough check on arithmetic overflow,
|
|
|
|
better check is made in ip6_append_data().
|
|
|
|
*/
|
|
|
|
if (len > INT_MAX)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
/* Mirror BSD error message compatibility */
|
|
|
|
if (msg->msg_flags & MSG_OOB)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get and verify the address.
|
|
|
|
*/
|
|
|
|
memset(&fl6, 0, sizeof(fl6));
|
|
|
|
|
|
|
|
fl6.flowi6_mark = sk->sk_mark;
|
2016-11-04 01:23:43 +08:00
|
|
|
fl6.flowi6_uid = sk->sk_uid;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
2018-07-06 22:12:55 +08:00
|
|
|
ipcm6_init(&ipc6);
|
2016-05-03 12:40:07 +08:00
|
|
|
|
2012-04-30 05:48:54 +08:00
|
|
|
if (lsa) {
|
|
|
|
if (addr_len < SIN6_LEN_RFC2133)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (lsa->l2tp_family && lsa->l2tp_family != AF_INET6)
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
|
|
|
|
daddr = &lsa->l2tp_addr;
|
|
|
|
if (np->sndflow) {
|
|
|
|
fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK;
|
|
|
|
if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
|
|
|
|
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
|
|
|
|
if (flowlabel == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise it will be difficult to maintain
|
|
|
|
* sk->sk_dst_cache.
|
|
|
|
*/
|
|
|
|
if (sk->sk_state == TCP_ESTABLISHED &&
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
ipv6_addr_equal(daddr, &sk->sk_v6_daddr))
|
|
|
|
daddr = &sk->sk_v6_daddr;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
if (addr_len >= sizeof(struct sockaddr_in6) &&
|
|
|
|
lsa->l2tp_scope_id &&
|
|
|
|
ipv6_addr_type(daddr) & IPV6_ADDR_LINKLOCAL)
|
|
|
|
fl6.flowi6_oif = lsa->l2tp_scope_id;
|
|
|
|
} else {
|
|
|
|
if (sk->sk_state != TCP_ESTABLISHED)
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
daddr = &sk->sk_v6_daddr;
|
2012-04-30 05:48:54 +08:00
|
|
|
fl6.flowlabel = np->flow_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fl6.flowi6_oif == 0)
|
|
|
|
fl6.flowi6_oif = sk->sk_bound_dev_if;
|
|
|
|
|
|
|
|
if (msg->msg_controllen) {
|
|
|
|
opt = &opt_space;
|
|
|
|
memset(opt, 0, sizeof(struct ipv6_txoptions));
|
|
|
|
opt->tot_len = sizeof(struct ipv6_txoptions);
|
2016-05-03 12:40:07 +08:00
|
|
|
ipc6.opt = opt;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
2018-07-06 22:12:57 +08:00
|
|
|
err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6);
|
2016-05-03 12:40:07 +08:00
|
|
|
if (err < 0) {
|
2012-04-30 05:48:54 +08:00
|
|
|
fl6_sock_release(flowlabel);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if ((fl6.flowlabel & IPV6_FLOWLABEL_MASK) && !flowlabel) {
|
|
|
|
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
|
|
|
|
if (flowlabel == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (!(opt->opt_nflen|opt->opt_flen))
|
|
|
|
opt = NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-30 11:37:57 +08:00
|
|
|
if (!opt) {
|
|
|
|
opt = txopt_get(np);
|
|
|
|
opt_to_free = opt;
|
|
|
|
}
|
2012-04-30 05:48:54 +08:00
|
|
|
if (flowlabel)
|
|
|
|
opt = fl6_merge_options(&opt_space, flowlabel, opt);
|
|
|
|
opt = ipv6_fixup_options(&opt_space, opt);
|
2016-05-03 12:40:07 +08:00
|
|
|
ipc6.opt = opt;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
fl6.flowi6_proto = sk->sk_protocol;
|
|
|
|
if (!ipv6_addr_any(daddr))
|
|
|
|
fl6.daddr = *daddr;
|
|
|
|
else
|
|
|
|
fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
|
|
|
|
if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
|
|
|
|
fl6.saddr = np->saddr;
|
|
|
|
|
|
|
|
final_p = fl6_update_dst(&fl6, opt, &final);
|
|
|
|
|
|
|
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
|
|
|
fl6.flowi6_oif = np->mcast_oif;
|
|
|
|
else if (!fl6.flowi6_oif)
|
|
|
|
fl6.flowi6_oif = np->ucast_oif;
|
|
|
|
|
|
|
|
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
|
|
|
|
|
2016-06-12 02:08:19 +08:00
|
|
|
if (ipc6.tclass < 0)
|
|
|
|
ipc6.tclass = np->tclass;
|
|
|
|
|
|
|
|
fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
|
|
|
|
|
2013-08-28 14:04:14 +08:00
|
|
|
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
|
2012-04-30 05:48:54 +08:00
|
|
|
if (IS_ERR(dst)) {
|
|
|
|
err = PTR_ERR(dst);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-05-03 12:40:07 +08:00
|
|
|
if (ipc6.hlimit < 0)
|
|
|
|
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
2016-05-03 12:40:07 +08:00
|
|
|
if (ipc6.dontfrag < 0)
|
|
|
|
ipc6.dontfrag = np->dontfrag;
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
if (msg->msg_flags & MSG_CONFIRM)
|
|
|
|
goto do_confirm;
|
|
|
|
|
|
|
|
back_from_confirm:
|
|
|
|
lock_sock(sk);
|
2014-11-25 02:23:40 +08:00
|
|
|
err = ip6_append_data(sk, ip_generic_getfrag, msg,
|
2016-05-03 12:40:07 +08:00
|
|
|
ulen, transhdrlen, &ipc6,
|
2012-04-30 05:48:54 +08:00
|
|
|
&fl6, (struct rt6_info *)dst,
|
2018-07-06 22:12:57 +08:00
|
|
|
msg->msg_flags);
|
2012-04-30 05:48:54 +08:00
|
|
|
if (err)
|
|
|
|
ip6_flush_pending_frames(sk);
|
|
|
|
else if (!(msg->msg_flags & MSG_MORE))
|
|
|
|
err = l2tp_ip6_push_pending_frames(sk);
|
|
|
|
release_sock(sk);
|
|
|
|
done:
|
|
|
|
dst_release(dst);
|
|
|
|
out:
|
|
|
|
fl6_sock_release(flowlabel);
|
2015-11-30 11:37:57 +08:00
|
|
|
txopt_put(opt_to_free);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
return err < 0 ? err : len;
|
|
|
|
|
|
|
|
do_confirm:
|
2017-02-07 05:14:16 +08:00
|
|
|
if (msg->msg_flags & MSG_PROBE)
|
|
|
|
dst_confirm_neigh(dst, &fl6.daddr);
|
2012-04-30 05:48:54 +08:00
|
|
|
if (!(msg->msg_flags & MSG_PROBE) || len)
|
|
|
|
goto back_from_confirm;
|
|
|
|
err = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-03-02 15:37:48 +08:00
|
|
|
static int l2tp_ip6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|
|
|
int noblock, int flags, int *addr_len)
|
2012-04-30 05:48:54 +08:00
|
|
|
{
|
2013-01-31 09:02:26 +08:00
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
2014-01-18 05:53:15 +08:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
|
2012-04-30 05:48:54 +08:00
|
|
|
size_t copied = 0;
|
|
|
|
int err = -EOPNOTSUPP;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (flags & MSG_OOB)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (flags & MSG_ERRQUEUE)
|
2013-11-23 07:46:12 +08:00
|
|
|
return ipv6_recv_error(sk, msg, len, addr_len);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
skb = skb_recv_datagram(sk, flags, noblock, &err);
|
|
|
|
if (!skb)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
copied = skb->len;
|
|
|
|
if (len < copied) {
|
|
|
|
msg->msg_flags |= MSG_TRUNC;
|
|
|
|
copied = len;
|
|
|
|
}
|
|
|
|
|
2014-11-06 05:46:40 +08:00
|
|
|
err = skb_copy_datagram_msg(skb, 0, msg, copied);
|
2012-04-30 05:48:54 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
sock_recv_timestamp(msg, sk, skb);
|
|
|
|
|
|
|
|
/* Copy the address. */
|
|
|
|
if (lsa) {
|
|
|
|
lsa->l2tp_family = AF_INET6;
|
|
|
|
lsa->l2tp_unused = 0;
|
|
|
|
lsa->l2tp_addr = ipv6_hdr(skb)->saddr;
|
|
|
|
lsa->l2tp_flowinfo = 0;
|
|
|
|
lsa->l2tp_scope_id = 0;
|
2013-04-07 09:51:55 +08:00
|
|
|
lsa->l2tp_conn_id = 0;
|
2012-04-30 05:48:54 +08:00
|
|
|
if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
|
2014-08-01 09:52:58 +08:00
|
|
|
lsa->l2tp_scope_id = inet6_iif(skb);
|
2019-03-12 21:50:11 +08:00
|
|
|
*addr_len = sizeof(*lsa);
|
2012-04-30 05:48:54 +08:00
|
|
|
}
|
|
|
|
|
2013-01-31 09:02:26 +08:00
|
|
|
if (np->rxopt.all)
|
|
|
|
ip6_datagram_recv_ctl(sk, msg, skb);
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
if (flags & MSG_TRUNC)
|
|
|
|
copied = skb->len;
|
|
|
|
done:
|
|
|
|
skb_free_datagram(sk, skb);
|
|
|
|
out:
|
|
|
|
return err ? err : copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct proto l2tp_ip6_prot = {
|
|
|
|
.name = "L2TP/IPv6",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.init = l2tp_ip6_open,
|
|
|
|
.close = l2tp_ip6_close,
|
|
|
|
.bind = l2tp_ip6_bind,
|
|
|
|
.connect = l2tp_ip6_connect,
|
2012-05-29 11:30:42 +08:00
|
|
|
.disconnect = l2tp_ip6_disconnect,
|
2017-02-10 08:15:52 +08:00
|
|
|
.ioctl = l2tp_ioctl,
|
2012-04-30 05:48:54 +08:00
|
|
|
.destroy = l2tp_ip6_destroy_sock,
|
|
|
|
.setsockopt = ipv6_setsockopt,
|
|
|
|
.getsockopt = ipv6_getsockopt,
|
|
|
|
.sendmsg = l2tp_ip6_sendmsg,
|
|
|
|
.recvmsg = l2tp_ip6_recvmsg,
|
|
|
|
.backlog_rcv = l2tp_ip6_backlog_recv,
|
2016-02-11 00:50:36 +08:00
|
|
|
.hash = inet6_hash,
|
2012-04-30 05:48:54 +08:00
|
|
|
.unhash = inet_unhash,
|
|
|
|
.obj_size = sizeof(struct l2tp_ip6_sock),
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
.compat_setsockopt = compat_ipv6_setsockopt,
|
|
|
|
.compat_getsockopt = compat_ipv6_getsockopt,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct proto_ops l2tp_ip6_ops = {
|
|
|
|
.family = PF_INET6,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.release = inet6_release,
|
|
|
|
.bind = inet6_bind,
|
|
|
|
.connect = inet_dgram_connect,
|
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
|
.accept = sock_no_accept,
|
|
|
|
.getname = l2tp_ip6_getname,
|
2018-06-29 00:43:44 +08:00
|
|
|
.poll = datagram_poll,
|
2012-04-30 05:48:54 +08:00
|
|
|
.ioctl = inet6_ioctl,
|
2019-04-18 04:51:48 +08:00
|
|
|
.gettstamp = sock_gettstamp,
|
2012-04-30 05:48:54 +08:00
|
|
|
.listen = sock_no_listen,
|
|
|
|
.shutdown = inet_shutdown,
|
|
|
|
.setsockopt = sock_common_setsockopt,
|
|
|
|
.getsockopt = sock_common_getsockopt,
|
|
|
|
.sendmsg = inet_sendmsg,
|
|
|
|
.recvmsg = sock_common_recvmsg,
|
|
|
|
.mmap = sock_no_mmap,
|
|
|
|
.sendpage = sock_no_sendpage,
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
.compat_setsockopt = compat_sock_common_setsockopt,
|
|
|
|
.compat_getsockopt = compat_sock_common_getsockopt,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct inet_protosw l2tp_ip6_protosw = {
|
|
|
|
.type = SOCK_DGRAM,
|
|
|
|
.protocol = IPPROTO_L2TP,
|
|
|
|
.prot = &l2tp_ip6_prot,
|
|
|
|
.ops = &l2tp_ip6_ops,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct inet6_protocol l2tp_ip6_protocol __read_mostly = {
|
|
|
|
.handler = l2tp_ip6_recv,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init l2tp_ip6_init(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2012-05-16 17:55:56 +08:00
|
|
|
pr_info("L2TP IP encapsulation support for IPv6 (L2TPv3)\n");
|
2012-04-30 05:48:54 +08:00
|
|
|
|
|
|
|
err = proto_register(&l2tp_ip6_prot, 1);
|
|
|
|
if (err != 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = inet6_add_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP);
|
|
|
|
if (err)
|
|
|
|
goto out1;
|
|
|
|
|
|
|
|
inet6_register_protosw(&l2tp_ip6_protosw);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out1:
|
|
|
|
proto_unregister(&l2tp_ip6_prot);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit l2tp_ip6_exit(void)
|
|
|
|
{
|
|
|
|
inet6_unregister_protosw(&l2tp_ip6_protosw);
|
|
|
|
inet6_del_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP);
|
|
|
|
proto_unregister(&l2tp_ip6_prot);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(l2tp_ip6_init);
|
|
|
|
module_exit(l2tp_ip6_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Chris Elston <celston@katalix.com>");
|
|
|
|
MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6");
|
|
|
|
MODULE_VERSION("1.0");
|
|
|
|
|
|
|
|
/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
|
|
|
|
* enums
|
|
|
|
*/
|
|
|
|
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 2, IPPROTO_L2TP);
|
2015-09-24 12:33:35 +08:00
|
|
|
MODULE_ALIAS_NET_PF_PROTO(PF_INET6, IPPROTO_L2TP);
|