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