All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling
@ 2018-08-10 11:21 Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 1/8] l2tp: define l2tp_tunnel_uses_xfrm() Guillaume Nault
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:21 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

The current ioctl() handling code can be simplified. It tests for
non-relevant conditions and uselessly holds sockets. Once useless
code is removed, it becomes even simpler to let pppol2tp_ioctl() handle
commands directly, rather than dispatch them to pppol2tp_tunnel_ioctl()
or pppol2tp_session_ioctl(). That is the approach taken by this series.

Patch #1 and #2 define helper functions aimed at simplifying the rest
of the patch set.

Patch #3 drops useless tests in pppol2p_ioctl() and avoid holding a
refcount on the socket.

Patches #4, #5 and #6 are the core of the series. They let
pppol2tp_ioctl() handle all ioctls and drop the tunnel and session
specific functions.

Then patch #6 brings a little bit of consolidation.

Finally, patch #7 takes advantage of the simplified code to make
pppol2tp sockets compatible with dev_ioctl(). Certainly not a killer
feature, but it is trivial and it is always nice to see l2tp getting
better integration with the rest of the stack.

Guillaume Nault (8):
  l2tp: define l2tp_tunnel_uses_xfrm()
  l2tp: split l2tp_session_get()
  l2tp: simplify pppol2tp_ioctl()
  l2tp: handle PPPIOC[GS]MRU and PPPIOC[GS]FLAGS in pppol2tp_ioctl()
  l2tp: remove pppol2tp_tunnel_ioctl()
  l2tp: remove pppol2tp_session_ioctl()
  l2tp: zero out stats in pppol2tp_copy_stats()
  l2tp: let pppol2tp_ioctl() fallback to dev_ioctl()

 include/uapi/linux/ppp-ioctl.h |   2 +-
 net/l2tp/l2tp_core.c           |  50 +++----
 net/l2tp/l2tp_core.h           |  25 +++-
 net/l2tp/l2tp_ip.c             |   2 +-
 net/l2tp/l2tp_ip6.c            |   2 +-
 net/l2tp/l2tp_netlink.c        |  11 +-
 net/l2tp/l2tp_ppp.c            | 240 +++++++++++----------------------
 7 files changed, 133 insertions(+), 199 deletions(-)

