Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b79585f5 authored by James Chapman's avatar James Chapman Committed by David S. Miller
Browse files

l2tp: pppol2tp_connect() handles ipv6 sockaddr variants



Userspace uses connect() to associate a pppol2tp socket with a tunnel
socket. This needs to allow the caller to supply the new IPv6
sockaddr_pppol2tp structures if IPv6 is used.

Signed-off-by: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9d4ec1ae
Loading
Loading
Loading
Loading
+28 −8
Original line number Diff line number Diff line
@@ -628,7 +628,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
{
	struct sock *sk = sock->sk;
	struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
	struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr;
	struct pppox_sock *po = pppox_sk(sk);
	struct l2tp_session *session = NULL;
	struct l2tp_tunnel *tunnel;
@@ -657,7 +656,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
	if (sk->sk_user_data)
		goto end; /* socket is already attached */

	/* Get params from socket address. Handle L2TPv2 and L2TPv3 */
	/* Get params from socket address. Handle L2TPv2 and L2TPv3.
	 * This is nasty because there are different sockaddr_pppol2tp
	 * structs for L2TPv2, L2TPv3, over IPv4 and IPv6. We use
	 * the sockaddr size to determine which structure the caller
	 * is using.
	 */
	peer_tunnel_id = 0;
	if (sockaddr_len == sizeof(struct sockaddr_pppol2tp)) {
		fd = sp->pppol2tp.fd;
		tunnel_id = sp->pppol2tp.s_tunnel;
@@ -665,12 +670,31 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
		session_id = sp->pppol2tp.s_session;
		peer_session_id = sp->pppol2tp.d_session;
	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3)) {
		struct sockaddr_pppol2tpv3 *sp3 =
			(struct sockaddr_pppol2tpv3 *) sp;
		ver = 3;
		fd = sp3->pppol2tp.fd;
		tunnel_id = sp3->pppol2tp.s_tunnel;
		peer_tunnel_id = sp3->pppol2tp.d_tunnel;
		session_id = sp3->pppol2tp.s_session;
		peer_session_id = sp3->pppol2tp.d_session;
	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpin6)) {
		struct sockaddr_pppol2tpin6 *sp6 =
			(struct sockaddr_pppol2tpin6 *) sp;
		fd = sp6->pppol2tp.fd;
		tunnel_id = sp6->pppol2tp.s_tunnel;
		peer_tunnel_id = sp6->pppol2tp.d_tunnel;
		session_id = sp6->pppol2tp.s_session;
		peer_session_id = sp6->pppol2tp.d_session;
	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3in6)) {
		struct sockaddr_pppol2tpv3in6 *sp6 =
			(struct sockaddr_pppol2tpv3in6 *) sp;
		ver = 3;
		fd = sp6->pppol2tp.fd;
		tunnel_id = sp6->pppol2tp.s_tunnel;
		peer_tunnel_id = sp6->pppol2tp.d_tunnel;
		session_id = sp6->pppol2tp.s_session;
		peer_session_id = sp6->pppol2tp.d_session;
	} else {
		error = -EINVAL;
		goto end; /* bad socket address */
@@ -711,12 +735,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
	if (tunnel->recv_payload_hook == NULL)
		tunnel->recv_payload_hook = pppol2tp_recv_payload_hook;

	if (tunnel->peer_tunnel_id == 0) {
		if (ver == 2)
			tunnel->peer_tunnel_id = sp->pppol2tp.d_tunnel;
		else
			tunnel->peer_tunnel_id = sp3->pppol2tp.d_tunnel;
	}
	if (tunnel->peer_tunnel_id == 0)
		tunnel->peer_tunnel_id = peer_tunnel_id;

	/* Create session if it doesn't already exist. We handle the
	 * case where a session was previously created by the netlink