Commit 528534f0 authored by Guillaume Nault's avatar Guillaume Nault Committed by David S. Miller

l2tp: remove pppol2tp_tunnel_ioctl()

Handle PPPIOCGL2TPSTATS in pppol2tp_ioctl() if the socket represents a
tunnel. This one is a bit special because the caller may use the tunnel
socket to retrieve statistics of one of its sessions. If the session_id
is set, the corresponding session's statistics are returned, instead of
those of the tunnel. This is handled by the new
pppol2tp_tunnel_copy_stats() helper function.

Set ->tunnel_id and ->using_ipsec out of the conditional, so
that it can be used by the 'else' branch in the following patch.
We cannot do that for ->session_id, because tunnel sockets have to
report the value that was originally passed in 'stats.session_id',
while session sockets have to report their own session_id.
Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 79e6760e
...@@ -1038,6 +1038,36 @@ static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest, ...@@ -1038,6 +1038,36 @@ static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
dest->rx_errors = atomic_long_read(&stats->rx_errors); dest->rx_errors = atomic_long_read(&stats->rx_errors);
} }
static int pppol2tp_tunnel_copy_stats(struct pppol2tp_ioc_stats *stats,
struct l2tp_tunnel *tunnel)
{
struct l2tp_session *session;
if (!stats->session_id) {
memset(stats, 0, sizeof(*stats));
pppol2tp_copy_stats(stats, &tunnel->stats);
return 0;
}
/* If session_id is set, search the corresponding session in the
* context of this tunnel and record the session's statistics.
*/
session = l2tp_tunnel_get_session(tunnel, stats->session_id);
if (!session)
return -EBADR;
if (session->pwtype != L2TP_PWTYPE_PPP) {
l2tp_session_dec_refcount(session);
return -EBADR;
}
memset(stats, 0, sizeof(*stats));
pppol2tp_copy_stats(stats, &session->stats);
l2tp_session_dec_refcount(session);
return 0;
}
/* Session ioctl helper. /* Session ioctl helper.
*/ */
static int pppol2tp_session_ioctl(struct l2tp_session *session, static int pppol2tp_session_ioctl(struct l2tp_session *session,
...@@ -1084,84 +1114,10 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session, ...@@ -1084,84 +1114,10 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
return err; return err;
} }
/* Tunnel ioctl helper.
*
* Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data
* specifies a session_id, the session ioctl handler is called. This allows an
* application to retrieve session stats via a tunnel socket.
*/
static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
unsigned int cmd, unsigned long arg)
{
int err = 0;
struct sock *sk;
struct pppol2tp_ioc_stats stats;
l2tp_dbg(tunnel, L2TP_MSG_CONTROL,
"%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n",
tunnel->name, cmd, arg);
sk = tunnel->sock;
sock_hold(sk);
switch (cmd) {
case PPPIOCGL2TPSTATS:
err = -ENXIO;
if (!(sk->sk_state & PPPOX_CONNECTED))
break;
if (copy_from_user(&stats, (void __user *) arg,
sizeof(stats))) {
err = -EFAULT;
break;
}
if (stats.session_id != 0) {
/* resend to session ioctl handler */
struct l2tp_session *session;
session = l2tp_tunnel_get_session(tunnel,
stats.session_id);
if (!session) {
err = -EBADR;
break;
}
if (session->pwtype != L2TP_PWTYPE_PPP) {
l2tp_session_dec_refcount(session);
err = -EBADR;
break;
}
err = pppol2tp_session_ioctl(session, cmd, arg);
l2tp_session_dec_refcount(session);
break;
}
stats.using_ipsec = l2tp_tunnel_uses_xfrm(tunnel);
pppol2tp_copy_stats(&stats, &tunnel->stats);
if (copy_to_user((void __user *) arg, &stats, sizeof(stats))) {
err = -EFAULT;
break;
}
l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: get L2TP stats\n",
tunnel->name);
err = 0;
break;
default:
err = -ENOSYS;
break;
}
sock_put(sk);
return err;
}
/* Main ioctl() handler.
* Dispatch to tunnel or session helpers depending on the socket.
*/
static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
struct pppol2tp_ioc_stats stats;
struct l2tp_session *session; struct l2tp_session *session;
int val; int val;
...@@ -1200,11 +1156,29 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, ...@@ -1200,11 +1156,29 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
return -ENOTCONN; return -ENOTCONN;
/* Session 0 represents the parent tunnel */ /* Session 0 represents the parent tunnel */
if (!session->session_id && !session->peer_session_id) if (!session->session_id && !session->peer_session_id) {
return pppol2tp_tunnel_ioctl(session->tunnel, cmd, u32 session_id;
arg); int err;
else
if (copy_from_user(&stats, (void __user *)arg,
sizeof(stats)))
return -EFAULT;
session_id = stats.session_id;
err = pppol2tp_tunnel_copy_stats(&stats,
session->tunnel);
if (err < 0)
return err;
stats.session_id = session_id;
} else {
return pppol2tp_session_ioctl(session, cmd, arg); return pppol2tp_session_ioctl(session, cmd, arg);
}
stats.tunnel_id = session->tunnel->tunnel_id;
stats.using_ipsec = l2tp_tunnel_uses_xfrm(session->tunnel);
if (copy_to_user((void __user *)arg, &stats, sizeof(stats)))
return -EFAULT;
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment