aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/Kconfig16
-rw-r--r--net/dccp/Makefile2
-rw-r--r--net/dccp/probe.c198
3 files changed, 216 insertions, 0 deletions
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
index 859e3359fcda..e2a095d0fd80 100644
--- a/net/dccp/Kconfig
+++ b/net/dccp/Kconfig
@@ -40,6 +40,22 @@ config IP_DCCP_DEBUG
40 40
41 Just say N. 41 Just say N.
42 42
43config NET_DCCPPROBE
44 tristate "DCCP connection probing"
45 depends on PROC_FS && KPROBES
46 ---help---
47 This module allows for capturing the changes to DCCP connection
48 state in response to incoming packets. It is used for debugging
49 DCCP congestion avoidance modules. If you don't understand
50 what was just said, you don't need it: say N.
51
52 Documentation on how to use the packet generator can be found
53 at http://linux-net.osdl.org/index.php/DccpProbe
54
55 To compile this code as a module, choose M here: the
56 module will be called dccp_probe.
57
58
43endmenu 59endmenu
44 60
45endmenu 61endmenu
diff --git a/net/dccp/Makefile b/net/dccp/Makefile
index 7696e219b05d..17ed99c46617 100644
--- a/net/dccp/Makefile
+++ b/net/dccp/Makefile
@@ -11,9 +11,11 @@ dccp_ipv4-y := ipv4.o
11dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o 11dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
12 12
13obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o 13obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
14obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
14 15
15dccp-$(CONFIG_SYSCTL) += sysctl.o 16dccp-$(CONFIG_SYSCTL) += sysctl.o
16 17
17dccp_diag-y := diag.o 18dccp_diag-y := diag.o
19dccp_probe-y := probe.o
18 20
19obj-y += ccids/ 21obj-y += ccids/
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
new file mode 100644
index 000000000000..146496fce2e2
--- /dev/null
+++ b/net/dccp/probe.c
@@ -0,0 +1,198 @@
1/*
2 * dccp_probe - Observe the DCCP flow with kprobes.
3 *
4 * The idea for this came from Werner Almesberger's umlsim
5 * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
6 *
7 * Modified for DCCP from Stephen Hemminger's code
8 * Copyright (C) 2006, Ian McDonald <ian.mcdonald@jandi.co.nz>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include <linux/kernel.h>
26#include <linux/kprobes.h>
27#include <linux/socket.h>
28#include <linux/dccp.h>
29#include <linux/proc_fs.h>
30#include <linux/module.h>
31#include <linux/kfifo.h>
32#include <linux/vmalloc.h>
33
34#include "dccp.h"
35#include "ccid.h"
36#include "ccids/ccid3.h"
37
38static int port;
39
40static int bufsize = 64 * 1024;
41
42static const char procname[] = "dccpprobe";
43
44struct {
45 struct kfifo *fifo;
46 spinlock_t lock;
47 wait_queue_head_t wait;
48 struct timeval tstart;
49} dccpw;
50
51static void printl(const char *fmt, ...)
52{
53 va_list args;
54 int len;
55 struct timeval now;
56 char tbuf[256];
57
58 va_start(args, fmt);
59 do_gettimeofday(&now);
60
61 now.tv_sec -= dccpw.tstart.tv_sec;
62 now.tv_usec -= dccpw.tstart.tv_usec;
63 if (now.tv_usec < 0) {
64 --now.tv_sec;
65 now.tv_usec += 1000000;
66 }
67
68 len = sprintf(tbuf, "%lu.%06lu ",
69 (unsigned long) now.tv_sec,
70 (unsigned long) now.tv_usec);
71 len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
72 va_end(args);
73
74 kfifo_put(dccpw.fifo, tbuf, len);
75 wake_up(&dccpw.wait);
76}
77
78static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
79 struct msghdr *msg, size_t size)
80{
81 const struct dccp_minisock *dmsk = dccp_msk(sk);
82 const struct inet_sock *inet = inet_sk(sk);
83 const struct ccid3_hc_tx_sock *hctx;
84
85 if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
86 hctx = ccid3_hc_tx_sk(sk);
87 else
88 hctx = NULL;
89
90 if (port == 0 || ntohs(inet->dport) == port ||
91 ntohs(inet->sport) == port) {
92 if (hctx)
93 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %d\n",
94 NIPQUAD(inet->saddr), ntohs(inet->sport),
95 NIPQUAD(inet->daddr), ntohs(inet->dport), size,
96 hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
97 hctx->ccid3hctx_p, hctx->ccid3hctx_t_ipi);
98 else
99 printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n",
100 NIPQUAD(inet->saddr), ntohs(inet->sport),
101 NIPQUAD(inet->daddr), ntohs(inet->dport), size);
102 }
103
104 jprobe_return();
105 return 0;
106}
107
108static struct jprobe dccp_send_probe = {
109 .kp = { .addr = (kprobe_opcode_t *)&dccp_sendmsg, },
110 .entry = (kprobe_opcode_t *)&jdccp_sendmsg,
111};
112
113static int dccpprobe_open(struct inode *inode, struct file *file)
114{
115 kfifo_reset(dccpw.fifo);
116 do_gettimeofday(&dccpw.tstart);
117 return 0;
118}
119
120static ssize_t dccpprobe_read(struct file *file, char __user *buf,
121 size_t len, loff_t *ppos)
122{
123 int error = 0, cnt = 0;
124 unsigned char *tbuf;
125
126 if (!buf || len < 0)
127 return -EINVAL;
128
129 if (len == 0)
130 return 0;
131
132 tbuf = vmalloc(len);
133 if (!tbuf)
134 return -ENOMEM;
135
136 error = wait_event_interruptible(dccpw.wait,
137 __kfifo_len(dccpw.fifo) != 0);
138 if (error)
139 goto out_free;
140
141 cnt = kfifo_get(dccpw.fifo, tbuf, len);
142 error = copy_to_user(buf, tbuf, cnt);
143
144out_free:
145 vfree(tbuf);
146
147 return error ? error : cnt;
148}
149
150static struct file_operations dccpprobe_fops = {
151 .owner = THIS_MODULE,
152 .open = dccpprobe_open,
153 .read = dccpprobe_read,
154};
155
156static __init int dccpprobe_init(void)
157{
158 int ret = -ENOMEM;
159
160 init_waitqueue_head(&dccpw.wait);
161 spin_lock_init(&dccpw.lock);
162 dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock);
163
164 if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops))
165 goto err0;
166
167 ret = register_jprobe(&dccp_send_probe);
168 if (ret)
169 goto err1;
170
171 pr_info("DCCP watch registered (port=%d)\n", port);
172 return 0;
173err1:
174 proc_net_remove(procname);
175err0:
176 kfifo_free(dccpw.fifo);
177 return ret;
178}
179module_init(dccpprobe_init);
180
181static __exit void dccpprobe_exit(void)
182{
183 kfifo_free(dccpw.fifo);
184 proc_net_remove(procname);
185 unregister_jprobe(&dccp_send_probe);
186
187}
188module_exit(dccpprobe_exit);
189
190MODULE_PARM_DESC(port, "Port to match (0=all)");
191module_param(port, int, 0);
192
193MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
194module_param(bufsize, int, 0);
195
196MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>");
197MODULE_DESCRIPTION("DCCP snooper");
198MODULE_LICENSE("GPL");