2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2020-07-22 19:32:06 +03:00
/* L2TP subsystem debugfs
2010-04-02 10:19:33 +04:00
*
* Copyright ( c ) 2010 Katalix Systems Ltd
*/
2012-05-16 13:55:56 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2010-04-02 10:19:33 +04:00
# include <linux/module.h>
# include <linux/skbuff.h>
# include <linux/socket.h>
# include <linux/hash.h>
# include <linux/l2tp.h>
# include <linux/in.h>
# include <linux/etherdevice.h>
# include <linux/spinlock.h>
# include <linux/debugfs.h>
# include <net/sock.h>
# include <net/ip.h>
# include <net/icmp.h>
# include <net/udp.h>
# include <net/inet_common.h>
# include <net/inet_hashtables.h>
# include <net/tcp_states.h>
# include <net/protocol.h>
# include <net/xfrm.h>
# include <net/net_namespace.h>
# include <net/netns/generic.h>
# include "l2tp_core.h"
static struct dentry * rootdir ;
struct l2tp_dfs_seq_data {
2021-12-10 10:44:25 +03:00
struct net * net ;
netns_tracker ns_tracker ;
2010-04-02 10:19:33 +04:00
int tunnel_idx ; /* current tunnel */
int session_idx ; /* index of session within current tunnel */
struct l2tp_tunnel * tunnel ;
struct l2tp_session * session ; /* NULL means get next tunnel */
} ;
static void l2tp_dfs_next_tunnel ( struct l2tp_dfs_seq_data * pd )
{
2018-04-12 21:50:35 +03:00
/* Drop reference taken during previous invocation */
if ( pd - > tunnel )
l2tp_tunnel_dec_refcount ( pd - > tunnel ) ;
pd - > tunnel = l2tp_tunnel_get_nth ( pd - > net , pd - > tunnel_idx ) ;
2010-04-02 10:19:33 +04:00
pd - > tunnel_idx + + ;
}
static void l2tp_dfs_next_session ( struct l2tp_dfs_seq_data * pd )
{
2018-04-25 20:54:14 +03:00
/* Drop reference taken during previous invocation */
if ( pd - > session )
l2tp_session_dec_refcount ( pd - > session ) ;
2017-10-31 19:36:42 +03:00
pd - > session = l2tp_session_get_nth ( pd - > tunnel , pd - > session_idx ) ;
2010-04-02 10:19:33 +04:00
pd - > session_idx + + ;
2020-07-23 14:29:50 +03:00
if ( ! pd - > session ) {
2010-04-02 10:19:33 +04:00
pd - > session_idx = 0 ;
l2tp_dfs_next_tunnel ( pd ) ;
}
}
static void * l2tp_dfs_seq_start ( struct seq_file * m , loff_t * offs )
{
struct l2tp_dfs_seq_data * pd = SEQ_START_TOKEN ;
loff_t pos = * offs ;
if ( ! pos )
goto out ;
2020-07-24 18:31:50 +03:00
if ( WARN_ON ( ! m - > private ) ) {
pd = NULL ;
goto out ;
}
2010-04-02 10:19:33 +04:00
pd = m - > private ;
2020-07-23 14:29:50 +03:00
if ( ! pd - > tunnel )
2010-04-02 10:19:33 +04:00
l2tp_dfs_next_tunnel ( pd ) ;
else
l2tp_dfs_next_session ( pd ) ;
/* NULL tunnel and session indicates end of list */
2020-07-23 14:29:50 +03:00
if ( ! pd - > tunnel & & ! pd - > session )
2010-04-02 10:19:33 +04:00
pd = NULL ;
out :
return pd ;
}
static void * l2tp_dfs_seq_next ( struct seq_file * m , void * v , loff_t * pos )
{
( * pos ) + + ;
return NULL ;
}
static void l2tp_dfs_seq_stop ( struct seq_file * p , void * v )
{
2018-04-12 21:50:35 +03:00
struct l2tp_dfs_seq_data * pd = v ;
if ( ! pd | | pd = = SEQ_START_TOKEN )
return ;
2018-04-25 20:54:14 +03:00
/* Drop reference taken by last invocation of l2tp_dfs_next_session()
* or l2tp_dfs_next_tunnel ( ) .
*/
if ( pd - > session ) {
l2tp_session_dec_refcount ( pd - > session ) ;
pd - > session = NULL ;
}
2018-04-19 17:20:48 +03:00
if ( pd - > tunnel ) {
2018-04-12 21:50:35 +03:00
l2tp_tunnel_dec_refcount ( pd - > tunnel ) ;
2018-04-19 17:20:48 +03:00
pd - > tunnel = NULL ;
}
2010-04-02 10:19:33 +04:00
}
static void l2tp_dfs_seq_tunnel_show ( struct seq_file * m , void * v )
{
struct l2tp_tunnel * tunnel = v ;
2021-11-26 19:09:03 +03:00
struct l2tp_session * session ;
2010-04-02 10:19:33 +04:00
int session_count = 0 ;
int hash ;
2021-11-26 19:09:03 +03:00
rcu_read_lock_bh ( ) ;
2010-04-02 10:19:33 +04:00
for ( hash = 0 ; hash < L2TP_HASH_SIZE ; hash + + ) {
2021-11-26 19:09:03 +03:00
hlist_for_each_entry_rcu ( session , & tunnel - > session_hlist [ hash ] , hlist ) {
/* Session ID of zero is a dummy/reserved value used by pppol2tp */
2010-04-02 10:19:33 +04:00
if ( session - > session_id = = 0 )
continue ;
session_count + + ;
}
}
2021-11-26 19:09:03 +03:00
rcu_read_unlock_bh ( ) ;
2010-04-02 10:19:33 +04:00
seq_printf ( m , " \n TUNNEL %u peer %u " , tunnel - > tunnel_id , tunnel - > peer_tunnel_id ) ;
if ( tunnel - > sock ) {
struct inet_sock * inet = inet_sk ( tunnel - > sock ) ;
2012-04-30 01:48:51 +04:00
# if IS_ENABLED(CONFIG_IPV6)
if ( tunnel - > sock - > sk_family = = AF_INET6 ) {
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 02:42:29 +04:00
const struct ipv6_pinfo * np = inet6_sk ( tunnel - > sock ) ;
2012-04-30 01:48:51 +04:00
seq_printf ( m , " from %pI6c to %pI6c \n " ,
2020-07-22 19:32:08 +03:00
& np - > saddr , & tunnel - > sock - > sk_v6_daddr ) ;
2020-07-23 14:29:52 +03:00
}
2012-04-30 01:48:51 +04:00
# endif
2020-07-23 14:29:52 +03:00
if ( tunnel - > sock - > sk_family = = AF_INET )
seq_printf ( m , " from %pI4 to %pI4 \n " ,
& inet - > inet_saddr , & inet - > inet_daddr ) ;
2010-04-02 10:19:33 +04:00
if ( tunnel - > encap = = L2TP_ENCAPTYPE_UDP )
seq_printf ( m , " source port %hu, dest port %hu \n " ,
ntohs ( inet - > inet_sport ) , ntohs ( inet - > inet_dport ) ) ;
}
seq_printf ( m , " L2TPv%d, %s \n " , tunnel - > version ,
tunnel - > encap = = L2TP_ENCAPTYPE_UDP ? " UDP " :
tunnel - > encap = = L2TP_ENCAPTYPE_IP ? " IP " :
" " ) ;
seq_printf ( m , " %d sessions, refcnt %d/%d \n " , session_count ,
2017-06-30 13:08:01 +03:00
tunnel - > sock ? refcount_read ( & tunnel - > sock - > sk_refcnt ) : 0 ,
2017-07-04 15:52:57 +03:00
refcount_read ( & tunnel - > ref_count ) ) ;
2013-03-19 10:11:22 +04:00
seq_printf ( m , " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld \n " ,
2020-08-22 17:59:08 +03:00
0 ,
2013-03-19 10:11:22 +04:00
atomic_long_read ( & tunnel - > stats . tx_packets ) ,
atomic_long_read ( & tunnel - > stats . tx_bytes ) ,
atomic_long_read ( & tunnel - > stats . tx_errors ) ,
atomic_long_read ( & tunnel - > stats . rx_packets ) ,
atomic_long_read ( & tunnel - > stats . rx_bytes ) ,
atomic_long_read ( & tunnel - > stats . rx_errors ) ) ;
2010-04-02 10:19:33 +04:00
}
static void l2tp_dfs_seq_session_show ( struct seq_file * m , void * v )
{
struct l2tp_session * session = v ;
seq_printf ( m , " SESSION %u, peer %u, %s \n " , session - > session_id ,
session - > peer_session_id ,
session - > pwtype = = L2TP_PWTYPE_ETH ? " ETH " :
session - > pwtype = = L2TP_PWTYPE_PPP ? " PPP " :
" " ) ;
if ( session - > send_seq | | session - > recv_seq )
l2tp: l2tp_debugfs: fix Clang -Wformat warnings
When building with Clang we encounter the following warnings:
| net/l2tp/l2tp_debugfs.c:187:40: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] seq_printf(m, " nr %hu, ns %hu\n", session->nr,
| session->ns);
-
| net/l2tp/l2tp_debugfs.c:196:32: error: format specifies type 'unsigned
| short' but the argument has type 'int' [-Werror,-Wformat]
| session->l2specific_type, l2tp_get_l2specific_len(session));
-
| net/l2tp/l2tp_debugfs.c:219:6: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] session->nr, session->ns,
Both session->nr and ->nc are of type `u32`. The currently used format
specifier is `%hu` which describes a `u16`. My proposed fix is to listen
to Clang and use the correct format specifier `%u`.
For the warning at line 196, l2tp_get_l2specific_len() returns an int
and should therefore be using the `%d` format specifier.
Link: https://github.com/ClangBuiltLinux/linux/issues/378
Signed-off-by: Justin Stitt <justinstitt@google.com>
Acked-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-07-08 01:14:56 +03:00
seq_printf ( m , " nr %u, ns %u \n " , session - > nr , session - > ns ) ;
2017-07-04 15:52:57 +03:00
seq_printf ( m , " refcnt %d \n " , refcount_read ( & session - > ref_count ) ) ;
2018-08-03 13:38:39 +03:00
seq_printf ( m , " config 0/0/%c/%c/-/%s %08x %u \n " ,
2010-04-02 10:19:33 +04:00
session - > recv_seq ? ' R ' : ' - ' ,
session - > send_seq ? ' S ' : ' - ' ,
session - > lns_mode ? " LNS " : " LAC " ,
2020-08-22 17:59:08 +03:00
0 ,
2010-04-02 10:19:33 +04:00
jiffies_to_msecs ( session - > reorder_timeout ) ) ;
l2tp: l2tp_debugfs: fix Clang -Wformat warnings
When building with Clang we encounter the following warnings:
| net/l2tp/l2tp_debugfs.c:187:40: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] seq_printf(m, " nr %hu, ns %hu\n", session->nr,
| session->ns);
-
| net/l2tp/l2tp_debugfs.c:196:32: error: format specifies type 'unsigned
| short' but the argument has type 'int' [-Werror,-Wformat]
| session->l2specific_type, l2tp_get_l2specific_len(session));
-
| net/l2tp/l2tp_debugfs.c:219:6: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] session->nr, session->ns,
Both session->nr and ->nc are of type `u32`. The currently used format
specifier is `%hu` which describes a `u16`. My proposed fix is to listen
to Clang and use the correct format specifier `%u`.
For the warning at line 196, l2tp_get_l2specific_len() returns an int
and should therefore be using the `%d` format specifier.
Link: https://github.com/ClangBuiltLinux/linux/issues/378
Signed-off-by: Justin Stitt <justinstitt@google.com>
Acked-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-07-08 01:14:56 +03:00
seq_printf ( m , " offset 0 l2specific %hu/%d \n " ,
2018-01-17 01:01:56 +03:00
session - > l2specific_type , l2tp_get_l2specific_len ( session ) ) ;
2010-04-02 10:19:33 +04:00
if ( session - > cookie_len ) {
seq_printf ( m , " cookie %02x%02x%02x%02x " ,
session - > cookie [ 0 ] , session - > cookie [ 1 ] ,
session - > cookie [ 2 ] , session - > cookie [ 3 ] ) ;
if ( session - > cookie_len = = 8 )
seq_printf ( m , " %02x%02x%02x%02x " ,
session - > cookie [ 4 ] , session - > cookie [ 5 ] ,
session - > cookie [ 6 ] , session - > cookie [ 7 ] ) ;
2020-07-22 19:32:12 +03:00
seq_puts ( m , " \n " ) ;
2010-04-02 10:19:33 +04:00
}
if ( session - > peer_cookie_len ) {
seq_printf ( m , " peer cookie %02x%02x%02x%02x " ,
session - > peer_cookie [ 0 ] , session - > peer_cookie [ 1 ] ,
session - > peer_cookie [ 2 ] , session - > peer_cookie [ 3 ] ) ;
if ( session - > peer_cookie_len = = 8 )
seq_printf ( m , " %02x%02x%02x%02x " ,
session - > peer_cookie [ 4 ] , session - > peer_cookie [ 5 ] ,
session - > peer_cookie [ 6 ] , session - > peer_cookie [ 7 ] ) ;
2020-07-22 19:32:12 +03:00
seq_puts ( m , " \n " ) ;
2010-04-02 10:19:33 +04:00
}
l2tp: l2tp_debugfs: fix Clang -Wformat warnings
When building with Clang we encounter the following warnings:
| net/l2tp/l2tp_debugfs.c:187:40: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] seq_printf(m, " nr %hu, ns %hu\n", session->nr,
| session->ns);
-
| net/l2tp/l2tp_debugfs.c:196:32: error: format specifies type 'unsigned
| short' but the argument has type 'int' [-Werror,-Wformat]
| session->l2specific_type, l2tp_get_l2specific_len(session));
-
| net/l2tp/l2tp_debugfs.c:219:6: error: format specifies type 'unsigned
| short' but the argument has type 'u32' (aka 'unsigned int')
| [-Werror,-Wformat] session->nr, session->ns,
Both session->nr and ->nc are of type `u32`. The currently used format
specifier is `%hu` which describes a `u16`. My proposed fix is to listen
to Clang and use the correct format specifier `%u`.
For the warning at line 196, l2tp_get_l2specific_len() returns an int
and should therefore be using the `%d` format specifier.
Link: https://github.com/ClangBuiltLinux/linux/issues/378
Signed-off-by: Justin Stitt <justinstitt@google.com>
Acked-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2022-07-08 01:14:56 +03:00
seq_printf ( m , " %u/%u tx %ld/%ld/%ld rx %ld/%ld/%ld \n " ,
2010-04-02 10:19:33 +04:00
session - > nr , session - > ns ,
2013-03-19 10:11:22 +04:00
atomic_long_read ( & session - > stats . tx_packets ) ,
atomic_long_read ( & session - > stats . tx_bytes ) ,
atomic_long_read ( & session - > stats . tx_errors ) ,
atomic_long_read ( & session - > stats . rx_packets ) ,
atomic_long_read ( & session - > stats . rx_bytes ) ,
atomic_long_read ( & session - > stats . rx_errors ) ) ;
2010-04-02 10:19:33 +04:00
2020-07-23 14:29:50 +03:00
if ( session - > show )
2010-04-02 10:19:33 +04:00
session - > show ( m , session ) ;
}
static int l2tp_dfs_seq_show ( struct seq_file * m , void * v )
{
struct l2tp_dfs_seq_data * pd = v ;
/* display header on line 1 */
if ( v = = SEQ_START_TOKEN ) {
seq_puts ( m , " TUNNEL ID, peer ID from IP to IP \n " ) ;
seq_puts ( m , " L2TPv2/L2TPv3, UDP/IP \n " ) ;
seq_puts ( m , " sessions session-count, refcnt refcnt/sk->refcnt \n " ) ;
seq_puts ( m , " debug tx-pkts/bytes/errs rx-pkts/bytes/errs \n " ) ;
seq_puts ( m , " SESSION ID, peer ID, PWTYPE \n " ) ;
seq_puts ( m , " refcnt cnt \n " ) ;
2018-01-04 01:48:04 +03:00
seq_puts ( m , " offset OFFSET l2specific TYPE/LEN \n " ) ;
2010-04-02 10:19:33 +04:00
seq_puts ( m , " [ cookie ] \n " ) ;
seq_puts ( m , " [ peer cookie ] \n " ) ;
seq_puts ( m , " config mtu/mru/rcvseq/sendseq/dataseq/lns debug reorderto \n " ) ;
seq_puts ( m , " nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs \n " ) ;
goto out ;
}
2018-04-25 20:54:14 +03:00
if ( ! pd - > session )
2010-04-02 10:19:33 +04:00
l2tp_dfs_seq_tunnel_show ( m , pd - > tunnel ) ;
2018-04-25 20:54:14 +03:00
else
2010-04-02 10:19:33 +04:00
l2tp_dfs_seq_session_show ( m , pd - > session ) ;
out :
return 0 ;
}
static const struct seq_operations l2tp_dfs_seq_ops = {
. start = l2tp_dfs_seq_start ,
. next = l2tp_dfs_seq_next ,
. stop = l2tp_dfs_seq_stop ,
. show = l2tp_dfs_seq_show ,
} ;
static int l2tp_dfs_seq_open ( struct inode * inode , struct file * file )
{
struct l2tp_dfs_seq_data * pd ;
struct seq_file * seq ;
int rc = - ENOMEM ;
2010-10-31 10:26:03 +03:00
pd = kzalloc ( sizeof ( * pd ) , GFP_KERNEL ) ;
2020-07-23 14:29:50 +03:00
if ( ! pd )
2010-04-02 10:19:33 +04:00
goto out ;
/* Derive the network namespace from the pid opening the
* file .
*/
pd - > net = get_net_ns_by_pid ( current - > pid ) ;
if ( IS_ERR ( pd - > net ) ) {
2011-06-05 04:54:03 +04:00
rc = PTR_ERR ( pd - > net ) ;
2010-04-02 10:19:33 +04:00
goto err_free_pd ;
}
2021-12-10 10:44:25 +03:00
netns_tracker_alloc ( pd - > net , & pd - > ns_tracker , GFP_KERNEL ) ;
2010-04-02 10:19:33 +04:00
rc = seq_open ( file , & l2tp_dfs_seq_ops ) ;
if ( rc )
goto err_free_net ;
seq = file - > private_data ;
seq - > private = pd ;
out :
return rc ;
err_free_net :
2021-12-10 10:44:25 +03:00
put_net_track ( pd - > net , & pd - > ns_tracker ) ;
2010-04-02 10:19:33 +04:00
err_free_pd :
kfree ( pd ) ;
goto out ;
}
static int l2tp_dfs_seq_release ( struct inode * inode , struct file * file )
{
struct l2tp_dfs_seq_data * pd ;
struct seq_file * seq ;
seq = file - > private_data ;
pd = seq - > private ;
if ( pd - > net )
2021-12-10 10:44:25 +03:00
put_net_track ( pd - > net , & pd - > ns_tracker ) ;
2010-04-02 10:19:33 +04:00
kfree ( pd ) ;
seq_release ( inode , file ) ;
return 0 ;
}
static const struct file_operations l2tp_dfs_fops = {
. owner = THIS_MODULE ,
. open = l2tp_dfs_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = l2tp_dfs_seq_release ,
} ;
static int __init l2tp_debugfs_init ( void )
{
rootdir = debugfs_create_dir ( " l2tp " , NULL ) ;
2019-06-14 10:04:38 +03:00
debugfs_create_file ( " tunnels " , 0600 , rootdir , NULL , & l2tp_dfs_fops ) ;
2010-04-02 10:19:33 +04:00
2012-05-16 13:55:56 +04:00
pr_info ( " L2TP debugfs support \n " ) ;
2010-04-02 10:19:33 +04:00
2019-06-14 10:04:38 +03:00
return 0 ;
2010-04-02 10:19:33 +04:00
}
static void __exit l2tp_debugfs_exit ( void )
{
2019-06-14 10:04:38 +03:00
debugfs_remove_recursive ( rootdir ) ;
2010-04-02 10:19:33 +04:00
}
module_init ( l2tp_debugfs_init ) ;
module_exit ( l2tp_debugfs_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " James Chapman <jchapman@katalix.com> " ) ;
MODULE_DESCRIPTION ( " L2TP debugfs driver " ) ;
MODULE_VERSION ( " 1.0 " ) ;