cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

l2tp_debugfs.c (9231B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* L2TP subsystem debugfs
      3 *
      4 * Copyright (c) 2010 Katalix Systems Ltd
      5 */
      6
      7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      8
      9#include <linux/module.h>
     10#include <linux/skbuff.h>
     11#include <linux/socket.h>
     12#include <linux/hash.h>
     13#include <linux/l2tp.h>
     14#include <linux/in.h>
     15#include <linux/etherdevice.h>
     16#include <linux/spinlock.h>
     17#include <linux/debugfs.h>
     18#include <net/sock.h>
     19#include <net/ip.h>
     20#include <net/icmp.h>
     21#include <net/udp.h>
     22#include <net/inet_common.h>
     23#include <net/inet_hashtables.h>
     24#include <net/tcp_states.h>
     25#include <net/protocol.h>
     26#include <net/xfrm.h>
     27#include <net/net_namespace.h>
     28#include <net/netns/generic.h>
     29
     30#include "l2tp_core.h"
     31
     32static struct dentry *rootdir;
     33
     34struct l2tp_dfs_seq_data {
     35	struct net	*net;
     36	netns_tracker	ns_tracker;
     37	int tunnel_idx;			/* current tunnel */
     38	int session_idx;		/* index of session within current tunnel */
     39	struct l2tp_tunnel *tunnel;
     40	struct l2tp_session *session;	/* NULL means get next tunnel */
     41};
     42
     43static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
     44{
     45	/* Drop reference taken during previous invocation */
     46	if (pd->tunnel)
     47		l2tp_tunnel_dec_refcount(pd->tunnel);
     48
     49	pd->tunnel = l2tp_tunnel_get_nth(pd->net, pd->tunnel_idx);
     50	pd->tunnel_idx++;
     51}
     52
     53static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
     54{
     55	/* Drop reference taken during previous invocation */
     56	if (pd->session)
     57		l2tp_session_dec_refcount(pd->session);
     58
     59	pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx);
     60	pd->session_idx++;
     61
     62	if (!pd->session) {
     63		pd->session_idx = 0;
     64		l2tp_dfs_next_tunnel(pd);
     65	}
     66}
     67
     68static void *l2tp_dfs_seq_start(struct seq_file *m, loff_t *offs)
     69{
     70	struct l2tp_dfs_seq_data *pd = SEQ_START_TOKEN;
     71	loff_t pos = *offs;
     72
     73	if (!pos)
     74		goto out;
     75
     76	if (WARN_ON(!m->private)) {
     77		pd = NULL;
     78		goto out;
     79	}
     80	pd = m->private;
     81
     82	if (!pd->tunnel)
     83		l2tp_dfs_next_tunnel(pd);
     84	else
     85		l2tp_dfs_next_session(pd);
     86
     87	/* NULL tunnel and session indicates end of list */
     88	if (!pd->tunnel && !pd->session)
     89		pd = NULL;
     90
     91out:
     92	return pd;
     93}
     94
     95static void *l2tp_dfs_seq_next(struct seq_file *m, void *v, loff_t *pos)
     96{
     97	(*pos)++;
     98	return NULL;
     99}
    100
    101static void l2tp_dfs_seq_stop(struct seq_file *p, void *v)
    102{
    103	struct l2tp_dfs_seq_data *pd = v;
    104
    105	if (!pd || pd == SEQ_START_TOKEN)
    106		return;
    107
    108	/* Drop reference taken by last invocation of l2tp_dfs_next_session()
    109	 * or l2tp_dfs_next_tunnel().
    110	 */
    111	if (pd->session) {
    112		l2tp_session_dec_refcount(pd->session);
    113		pd->session = NULL;
    114	}
    115	if (pd->tunnel) {
    116		l2tp_tunnel_dec_refcount(pd->tunnel);
    117		pd->tunnel = NULL;
    118	}
    119}
    120
    121static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
    122{
    123	struct l2tp_tunnel *tunnel = v;
    124	struct l2tp_session *session;
    125	int session_count = 0;
    126	int hash;
    127
    128	rcu_read_lock_bh();
    129	for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
    130		hlist_for_each_entry_rcu(session, &tunnel->session_hlist[hash], hlist) {
    131			/* Session ID of zero is a dummy/reserved value used by pppol2tp */
    132			if (session->session_id == 0)
    133				continue;
    134
    135			session_count++;
    136		}
    137	}
    138	rcu_read_unlock_bh();
    139
    140	seq_printf(m, "\nTUNNEL %u peer %u", tunnel->tunnel_id, tunnel->peer_tunnel_id);
    141	if (tunnel->sock) {
    142		struct inet_sock *inet = inet_sk(tunnel->sock);
    143
    144#if IS_ENABLED(CONFIG_IPV6)
    145		if (tunnel->sock->sk_family == AF_INET6) {
    146			const struct ipv6_pinfo *np = inet6_sk(tunnel->sock);
    147
    148			seq_printf(m, " from %pI6c to %pI6c\n",
    149				   &np->saddr, &tunnel->sock->sk_v6_daddr);
    150		}
    151#endif
    152		if (tunnel->sock->sk_family == AF_INET)
    153			seq_printf(m, " from %pI4 to %pI4\n",
    154				   &inet->inet_saddr, &inet->inet_daddr);
    155
    156		if (tunnel->encap == L2TP_ENCAPTYPE_UDP)
    157			seq_printf(m, " source port %hu, dest port %hu\n",
    158				   ntohs(inet->inet_sport), ntohs(inet->inet_dport));
    159	}
    160	seq_printf(m, " L2TPv%d, %s\n", tunnel->version,
    161		   tunnel->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
    162		   tunnel->encap == L2TP_ENCAPTYPE_IP ? "IP" :
    163		   "");
    164	seq_printf(m, " %d sessions, refcnt %d/%d\n", session_count,
    165		   tunnel->sock ? refcount_read(&tunnel->sock->sk_refcnt) : 0,
    166		   refcount_read(&tunnel->ref_count));
    167	seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n",
    168		   0,
    169		   atomic_long_read(&tunnel->stats.tx_packets),
    170		   atomic_long_read(&tunnel->stats.tx_bytes),
    171		   atomic_long_read(&tunnel->stats.tx_errors),
    172		   atomic_long_read(&tunnel->stats.rx_packets),
    173		   atomic_long_read(&tunnel->stats.rx_bytes),
    174		   atomic_long_read(&tunnel->stats.rx_errors));
    175}
    176
    177static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)
    178{
    179	struct l2tp_session *session = v;
    180
    181	seq_printf(m, "  SESSION %u, peer %u, %s\n", session->session_id,
    182		   session->peer_session_id,
    183		   session->pwtype == L2TP_PWTYPE_ETH ? "ETH" :
    184		   session->pwtype == L2TP_PWTYPE_PPP ? "PPP" :
    185		   "");
    186	if (session->send_seq || session->recv_seq)
    187		seq_printf(m, "   nr %hu, ns %hu\n", session->nr, session->ns);
    188	seq_printf(m, "   refcnt %d\n", refcount_read(&session->ref_count));
    189	seq_printf(m, "   config 0/0/%c/%c/-/%s %08x %u\n",
    190		   session->recv_seq ? 'R' : '-',
    191		   session->send_seq ? 'S' : '-',
    192		   session->lns_mode ? "LNS" : "LAC",
    193		   0,
    194		   jiffies_to_msecs(session->reorder_timeout));
    195	seq_printf(m, "   offset 0 l2specific %hu/%hu\n",
    196		   session->l2specific_type, l2tp_get_l2specific_len(session));
    197	if (session->cookie_len) {
    198		seq_printf(m, "   cookie %02x%02x%02x%02x",
    199			   session->cookie[0], session->cookie[1],
    200			   session->cookie[2], session->cookie[3]);
    201		if (session->cookie_len == 8)
    202			seq_printf(m, "%02x%02x%02x%02x",
    203				   session->cookie[4], session->cookie[5],
    204				   session->cookie[6], session->cookie[7]);
    205		seq_puts(m, "\n");
    206	}
    207	if (session->peer_cookie_len) {
    208		seq_printf(m, "   peer cookie %02x%02x%02x%02x",
    209			   session->peer_cookie[0], session->peer_cookie[1],
    210			   session->peer_cookie[2], session->peer_cookie[3]);
    211		if (session->peer_cookie_len == 8)
    212			seq_printf(m, "%02x%02x%02x%02x",
    213				   session->peer_cookie[4], session->peer_cookie[5],
    214				   session->peer_cookie[6], session->peer_cookie[7]);
    215		seq_puts(m, "\n");
    216	}
    217
    218	seq_printf(m, "   %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n",
    219		   session->nr, session->ns,
    220		   atomic_long_read(&session->stats.tx_packets),
    221		   atomic_long_read(&session->stats.tx_bytes),
    222		   atomic_long_read(&session->stats.tx_errors),
    223		   atomic_long_read(&session->stats.rx_packets),
    224		   atomic_long_read(&session->stats.rx_bytes),
    225		   atomic_long_read(&session->stats.rx_errors));
    226
    227	if (session->show)
    228		session->show(m, session);
    229}
    230
    231static int l2tp_dfs_seq_show(struct seq_file *m, void *v)
    232{
    233	struct l2tp_dfs_seq_data *pd = v;
    234
    235	/* display header on line 1 */
    236	if (v == SEQ_START_TOKEN) {
    237		seq_puts(m, "TUNNEL ID, peer ID from IP to IP\n");
    238		seq_puts(m, " L2TPv2/L2TPv3, UDP/IP\n");
    239		seq_puts(m, " sessions session-count, refcnt refcnt/sk->refcnt\n");
    240		seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
    241		seq_puts(m, "  SESSION ID, peer ID, PWTYPE\n");
    242		seq_puts(m, "   refcnt cnt\n");
    243		seq_puts(m, "   offset OFFSET l2specific TYPE/LEN\n");
    244		seq_puts(m, "   [ cookie ]\n");
    245		seq_puts(m, "   [ peer cookie ]\n");
    246		seq_puts(m, "   config mtu/mru/rcvseq/sendseq/dataseq/lns debug reorderto\n");
    247		seq_puts(m, "   nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
    248		goto out;
    249	}
    250
    251	if (!pd->session)
    252		l2tp_dfs_seq_tunnel_show(m, pd->tunnel);
    253	else
    254		l2tp_dfs_seq_session_show(m, pd->session);
    255
    256out:
    257	return 0;
    258}
    259
    260static const struct seq_operations l2tp_dfs_seq_ops = {
    261	.start		= l2tp_dfs_seq_start,
    262	.next		= l2tp_dfs_seq_next,
    263	.stop		= l2tp_dfs_seq_stop,
    264	.show		= l2tp_dfs_seq_show,
    265};
    266
    267static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
    268{
    269	struct l2tp_dfs_seq_data *pd;
    270	struct seq_file *seq;
    271	int rc = -ENOMEM;
    272
    273	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
    274	if (!pd)
    275		goto out;
    276
    277	/* Derive the network namespace from the pid opening the
    278	 * file.
    279	 */
    280	pd->net = get_net_ns_by_pid(current->pid);
    281	if (IS_ERR(pd->net)) {
    282		rc = PTR_ERR(pd->net);
    283		goto err_free_pd;
    284	}
    285	netns_tracker_alloc(pd->net, &pd->ns_tracker, GFP_KERNEL);
    286	rc = seq_open(file, &l2tp_dfs_seq_ops);
    287	if (rc)
    288		goto err_free_net;
    289
    290	seq = file->private_data;
    291	seq->private = pd;
    292
    293out:
    294	return rc;
    295
    296err_free_net:
    297	put_net_track(pd->net, &pd->ns_tracker);
    298err_free_pd:
    299	kfree(pd);
    300	goto out;
    301}
    302
    303static int l2tp_dfs_seq_release(struct inode *inode, struct file *file)
    304{
    305	struct l2tp_dfs_seq_data *pd;
    306	struct seq_file *seq;
    307
    308	seq = file->private_data;
    309	pd = seq->private;
    310	if (pd->net)
    311		put_net_track(pd->net, &pd->ns_tracker);
    312	kfree(pd);
    313	seq_release(inode, file);
    314
    315	return 0;
    316}
    317
    318static const struct file_operations l2tp_dfs_fops = {
    319	.owner		= THIS_MODULE,
    320	.open		= l2tp_dfs_seq_open,
    321	.read		= seq_read,
    322	.llseek		= seq_lseek,
    323	.release	= l2tp_dfs_seq_release,
    324};
    325
    326static int __init l2tp_debugfs_init(void)
    327{
    328	rootdir = debugfs_create_dir("l2tp", NULL);
    329
    330	debugfs_create_file("tunnels", 0600, rootdir, NULL, &l2tp_dfs_fops);
    331
    332	pr_info("L2TP debugfs support\n");
    333
    334	return 0;
    335}
    336
    337static void __exit l2tp_debugfs_exit(void)
    338{
    339	debugfs_remove_recursive(rootdir);
    340}
    341
    342module_init(l2tp_debugfs_init);
    343module_exit(l2tp_debugfs_exit);
    344
    345MODULE_LICENSE("GPL");
    346MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
    347MODULE_DESCRIPTION("L2TP debugfs driver");
    348MODULE_VERSION("1.0");