aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-09-24 22:29:57 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-24 22:29:57 -0400
commit76a081e5b32fde17f6f6d007e1806744cc848712 (patch)
tree869a5a0c406fbc71ffb803f57aad147014510f27
parent0d6c7ae22d4fadbc83677ea1a6144eea8911e319 (diff)
parente41542f5167d6b506607f8dd111fa0a3e468ccb8 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6
-rw-r--r--Documentation/networking/dccp.txt8
-rw-r--r--include/linux/dccp.h14
-rw-r--r--net/dccp/Kconfig16
-rw-r--r--net/dccp/Makefile2
-rw-r--r--net/dccp/ccids/ccid2.c2
-rw-r--r--net/dccp/ccids/ccid3.c2
-rw-r--r--net/dccp/ipv4.c3
-rw-r--r--net/dccp/probe.c198
-rw-r--r--net/dccp/proto.c11
9 files changed, 232 insertions, 24 deletions
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index c45daabd3bfe..74563b38ffd9 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -1,7 +1,6 @@
1DCCP protocol 1DCCP protocol
2============ 2============
3 3
4Last updated: 10 November 2005
5 4
6Contents 5Contents
7======== 6========
@@ -42,8 +41,11 @@ Socket options
42DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for 41DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
43calculations. 42calculations.
44 43
45DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the 44DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
46specification. If you don't set it you will get EPROTO. 45service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
46the socket will fall back to 0 (which means that no meaningful service code
47is present). Connecting sockets set at most one service option; for
48listening sockets, multiple service codes can be specified.
47 49
48Notes 50Notes
49===== 51=====
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 2d7671c92c0b..d6f4ec467a4b 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -169,6 +169,12 @@ enum {
169 DCCPO_MAX_CCID_SPECIFIC = 255, 169 DCCPO_MAX_CCID_SPECIFIC = 255,
170}; 170};
171 171
172/* DCCP CCIDS */
173enum {
174 DCCPC_CCID2 = 2,
175 DCCPC_CCID3 = 3,
176};
177
172/* DCCP features */ 178/* DCCP features */
173enum { 179enum {
174 DCCPF_RESERVED = 0, 180 DCCPF_RESERVED = 0,
@@ -320,7 +326,7 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
320/* initial values for each feature */ 326/* initial values for each feature */
321#define DCCPF_INITIAL_SEQUENCE_WINDOW 100 327#define DCCPF_INITIAL_SEQUENCE_WINDOW 100
322#define DCCPF_INITIAL_ACK_RATIO 2 328#define DCCPF_INITIAL_ACK_RATIO 2
323#define DCCPF_INITIAL_CCID 2 329#define DCCPF_INITIAL_CCID DCCPC_CCID2
324#define DCCPF_INITIAL_SEND_ACK_VECTOR 1 330#define DCCPF_INITIAL_SEND_ACK_VECTOR 1
325/* FIXME: for now we're default to 1 but it should really be 0 */ 331/* FIXME: for now we're default to 1 but it should really be 0 */
326#define DCCPF_INITIAL_SEND_NDP_COUNT 1 332#define DCCPF_INITIAL_SEND_NDP_COUNT 1
@@ -404,6 +410,7 @@ struct dccp_service_list {
404}; 410};
405 411
406#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) 412#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
413#define DCCP_SERVICE_CODE_IS_ABSENT 0
407 414
408static inline int dccp_list_has_service(const struct dccp_service_list *sl, 415static inline int dccp_list_has_service(const struct dccp_service_list *sl,
409 const __be32 service) 416 const __be32 service)
@@ -484,11 +491,6 @@ static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
484 return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock; 491 return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
485} 492}
486 493
487static inline int dccp_service_not_initialized(const struct sock *sk)
488{
489 return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
490}
491
492static inline const char *dccp_role(const struct sock *sk) 494static inline const char *dccp_role(const struct sock *sk)
493{ 495{
494 switch (dccp_sk(sk)->dccps_role) { 496 switch (dccp_sk(sk)->dccps_role) {
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/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 457dd3db7f41..2efb505aeb35 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -808,7 +808,7 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
808} 808}
809 809
810static struct ccid_operations ccid2 = { 810static struct ccid_operations ccid2 = {
811 .ccid_id = 2, 811 .ccid_id = DCCPC_CCID2,
812 .ccid_name = "ccid2", 812 .ccid_name = "ccid2",
813 .ccid_owner = THIS_MODULE, 813 .ccid_owner = THIS_MODULE,
814 .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), 814 .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 195aa9566228..67d2dc0e7c67 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -1240,7 +1240,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
1240} 1240}
1241 1241
1242static struct ccid_operations ccid3 = { 1242static struct ccid_operations ccid3 = {
1243 .ccid_id = 3, 1243 .ccid_id = DCCPC_CCID3,
1244 .ccid_name = "ccid3", 1244 .ccid_name = "ccid3",
1245 .ccid_owner = THIS_MODULE, 1245 .ccid_owner = THIS_MODULE,
1246 .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), 1246 .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock),
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 9a1a76a7dc41..66be29b6f508 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -56,9 +56,6 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
56 56
57 dp->dccps_role = DCCP_ROLE_CLIENT; 57 dp->dccps_role = DCCP_ROLE_CLIENT;
58 58
59 if (dccp_service_not_initialized(sk))
60 return -EPROTO;
61
62 if (addr_len < sizeof(struct sockaddr_in)) 59 if (addr_len < sizeof(struct sockaddr_in))
63 return -EINVAL; 60 return -EINVAL;
64 61
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");
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 962df0ea31aa..72cbdcfc2c65 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
217 icsk->icsk_sync_mss = dccp_sync_mss; 217 icsk->icsk_sync_mss = dccp_sync_mss;
218 dp->dccps_mss_cache = 536; 218 dp->dccps_mss_cache = 536;
219 dp->dccps_role = DCCP_ROLE_UNDEFINED; 219 dp->dccps_role = DCCP_ROLE_UNDEFINED;
220 dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; 220 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
221 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; 221 dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
222 222
223 return 0; 223 return 0;
@@ -267,12 +267,6 @@ static inline int dccp_listen_start(struct sock *sk)
267 struct dccp_sock *dp = dccp_sk(sk); 267 struct dccp_sock *dp = dccp_sk(sk);
268 268
269 dp->dccps_role = DCCP_ROLE_LISTEN; 269 dp->dccps_role = DCCP_ROLE_LISTEN;
270 /*
271 * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
272 * before calling listen()
273 */
274 if (dccp_service_not_initialized(sk))
275 return -EPROTO;
276 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); 270 return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
277} 271}
278 272
@@ -540,9 +534,6 @@ static int dccp_getsockopt_service(struct sock *sk, int len,
540 int err = -ENOENT, slen = 0, total_len = sizeof(u32); 534 int err = -ENOENT, slen = 0, total_len = sizeof(u32);
541 535
542 lock_sock(sk); 536 lock_sock(sk);
543 if (dccp_service_not_initialized(sk))
544 goto out;
545
546 if ((sl = dp->dccps_service_list) != NULL) { 537 if ((sl = dp->dccps_service_list) != NULL) {
547 slen = sl->dccpsl_nr * sizeof(u32); 538 slen = sl->dccpsl_nr * sizeof(u32);
548 total_len += slen; 539 total_len += slen;