-- 
2.18.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH net-next 1/8] l2tp: define l2tp_tunnel_uses_xfrm()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
@ 2018-08-10 11:21 ` Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 2/8] l2tp: split l2tp_session_get() Guillaume Nault
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:21 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

Use helper function to figure out if a tunnel is using ipsec.
Also, avoid accessing ->sk_policy directly since it's RCU protected.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_core.h    | 19 +++++++++++++++++++
 net/l2tp/l2tp_netlink.c |  7 +------
 net/l2tp/l2tp_ppp.c     |  5 +----
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 5804065dfbfb..04a9488c54b4 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -15,6 +15,10 @@
 #include <net/dst.h>
 #include <net/sock.h>
 
+#ifdef CONFIG_XFRM
+#include <net/xfrm.h>
+#endif
+
 /* Just some random numbers */
 #define L2TP_TUNNEL_MAGIC	0x42114DDA
 #define L2TP_SESSION_MAGIC	0x0C04EB7D
@@ -284,6 +288,21 @@ static inline u32 l2tp_tunnel_dst_mtu(const struct l2tp_tunnel *tunnel)
 	return mtu;
 }
 
+#ifdef CONFIG_XFRM
+static inline bool l2tp_tunnel_uses_xfrm(const struct l2tp_tunnel *tunnel)
+{
+	struct sock *sk = tunnel->sock;
+
+	return sk && (rcu_access_pointer(sk->sk_policy[0]) ||
+		      rcu_access_pointer(sk->sk_policy[1]));
+}
+#else
+static inline bool l2tp_tunnel_uses_xfrm(const struct l2tp_tunnel *tunnel)
+{
+	return false;
+}
+#endif
+
 #define l2tp_printk(ptr, type, func, fmt, ...)				\
 do {									\
 	if (((ptr)->debug) & (type))					\
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 2e1e92651545..357503e5acd5 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -710,9 +710,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
 	void *hdr;
 	struct nlattr *nest;
 	struct l2tp_tunnel *tunnel = session->tunnel;
-	struct sock *sk = NULL;
-
-	sk = tunnel->sock;
 
 	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
 	if (!hdr)
@@ -738,10 +735,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
 	    nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) ||
 	    nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) ||
 	    nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) ||
-#ifdef CONFIG_XFRM
-	    (((sk) && (sk->sk_policy[0] || sk->sk_policy[1])) &&
+	    (l2tp_tunnel_uses_xfrm(tunnel) &&
 	     nla_put_u8(skb, L2TP_ATTR_USING_IPSEC, 1)) ||
-#endif
 	    (session->reorder_timeout &&
 	     nla_put_msecs(skb, L2TP_ATTR_RECV_TIMEOUT,
 			   session->reorder_timeout, L2TP_ATTR_PAD)))
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 6e2c8e7595e0..c33ef9a3f3b5 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -95,7 +95,6 @@
 #include <net/netns/generic.h>
 #include <net/ip.h>
 #include <net/udp.h>
-#include <net/xfrm.h>
 #include <net/inet_common.h>
 
 #include <asm/byteorder.h>
@@ -1153,9 +1152,7 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
 			l2tp_session_dec_refcount(session);
 			break;
 		}
-#ifdef CONFIG_XFRM
-		stats.using_ipsec = (sk->sk_policy[0] || sk->sk_policy[1]) ? 1 : 0;
-#endif
+		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;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 2/8] l2tp: split l2tp_session_get()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 1/8] l2tp: define l2tp_tunnel_uses_xfrm() Guillaume Nault
@ 2018-08-10 11:21 ` Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 3/8] l2tp: simplify pppol2tp_ioctl() Guillaume Nault
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:21 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

l2tp_session_get() is used for two different purposes. If 'tunnel' is
NULL, the session is searched globally in the supplied network
namespace. Otherwise it is searched exclusively in the tunnel context.

Callers always know the context in which they need to search the
session. But some of them do provide both a namespace and a tunnel,
making the semantic of the call unclear.

This patch defines l2tp_tunnel_get_session() for lookups done in a
tunnel and restricts l2tp_session_get() to namespace searches.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_core.c    | 50 ++++++++++++++++++++---------------------
 net/l2tp/l2tp_core.h    |  6 ++---
 net/l2tp/l2tp_ip.c      |  2 +-
 net/l2tp/l2tp_ip6.c     |  2 +-
 net/l2tp/l2tp_netlink.c |  4 ++--
 net/l2tp/l2tp_ppp.c     |  8 +++----
 6 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index ac6a00bcec71..2bd701a58aa6 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -203,44 +203,44 @@ struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth);
 
-/* Lookup a session. A new reference is held on the returned session. */
-struct l2tp_session *l2tp_session_get(const struct net *net,
-				      struct l2tp_tunnel *tunnel,
-				      u32 session_id)
+struct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel,
+					     u32 session_id)
 {
 	struct hlist_head *session_list;
 	struct l2tp_session *session;
 
-	if (!tunnel) {
-		struct l2tp_net *pn = l2tp_pernet(net);
-
-		session_list = l2tp_session_id_hash_2(pn, session_id);
+	session_list = l2tp_session_id_hash(tunnel, session_id);
 
-		rcu_read_lock_bh();
-		hlist_for_each_entry_rcu(session, session_list, global_hlist) {
-			if (session->session_id == session_id) {
-				l2tp_session_inc_refcount(session);
-				rcu_read_unlock_bh();
+	read_lock_bh(&tunnel->hlist_lock);
+	hlist_for_each_entry(session, session_list, hlist)
+		if (session->session_id == session_id) {
+			l2tp_session_inc_refcount(session);
+			read_unlock_bh(&tunnel->hlist_lock);
 
-				return session;
-			}
+			return session;
 		}
-		rcu_read_unlock_bh();
+	read_unlock_bh(&tunnel->hlist_lock);
 
-		return NULL;
-	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_get_session);
 
-	session_list = l2tp_session_id_hash(tunnel, session_id);
-	read_lock_bh(&tunnel->hlist_lock);
-	hlist_for_each_entry(session, session_list, hlist) {
+struct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id)
+{
+	struct hlist_head *session_list;
+	struct l2tp_session *session;
+
+	session_list = l2tp_session_id_hash_2(l2tp_pernet(net), session_id);
+
+	rcu_read_lock_bh();
+	hlist_for_each_entry_rcu(session, session_list, global_hlist)
 		if (session->session_id == session_id) {
 			l2tp_session_inc_refcount(session);
-			read_unlock_bh(&tunnel->hlist_lock);
+			rcu_read_unlock_bh();
 
 			return session;
 		}
-	}
-	read_unlock_bh(&tunnel->hlist_lock);
+	rcu_read_unlock_bh();
 
 	return NULL;
 }
@@ -872,7 +872,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
 	}
 
 	/* Find the session context */
-	session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id);
+	session = l2tp_tunnel_get_session(tunnel, session_id);
 	if (!session || !session->recv_skb) {
 		if (session)
 			l2tp_session_dec_refcount(session);
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 04a9488c54b4..8480a0af973e 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -196,12 +196,12 @@ static inline void *l2tp_session_priv(struct l2tp_session *session)
 
 struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
 struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth);
+struct l2tp_session *l2tp_tunnel_get_session(struct l2tp_tunnel *tunnel,
+					     u32 session_id);
 
 void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
-struct l2tp_session *l2tp_session_get(const struct net *net,
-				      struct l2tp_tunnel *tunnel,
-				      u32 session_id);
+struct l2tp_session *l2tp_session_get(const struct net *net, u32 session_id);
 struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
 struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
 						const char *ifname);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 0bc39cc20a3f..35f6f86d4dcc 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -144,7 +144,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)
 	}
 
 	/* Ok, this is a data packet. Lookup the session. */
-	session = l2tp_session_get(net, NULL, session_id);
+	session = l2tp_session_get(net, session_id);
 	if (!session)
 		goto discard;
 
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 42f828cf62fb..237f1a4a0b0c 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -157,7 +157,7 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
 	}
 
 	/* Ok, this is a data packet. Lookup the session. */
-	session = l2tp_session_get(net, NULL, session_id);
+	session = l2tp_session_get(net, session_id);
 	if (!session)
 		goto discard;
 
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 357503e5acd5..edbd5d1fbcde 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -66,7 +66,7 @@ static struct l2tp_session *l2tp_nl_session_get(struct genl_info *info)
 		session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
 		tunnel = l2tp_tunnel_get(net, tunnel_id);
 		if (tunnel) {
-			session = l2tp_session_get(net, tunnel, session_id);
+			session = l2tp_tunnel_get_session(tunnel, session_id);
 			l2tp_tunnel_dec_refcount(tunnel);
 		}
 	}
@@ -627,7 +627,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
 							   &cfg);
 
 	if (ret >= 0) {
-		session = l2tp_session_get(net, tunnel, session_id);
+		session = l2tp_tunnel_get_session(tunnel, session_id);
 		if (session) {
 			ret = l2tp_session_notify(&l2tp_nl_family, info, session,
 						  L2TP_CMD_SESSION_CREATE);
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index c33ef9a3f3b5..cd43d02484e4 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -757,7 +757,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 	if (tunnel->peer_tunnel_id == 0)
 		tunnel->peer_tunnel_id = info.peer_tunnel_id;
 
-	session = l2tp_session_get(sock_net(sk), tunnel, info.session_id);
+	session = l2tp_tunnel_get_session(tunnel, info.session_id);
 	if (session) {
 		drop_refcnt = true;
 
@@ -1134,10 +1134,10 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
 		}
 		if (stats.session_id != 0) {
 			/* resend to session ioctl handler */
-			struct l2tp_session *session =
-				l2tp_session_get(sock_net(sk), tunnel,
-						 stats.session_id);
+			struct l2tp_session *session;
 
+			session = l2tp_tunnel_get_session(tunnel,
+							  stats.session_id);
 			if (!session) {
 				err = -EBADR;
 				break;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 4/8] l2tp: handle PPPIOC[GS]MRU and PPPIOC[GS]FLAGS in pppol2tp_ioctl()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (2 preceding siblings ...)
  2018-08-10 11:21 ` [PATCH net-next 3/8] l2tp: simplify pppol2tp_ioctl() Guillaume Nault
@ 2018-08-10 11:21 ` Guillaume Nault
  2018-08-10 11:22 ` [PATCH net-next 5/8] l2tp: remove pppol2tp_tunnel_ioctl() Guillaume Nault
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:21 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

Let pppol2tp_ioctl() handle ioctl commands directly. It still relies on
pppol2tp_{session,tunnel}_ioctl() for PPPIOCGL2TPSTATS.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
Checkpatch does not like the -ENOSYS return value, which should only be
used for non-existing syscalls. I have kept them so that userspace gets
the same errors before and after this patch.

However I am feeling that I may be too conservative and that, maybe
the *MRU and *FLAGS commands should be dropped entirely, like *IFMTU
was. That would drop two of the three -ENOSYS errors (the last one is
dropped by the last patch anyway).

David, James, do you have any preference? After all, the MRU/FLAGS
ioctls never had any effect on pppol2tp sockets. So I do not expect
code to use them or expect them to succeed. I you are ok, I will send
a followup patch for dropping those commands.

 net/l2tp/l2tp_ppp.c | 73 +++++++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 29 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index e3ed8d473d91..f4ec6b2a093e 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1045,7 +1045,6 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
 {
 	int err = 0;
 	struct sock *sk;
-	int val = (int) arg;
 	struct l2tp_tunnel *tunnel = session->tunnel;
 	struct pppol2tp_ioc_stats stats;
 
@@ -1058,22 +1057,6 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
 		return -EBADR;
 
 	switch (cmd) {
-	case PPPIOCGMRU:
-	case PPPIOCGFLAGS:
-		err = -EFAULT;
-		if (put_user(0, (int __user *)arg))
-			break;
-		err = 0;
-		break;
-
-	case PPPIOCSMRU:
-	case PPPIOCSFLAGS:
-		err = -EFAULT;
-		if (get_user(val, (int __user *)arg))
-			break;
-		err = 0;
-		break;
-
 	case PPPIOCGL2TPSTATS:
 		err = -ENXIO;
 		if (!(sk->sk_state & PPPOX_CONNECTED))
@@ -1180,23 +1163,55 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 			  unsigned long arg)
 {
 	struct l2tp_session *session;
-	struct l2tp_tunnel *tunnel;
+	int val;
+
+	switch (cmd) {
+	case PPPIOCGMRU:
+	case PPPIOCGFLAGS:
+		session = sock->sk->sk_user_data;
+		if (!session)
+			return -ENOTCONN;
 
-	session = sock->sk->sk_user_data;
-	if (!session)
-		return -ENOTCONN;
+		/* Not defined for tunnels */
+		if (!session->session_id && !session->peer_session_id)
+			return -ENOSYS;
 
-	/* Special case: if session's session_id is zero, treat ioctl as a
-	 * tunnel ioctl
-	 */
-	if ((session->session_id == 0) &&
-	    (session->peer_session_id == 0)) {
-		tunnel = session->tunnel;
+		if (put_user(0, (int __user *)arg))
+			return -EFAULT;
+		break;
+
+	case PPPIOCSMRU:
+	case PPPIOCSFLAGS:
+		session = sock->sk->sk_user_data;
+		if (!session)
+			return -ENOTCONN;
 
-		return pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
+		/* Not defined for tunnels */
+		if (!session->session_id && !session->peer_session_id)
+			return -ENOSYS;
+
+		if (get_user(val, (int __user *)arg))
+			return -EFAULT;
+		break;
+
+	case PPPIOCGL2TPSTATS:
+		session = sock->sk->sk_user_data;
+		if (!session)
+			return -ENOTCONN;
+
+		/* Session 0 represents the parent tunnel */
+		if (!session->session_id && !session->peer_session_id)
+			return pppol2tp_tunnel_ioctl(session->tunnel, cmd,
+						     arg);
+		else
+			return pppol2tp_session_ioctl(session, cmd, arg);
+		break;
+
+	default:
+		return -ENOSYS;
 	}
 
-	return pppol2tp_session_ioctl(session, cmd, arg);
+	return 0;
 }
 
 /*****************************************************************************
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 3/8] l2tp: simplify pppol2tp_ioctl()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 1/8] l2tp: define l2tp_tunnel_uses_xfrm() Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 2/8] l2tp: split l2tp_session_get() Guillaume Nault
@ 2018-08-10 11:21 ` Guillaume Nault
  2018-08-10 11:21 ` [PATCH net-next 4/8] l2tp: handle PPPIOC[GS]MRU and PPPIOC[GS]FLAGS in pppol2tp_ioctl() Guillaume Nault
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:21 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

  * Drop test on 'sk': sock->sk cannot be NULL, or pppox_ioctl() could
    not have called us.

  * Drop test on 'SOCK_DEAD' state: if this flag was set, the socket
    would be in the process of being released and no ioctl could be
    running anymore.

  * Drop test on 'PPPOX_*' state: we depend on ->sk_user_data to get
    the session structure. If it is non-NULL, then the socket is
    connected. Testing for PPPOX_* is redundant.

  * Retrieve session using ->sk_user_data directly, instead of going
    through pppol2tp_sock_to_session(). This avoids grabbing a useless
    reference on the socket.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_ppp.c | 33 ++++++---------------------------
 1 file changed, 6 insertions(+), 27 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index cd43d02484e4..e3ed8d473d91 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1179,28 +1179,12 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
 static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 			  unsigned long arg)
 {
-	struct sock *sk = sock->sk;
 	struct l2tp_session *session;
 	struct l2tp_tunnel *tunnel;
-	int err;
-
-	if (!sk)
-		return 0;
-
-	err = -EBADF;
-	if (sock_flag(sk, SOCK_DEAD) != 0)
-		goto end;
-
-	err = -ENOTCONN;
-	if ((sk->sk_user_data == NULL) ||
-	    (!(sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND))))
-		goto end;
 
-	/* Get session context from the socket */
-	err = -EBADF;
-	session = pppol2tp_sock_to_session(sk);
-	if (session == NULL)
-		goto end;
+	session = sock->sk->sk_user_data;
+	if (!session)
+		return -ENOTCONN;
 
 	/* Special case: if session's session_id is zero, treat ioctl as a
 	 * tunnel ioctl
@@ -1208,16 +1192,11 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 	if ((session->session_id == 0) &&
 	    (session->peer_session_id == 0)) {
 		tunnel = session->tunnel;
-		err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
-		goto end_put_sess;
-	}
 
-	err = pppol2tp_session_ioctl(session, cmd, arg);
+		return pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
+	}
 
-end_put_sess:
-	sock_put(sk);
-end:
-	return err;
+	return pppol2tp_session_ioctl(session, cmd, arg);
 }
 
 /*****************************************************************************
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 5/8] l2tp: remove pppol2tp_tunnel_ioctl()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (3 preceding siblings ...)
  2018-08-10 11:21 ` [PATCH net-next 4/8] l2tp: handle PPPIOC[GS]MRU and PPPIOC[GS]FLAGS in pppol2tp_ioctl() Guillaume Nault
@ 2018-08-10 11:22 ` Guillaume Nault
  2018-08-10 11:22 ` [PATCH net-next 6/8] l2tp: remove pppol2tp_session_ioctl() Guillaume Nault
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:22 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

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: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_ppp.c | 132 ++++++++++++++++++--------------------------
 1 file changed, 53 insertions(+), 79 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index f4ec6b2a093e..2afd3ab8a551 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1038,6 +1038,36 @@ static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
 	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.
  */
 static int pppol2tp_session_ioctl(struct l2tp_session *session,
@@ -1084,84 +1114,10 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
 	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,
 			  unsigned long arg)
 {
+	struct pppol2tp_ioc_stats stats;
 	struct l2tp_session *session;
 	int val;
 
@@ -1200,11 +1156,29 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 			return -ENOTCONN;
 
 		/* Session 0 represents the parent tunnel */
-		if (!session->session_id && !session->peer_session_id)
-			return pppol2tp_tunnel_ioctl(session->tunnel, cmd,
-						     arg);
-		else
+		if (!session->session_id && !session->peer_session_id) {
+			u32 session_id;
+			int err;
+
+			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);
+		}
+		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;
 
 	default:
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 6/8] l2tp: remove pppol2tp_session_ioctl()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (4 preceding siblings ...)
  2018-08-10 11:22 ` [PATCH net-next 5/8] l2tp: remove pppol2tp_tunnel_ioctl() Guillaume Nault
@ 2018-08-10 11:22 ` Guillaume Nault
  2018-08-10 11:22 ` [PATCH net-next 7/8] l2tp: zero out stats in pppol2tp_copy_stats() Guillaume Nault
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:22 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

pppol2tp_ioctl() has everything in place for handling PPPIOCGL2TPSTATS
on session sockets. We just need to copy the stats and set ->session_id.

As a side effect of sharing session and tunnel code, ->using_ipsec is
properly set even when the request was made using a session socket.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 include/uapi/linux/ppp-ioctl.h |  2 +-
 net/l2tp/l2tp_ppp.c            | 50 ++--------------------------------
 2 files changed, 4 insertions(+), 48 deletions(-)

diff --git a/include/uapi/linux/ppp-ioctl.h b/include/uapi/linux/ppp-ioctl.h
index 784c2e3e572e..88b5f9990320 100644
--- a/include/uapi/linux/ppp-ioctl.h
+++ b/include/uapi/linux/ppp-ioctl.h
@@ -68,7 +68,7 @@ struct ppp_option_data {
 struct pppol2tp_ioc_stats {
 	__u16		tunnel_id;	/* redundant */
 	__u16		session_id;	/* if zero, get tunnel stats */
-	__u32		using_ipsec:1;	/* valid only for session_id == 0 */
+	__u32		using_ipsec:1;
 	__aligned_u64	tx_packets;
 	__aligned_u64	tx_bytes;
 	__aligned_u64	tx_errors;
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 2afd3ab8a551..bdfbd3ed7e14 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1068,52 +1068,6 @@ static int pppol2tp_tunnel_copy_stats(struct pppol2tp_ioc_stats *stats,
 	return 0;
 }
 
-/* Session ioctl helper.
- */
-static int pppol2tp_session_ioctl(struct l2tp_session *session,
-				  unsigned int cmd, unsigned long arg)
-{
-	int err = 0;
-	struct sock *sk;
-	struct l2tp_tunnel *tunnel = session->tunnel;
-	struct pppol2tp_ioc_stats stats;
-
-	l2tp_dbg(session, L2TP_MSG_CONTROL,
-		 "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
-		 session->name, cmd, arg);
-
-	sk = pppol2tp_session_get_sock(session);
-	if (!sk)
-		return -EBADR;
-
-	switch (cmd) {
-	case PPPIOCGL2TPSTATS:
-		err = -ENXIO;
-		if (!(sk->sk_state & PPPOX_CONNECTED))
-			break;
-
-		memset(&stats, 0, sizeof(stats));
-		stats.tunnel_id = tunnel->tunnel_id;
-		stats.session_id = session->session_id;
-		pppol2tp_copy_stats(&stats, &session->stats);
-		if (copy_to_user((void __user *) arg, &stats,
-				 sizeof(stats)))
-			break;
-		l2tp_info(session, L2TP_MSG_CONTROL, "%s: get L2TP stats\n",
-			  session->name);
-		err = 0;
-		break;
-
-	default:
-		err = -ENOSYS;
-		break;
-	}
-
-	sock_put(sk);
-
-	return err;
-}
-
 static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 			  unsigned long arg)
 {
@@ -1172,7 +1126,9 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 
 			stats.session_id = session_id;
 		} else {
-			return pppol2tp_session_ioctl(session, cmd, arg);
+			memset(&stats, 0, sizeof(stats));
+			pppol2tp_copy_stats(&stats, &session->stats);
+			stats.session_id = session->session_id;
 		}
 		stats.tunnel_id = session->tunnel->tunnel_id;
 		stats.using_ipsec = l2tp_tunnel_uses_xfrm(session->tunnel);
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 7/8] l2tp: zero out stats in pppol2tp_copy_stats()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (5 preceding siblings ...)
  2018-08-10 11:22 ` [PATCH net-next 6/8] l2tp: remove pppol2tp_session_ioctl() Guillaume Nault
@ 2018-08-10 11:22 ` Guillaume Nault
  2018-08-10 11:22 ` [PATCH net-next 8/8] l2tp: let pppol2tp_ioctl() fallback to dev_ioctl() Guillaume Nault
  2018-08-11 19:19 ` [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling David Miller
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:22 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

Integrate memset(0) in pppol2tp_copy_stats() to avoid calling it
manually every time.

While there, constify 'stats'.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_ppp.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index bdfbd3ed7e14..e2eea60bf875 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1026,8 +1026,10 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
  ****************************************************************************/
 
 static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
-				struct l2tp_stats *stats)
+				const struct l2tp_stats *stats)
 {
+	memset(dest, 0, sizeof(*dest));
+
 	dest->tx_packets = atomic_long_read(&stats->tx_packets);
 	dest->tx_bytes = atomic_long_read(&stats->tx_bytes);
 	dest->tx_errors = atomic_long_read(&stats->tx_errors);
@@ -1044,7 +1046,6 @@ static int pppol2tp_tunnel_copy_stats(struct pppol2tp_ioc_stats *stats,
 	struct l2tp_session *session;
 
 	if (!stats->session_id) {
-		memset(stats, 0, sizeof(*stats));
 		pppol2tp_copy_stats(stats, &tunnel->stats);
 		return 0;
 	}
@@ -1061,7 +1062,6 @@ static int pppol2tp_tunnel_copy_stats(struct pppol2tp_ioc_stats *stats,
 		return -EBADR;
 	}
 
-	memset(stats, 0, sizeof(*stats));
 	pppol2tp_copy_stats(stats, &session->stats);
 	l2tp_session_dec_refcount(session);
 
@@ -1126,7 +1126,6 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 
 			stats.session_id = session_id;
 		} else {
-			memset(&stats, 0, sizeof(stats));
 			pppol2tp_copy_stats(&stats, &session->stats);
 			stats.session_id = session->session_id;
 		}
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next 8/8] l2tp: let pppol2tp_ioctl() fallback to dev_ioctl()
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (6 preceding siblings ...)
  2018-08-10 11:22 ` [PATCH net-next 7/8] l2tp: zero out stats in pppol2tp_copy_stats() Guillaume Nault
@ 2018-08-10 11:22 ` Guillaume Nault
  2018-08-11 19:19 ` [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling David Miller
  8 siblings, 0 replies; 10+ messages in thread
From: Guillaume Nault @ 2018-08-10 11:22 UTC (permalink / raw
  To: netdev; +Cc: James Chapman

Return -ENOIOCTLCMD for unknown ioctl commands. This lets dev_ioctl()
handle generic socket ioctls like SIOCGIFNAME or SIOCGIFINDEX.
PF_PPPOX/PX_PROTO_OL2TP was one of the few socket types not honouring
this mechanism.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 net/l2tp/l2tp_ppp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index e2eea60bf875..62f2d3f1e431 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1137,7 +1137,7 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
 		break;
 
 	default:
-		return -ENOSYS;
+		return -ENOIOCTLCMD;
 	}
 
 	return 0;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling
  2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
                   ` (7 preceding siblings ...)
  2018-08-10 11:22 ` [PATCH net-next 8/8] l2tp: let pppol2tp_ioctl() fallback to dev_ioctl() Guillaume Nault
@ 2018-08-11 19:19 ` David Miller
  8 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2018-08-11 19:19 UTC (permalink / raw
  To: g.nault; +Cc: netdev, jchapman

From: Guillaume Nault <g.nault@alphalink.fr>
Date: Fri, 10 Aug 2018 13:21:54 +0200

> The current ioctl() handling code can be simplified. It tests for
> non-relevant conditions and uselessly holds sockets. Once useless
> code is removed, it becomes even simpler to let pppol2tp_ioctl() handle
> commands directly, rather than dispatch them to pppol2tp_tunnel_ioctl()
> or pppol2tp_session_ioctl(). That is the approach taken by this series.
> 
> Patch #1 and #2 define helper functions aimed at simplifying the rest
> of the patch set.
> 
> Patch #3 drops useless tests in pppol2p_ioctl() and avoid holding a
> refcount on the socket.
> 
> Patches #4, #5 and #6 are the core of the series. They let
> pppol2tp_ioctl() handle all ioctls and drop the tunnel and session
> specific functions.
> 
> Then patch #6 brings a little bit of consolidation.
> 
> Finally, patch #7 takes advantage of the simplified code to make
> pppol2tp sockets compatible with dev_ioctl(). Certainly not a killer
> feature, but it is trivial and it is always nice to see l2tp getting
> better integration with the rest of the stack.

Very nice cleanups.

Let's leave the -ENOSYS stuff there for now, changing error return
codes seems to always break something :-/

Series applied, thanks!

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-08-11 22:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-10 11:21 [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling Guillaume Nault
2018-08-10 11:21 ` [PATCH net-next 1/8] l2tp: define l2tp_tunnel_uses_xfrm() Guillaume Nault
2018-08-10 11:21 ` [PATCH net-next 2/8] l2tp: split l2tp_session_get() Guillaume Nault
2018-08-10 11:21 ` [PATCH net-next 3/8] l2tp: simplify pppol2tp_ioctl() Guillaume Nault
2018-08-10 11:21 ` [PATCH net-next 4/8] l2tp: handle PPPIOC[GS]MRU and PPPIOC[GS]FLAGS in pppol2tp_ioctl() Guillaume Nault
2018-08-10 11:22 ` [PATCH net-next 5/8] l2tp: remove pppol2tp_tunnel_ioctl() Guillaume Nault
2018-08-10 11:22 ` [PATCH net-next 6/8] l2tp: remove pppol2tp_session_ioctl() Guillaume Nault
2018-08-10 11:22 ` [PATCH net-next 7/8] l2tp: zero out stats in pppol2tp_copy_stats() Guillaume Nault
2018-08-10 11:22 ` [PATCH net-next 8/8] l2tp: let pppol2tp_ioctl() fallback to dev_ioctl() Guillaume Nault
2018-08-11 19:19 ` [PATCH net-next 0/8] l2tp: rework pppol2tp ioctl handling David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.