Commit 76a081e5 authored by David S. Miller's avatar David S. Miller

Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6

parents 0d6c7ae2 e41542f5
DCCP protocol DCCP protocol
============ ============
Last updated: 10 November 2005
Contents Contents
======== ========
...@@ -42,8 +41,11 @@ Socket options ...@@ -42,8 +41,11 @@ Socket options
DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
calculations. calculations.
DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
specification. If you don't set it you will get EPROTO. service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
the socket will fall back to 0 (which means that no meaningful service code
is present). Connecting sockets set at most one service option; for
listening sockets, multiple service codes can be specified.
Notes Notes
===== =====
......
...@@ -169,6 +169,12 @@ enum { ...@@ -169,6 +169,12 @@ enum {
DCCPO_MAX_CCID_SPECIFIC = 255, DCCPO_MAX_CCID_SPECIFIC = 255,
}; };
/* DCCP CCIDS */
enum {
DCCPC_CCID2 = 2,
DCCPC_CCID3 = 3,
};
/* DCCP features */ /* DCCP features */
enum { enum {
DCCPF_RESERVED = 0, DCCPF_RESERVED = 0,
...@@ -320,7 +326,7 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) ...@@ -320,7 +326,7 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
/* initial values for each feature */ /* initial values for each feature */
#define DCCPF_INITIAL_SEQUENCE_WINDOW 100 #define DCCPF_INITIAL_SEQUENCE_WINDOW 100
#define DCCPF_INITIAL_ACK_RATIO 2 #define DCCPF_INITIAL_ACK_RATIO 2
#define DCCPF_INITIAL_CCID 2 #define DCCPF_INITIAL_CCID DCCPC_CCID2
#define DCCPF_INITIAL_SEND_ACK_VECTOR 1 #define DCCPF_INITIAL_SEND_ACK_VECTOR 1
/* FIXME: for now we're default to 1 but it should really be 0 */ /* FIXME: for now we're default to 1 but it should really be 0 */
#define DCCPF_INITIAL_SEND_NDP_COUNT 1 #define DCCPF_INITIAL_SEND_NDP_COUNT 1
...@@ -404,6 +410,7 @@ struct dccp_service_list { ...@@ -404,6 +410,7 @@ struct dccp_service_list {
}; };
#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
#define DCCP_SERVICE_CODE_IS_ABSENT 0
static inline int dccp_list_has_service(const struct dccp_service_list *sl, static inline int dccp_list_has_service(const struct dccp_service_list *sl,
const __be32 service) const __be32 service)
...@@ -484,11 +491,6 @@ static inline struct dccp_minisock *dccp_msk(const struct sock *sk) ...@@ -484,11 +491,6 @@ static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock; return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
} }
static inline int dccp_service_not_initialized(const struct sock *sk)
{
return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
}
static inline const char *dccp_role(const struct sock *sk) static inline const char *dccp_role(const struct sock *sk)
{ {
switch (dccp_sk(sk)->dccps_role) { switch (dccp_sk(sk)->dccps_role) {
......
...@@ -40,6 +40,22 @@ config IP_DCCP_DEBUG ...@@ -40,6 +40,22 @@ config IP_DCCP_DEBUG
Just say N. Just say N.
config NET_DCCPPROBE
tristate "DCCP connection probing"
depends on PROC_FS && KPROBES
---help---
This module allows for capturing the changes to DCCP connection
state in response to incoming packets. It is used for debugging
DCCP congestion avoidance modules. If you don't understand
what was just said, you don't need it: say N.
Documentation on how to use the packet generator can be found
at http://linux-net.osdl.org/index.php/DccpProbe
To compile this code as a module, choose M here: the
module will be called dccp_probe.
endmenu endmenu
endmenu endmenu
...@@ -11,9 +11,11 @@ dccp_ipv4-y := ipv4.o ...@@ -11,9 +11,11 @@ dccp_ipv4-y := ipv4.o
dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
dccp-$(CONFIG_SYSCTL) += sysctl.o dccp-$(CONFIG_SYSCTL) += sysctl.o
dccp_diag-y := diag.o dccp_diag-y := diag.o
dccp_probe-y := probe.o
obj-y += ccids/ obj-y += ccids/
...@@ -808,7 +808,7 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -808,7 +808,7 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
} }
static struct ccid_operations ccid2 = { static struct ccid_operations ccid2 = {
.ccid_id = 2, .ccid_id = DCCPC_CCID2,
.ccid_name = "ccid2", .ccid_name = "ccid2",
.ccid_owner = THIS_MODULE, .ccid_owner = THIS_MODULE,
.ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
......
...@@ -1240,7 +1240,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, ...@@ -1240,7 +1240,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
} }
static struct ccid_operations ccid3 = { static struct ccid_operations ccid3 = {
.ccid_id = 3, .ccid_id = DCCPC_CCID3,
.ccid_name = "ccid3", .ccid_name = "ccid3",
.ccid_owner = THIS_MODULE, .ccid_owner = THIS_MODULE,
.ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock),
......
...@@ -56,9 +56,6 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -56,9 +56,6 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
dp->dccps_role = DCCP_ROLE_CLIENT; dp->dccps_role = DCCP_ROLE_CLIENT;
if (dccp_service_not_initialized(sk))
return -EPROTO;
if (addr_len < sizeof(struct sockaddr_in)) if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL; return -EINVAL;
......
/*
* dccp_probe - Observe the DCCP flow with kprobes.
*
* The idea for this came from Werner Almesberger's umlsim
* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
*
* Modified for DCCP from Stephen Hemminger's code
* Copyright (C) 2006, Ian McDonald <ian.mcdonald@jandi.co.nz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/socket.h>
#include <linux/dccp.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/kfifo.h>
#include <linux/vmalloc.h>
#include "dccp.h"
#include "ccid.h"
#include "ccids/ccid3.h"
static int port;
static int bufsize = 64 * 1024;
static const char procname[] = "dccpprobe";
struct {
struct kfifo *fifo;
spinlock_t lock;
wait_queue_head_t wait;
struct timeval tstart;
} dccpw;
static void printl(const char *fmt, ...)
{
va_list args;
int len;
struct timeval now;
char tbuf[256];
va_start(args, fmt);
do_gettimeofday(&now);
now.tv_sec -= dccpw.tstart.tv_sec;
now.tv_usec -= dccpw.tstart.tv_usec;
if (now.tv_usec < 0) {
--now.tv_sec;
now.tv_usec += 1000000;
}
len = sprintf(tbuf, "%lu.%06lu ",
(unsigned long) now.tv_sec,
(unsigned long) now.tv_usec);
len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
va_end(args);
kfifo_put(dccpw.fifo, tbuf, len);
wake_up(&dccpw.wait);
}
static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t size)
{
const struct dccp_minisock *dmsk = dccp_msk(sk);
const struct inet_sock *inet = inet_sk(sk);
const struct ccid3_hc_tx_sock *hctx;
if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
hctx = ccid3_hc_tx_sk(sk);
else
hctx = NULL;
if (port == 0 || ntohs(inet->dport) == port ||
ntohs(inet->sport) == port) {
if (hctx)
printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %d\n",
NIPQUAD(inet->saddr), ntohs(inet->sport),
NIPQUAD(inet->daddr), ntohs(inet->dport), size,
hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
hctx->ccid3hctx_p, hctx->ccid3hctx_t_ipi);
else
printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n",
NIPQUAD(inet->saddr), ntohs(inet->sport),
NIPQUAD(inet->daddr), ntohs(inet->dport), size);
}
jprobe_return();
return 0;
}
static struct jprobe dccp_send_probe = {
.kp = { .addr = (kprobe_opcode_t *)&dccp_sendmsg, },
.entry = (kprobe_opcode_t *)&jdccp_sendmsg,
};
static int dccpprobe_open(struct inode *inode, struct file *file)
{
kfifo_reset(dccpw.fifo);
do_gettimeofday(&dccpw.tstart);
return 0;
}
static ssize_t dccpprobe_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int error = 0, cnt = 0;
unsigned char *tbuf;
if (!buf || len < 0)
return -EINVAL;
if (len == 0)
return 0;
tbuf = vmalloc(len);
if (!tbuf)
return -ENOMEM;
error = wait_event_interruptible(dccpw.wait,
__kfifo_len(dccpw.fifo) != 0);
if (error)
goto out_free;
cnt = kfifo_get(dccpw.fifo, tbuf, len);
error = copy_to_user(buf, tbuf, cnt);
out_free:
vfree(tbuf);
return error ? error : cnt;
}
static struct file_operations dccpprobe_fops = {
.owner = THIS_MODULE,
.open = dccpprobe_open,
.read = dccpprobe_read,
};
static __init int dccpprobe_init(void)
{
int ret = -ENOMEM;
init_waitqueue_head(&dccpw.wait);
spin_lock_init(&dccpw.lock);
dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock);
if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops))
goto err0;
ret = register_jprobe(&dccp_send_probe);
if (ret)
goto err1;
pr_info("DCCP watch registered (port=%d)\n", port);
return 0;
err1:
proc_net_remove(procname);
err0:
kfifo_free(dccpw.fifo);
return ret;
}
module_init(dccpprobe_init);
static __exit void dccpprobe_exit(void)
{
kfifo_free(dccpw.fifo);
proc_net_remove(procname);
unregister_jprobe(&dccp_send_probe);
}
module_exit(dccpprobe_exit);
MODULE_PARM_DESC(port, "Port to match (0=all)");
module_param(port, int, 0);
MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
module_param(bufsize, int, 0);
MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>");
MODULE_DESCRIPTION("DCCP snooper");
MODULE_LICENSE("GPL");
...@@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) ...@@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
icsk->icsk_sync_mss = dccp_sync_mss; icsk->icsk_sync_mss = dccp_sync_mss;
dp->dccps_mss_cache = 536; dp->dccps_mss_cache = 536;
dp->dccps_role = DCCP_ROLE_UNDEFINED; dp->dccps_role = DCCP_ROLE_UNDEFINED;
dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
return 0; return 0;
...@@ -267,12 +267,6 @@ static inline int dccp_listen_start(struct sock *sk) ...@@ -267,12 +267,6 @@ static inline int dccp_listen_start(struct sock *sk)
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
dp->dccps_role = DCCP_ROLE_LISTEN; dp->dccps_role = DCCP_ROLE_LISTEN;
/*
* Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
* before calling listen()
*/
if (dccp_service_not_initialized(sk))
return -EPROTO;
return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
} }
...@@ -540,9 +534,6 @@ static int dccp_getsockopt_service(struct sock *sk, int len, ...@@ -540,9 +534,6 @@ static int dccp_getsockopt_service(struct sock *sk, int len,
int err = -ENOENT, slen = 0, total_len = sizeof(u32); int err = -ENOENT, slen = 0, total_len = sizeof(u32);
lock_sock(sk); lock_sock(sk);
if (dccp_service_not_initialized(sk))
goto out;
if ((sl = dp->dccps_service_list) != NULL) { if ((sl = dp->dccps_service_list) != NULL) {
slen = sl->dccpsl_nr * sizeof(u32); slen = sl->dccpsl_nr * sizeof(u32);
total_len += slen; total_len += slen;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment