summaryrefslogtreecommitdiff
path: root/net/l2tp
diff options
context:
space:
mode:
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_ppp.c125
1 files changed, 67 insertions, 58 deletions
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index db2e584c625e..f011af6601c9 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -650,54 +650,22 @@ static int pppol2tp_tunnel_mtu(const struct l2tp_tunnel *tunnel)
return mtu - PPPOL2TP_HEADER_OVERHEAD;
}
-/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
- */
-static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
+static struct l2tp_tunnel *pppol2tp_tunnel_get(struct net *net,
+ const struct l2tp_connect_info *info,
+ bool *new_tunnel)
{
- struct sock *sk = sock->sk;
- struct pppox_sock *po = pppox_sk(sk);
- struct l2tp_session *session = NULL;
- struct l2tp_connect_info info;
struct l2tp_tunnel *tunnel;
- struct pppol2tp_session *ps;
- struct l2tp_session_cfg cfg = { 0, };
- bool drop_refcnt = false;
- bool drop_tunnel = false;
- bool new_session = false;
- bool new_tunnel = false;
int error;
- error = pppol2tp_sockaddr_get_info(uservaddr, sockaddr_len, &info);
- if (error < 0)
- return error;
+ *new_tunnel = false;
- lock_sock(sk);
-
- /* Check for already bound sockets */
- error = -EBUSY;
- if (sk->sk_state & PPPOX_CONNECTED)
- goto end;
-
- /* We don't supporting rebinding anyway */
- error = -EALREADY;
- if (sk->sk_user_data)
- goto end; /* socket is already attached */
-
- /* Don't bind if tunnel_id is 0 */
- error = -EINVAL;
- if (!info.tunnel_id)
- goto end;
-
- tunnel = l2tp_tunnel_get(sock_net(sk), info.tunnel_id);
- if (tunnel)
- drop_tunnel = true;
+ tunnel = l2tp_tunnel_get(net, info->tunnel_id);
/* Special case: create tunnel context if session_id and
* peer_session_id is 0. Otherwise look up tunnel using supplied
* tunnel id.
*/
- if (!info.session_id && !info.peer_session_id) {
+ if (!info->session_id && !info->peer_session_id) {
if (!tunnel) {
struct l2tp_tunnel_cfg tcfg = {
.encap = L2TP_ENCAPTYPE_UDP,
@@ -706,40 +674,82 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Prevent l2tp_tunnel_register() from trying to set up
* a kernel socket.
*/
- if (info.fd < 0) {
- error = -EBADF;
- goto end;
- }
+ if (info->fd < 0)
+ return ERR_PTR(-EBADF);
- error = l2tp_tunnel_create(info.fd,
- info.version,
- info.tunnel_id,
- info.peer_tunnel_id, &tcfg,
+ error = l2tp_tunnel_create(info->fd,
+ info->version,
+ info->tunnel_id,
+ info->peer_tunnel_id, &tcfg,
&tunnel);
if (error < 0)
- goto end;
+ return ERR_PTR(error);
l2tp_tunnel_inc_refcount(tunnel);
- error = l2tp_tunnel_register(tunnel, sock_net(sk),
- &tcfg);
+ error = l2tp_tunnel_register(tunnel, net, &tcfg);
if (error < 0) {
kfree(tunnel);
- goto end;
+ return ERR_PTR(error);
}
- drop_tunnel = true;
- new_tunnel = true;
+
+ *new_tunnel = true;
}
} else {
/* Error if we can't find the tunnel */
- error = -ENOENT;
if (!tunnel)
- goto end;
+ return ERR_PTR(-ENOENT);
/* Error if socket is not prepped */
- if (!tunnel->sock)
- goto end;
+ if (!tunnel->sock) {
+ l2tp_tunnel_dec_refcount(tunnel);
+ return ERR_PTR(-ENOENT);
+ }
}
+ return tunnel;
+}
+
+/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
+ */
+static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct l2tp_session *session = NULL;
+ struct l2tp_connect_info info;
+ struct l2tp_tunnel *tunnel;
+ struct pppol2tp_session *ps;
+ struct l2tp_session_cfg cfg = { 0, };
+ bool drop_refcnt = false;
+ bool new_session = false;
+ bool new_tunnel = false;
+ int error;
+
+ error = pppol2tp_sockaddr_get_info(uservaddr, sockaddr_len, &info);
+ if (error < 0)
+ return error;
+
+ /* Don't bind if tunnel_id is 0 */
+ if (!info.tunnel_id)
+ return -EINVAL;
+
+ tunnel = pppol2tp_tunnel_get(sock_net(sk), &info, &new_tunnel);
+ if (IS_ERR(tunnel))
+ return PTR_ERR(tunnel);
+
+ lock_sock(sk);
+
+ /* Check for already bound sockets */
+ error = -EBUSY;
+ if (sk->sk_state & PPPOX_CONNECTED)
+ goto end;
+
+ /* We don't supporting rebinding anyway */
+ error = -EALREADY;
+ if (sk->sk_user_data)
+ goto end; /* socket is already attached */
+
if (tunnel->peer_tunnel_id == 0)
tunnel->peer_tunnel_id = info.peer_tunnel_id;
@@ -840,8 +850,7 @@ end:
}
if (drop_refcnt)
l2tp_session_dec_refcount(session);
- if (drop_tunnel)
- l2tp_tunnel_dec_refcount(tunnel);
+ l2tp_tunnel_dec_refcount(tunnel);
release_sock(sk);
return error;