l2tp: pppol2tp_connect() handles ipv6 sockaddr variants
authorJames Chapman <jchapman@katalix.com>
Sun, 29 Apr 2012 21:48:50 +0000 (21:48 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 May 2012 13:30:55 +0000 (09:30 -0400)
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: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/l2tp/l2tp_ppp.c

index 27b9dec9d2541494ba577994e0ef88999ea0c12a..9f2c421aa307e6b4128b4583b5e725712d8a4e84 100644 (file)
@@ -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