Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 41631
b: refs/heads/master
c: 6f4e5ff
h: refs/heads/master
i:
  41629: 6a79976
  41627: 1e7ac11
  41623: d94cd20
  41615: 30bf8f9
  41599: 6da8a00
v: v3
  • Loading branch information
Gerrit Renker authored and David S. Miller committed Dec 3, 2006
1 parent 2240d5f commit e9cf397
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 98 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a11d206d0f88e092419877c7f706cafb5e1c2e57
refs/heads/master: 6f4e5fff1e4d46714ea554fd83e44eab534e8b11
16 changes: 16 additions & 0 deletions trunk/Documentation/networking/dccp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ 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.

DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the
partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums
always cover the entire packet and that only fully covered application data is
accepted by the receiver. Hence, when using this feature on the sender, it must
be enabled at the receiver, too with suitable choice of CsCov.

DCCP_SOCKOPT_SEND_CSCOV sets the sender checksum coverage. Values in the
range 0..15 are acceptable. The default setting is 0 (full coverage),
values between 1..15 indicate partial coverage.
DCCP_SOCKOPT_SEND_CSCOV is for the receiver and has a different meaning: it
sets a threshold, where again values 0..15 are acceptable. The default
of 0 means that all packets with a partial coverage will be discarded.
Values in the range 1..15 indicate that packets with minimally such a
coverage value are also acceptable. The higher the number, the more
restrictive this setting (see [RFC 4340, sec. 9.2.1]).

Notes
=====

Expand Down
7 changes: 7 additions & 0 deletions trunk/include/linux/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ enum {
DCCPF_ACK_RATIO = 5,
DCCPF_SEND_ACK_VECTOR = 6,
DCCPF_SEND_NDP_COUNT = 7,
DCCPF_MIN_CSUM_COVER = 8,
/* 10-127 reserved */
DCCPF_MIN_CCID_SPECIFIC = 128,
DCCPF_MAX_CCID_SPECIFIC = 255,
Expand All @@ -200,6 +201,8 @@ struct dccp_so_feat {
#define DCCP_SOCKOPT_SERVICE 2
#define DCCP_SOCKOPT_CHANGE_L 3
#define DCCP_SOCKOPT_CHANGE_R 4
#define DCCP_SOCKOPT_SEND_CSCOV 10
#define DCCP_SOCKOPT_RECV_CSCOV 11
#define DCCP_SOCKOPT_CCID_RX_INFO 128
#define DCCP_SOCKOPT_CCID_TX_INFO 192

Expand Down Expand Up @@ -450,6 +453,8 @@ struct dccp_ackvec;
* @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option
* @dccps_packet_size - Set thru setsockopt
* @dccps_role - Role of this sock, one of %dccp_role
* @dccps_pcslen - sender partial checksum coverage (via sockopt)
* @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
* @dccps_ndp_count - number of Non Data Packets since last data packet
* @dccps_hc_rx_ackvec - rx half connection ack vector
* @dccps_xmit_timer - timer for when CCID is not ready to send
Expand All @@ -474,6 +479,8 @@ struct dccp_sock {
__u32 dccps_packet_size;
__u16 dccps_l_ack_ratio;
__u16 dccps_r_ack_ratio;
__u16 dccps_pcslen;
__u16 dccps_pcrlen;
unsigned long dccps_ndp_count;
__u32 dccps_mss_cache;
struct dccp_minisock dccps_minisock;
Expand Down
29 changes: 24 additions & 5 deletions trunk/net/dccp/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,30 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
#define DCCP_ADD_STATS_USER(field, val) \
SNMP_ADD_STATS_USER(dccp_statistics, field, val)

/*
* Checksumming routines
*/
static inline int dccp_csum_coverage(const struct sk_buff *skb)
{
const struct dccp_hdr* dh = dccp_hdr(skb);

if (dh->dccph_cscov == 0)
return skb->len;
return (dh->dccph_doff + dh->dccph_cscov - 1) * sizeof(u32);
}

static inline void dccp_csum_outgoing(struct sk_buff *skb)
{
int cov = dccp_csum_coverage(skb);

if (cov >= skb->len)
dccp_hdr(skb)->dccph_cscov = 0;

skb->csum = skb_checksum(skb, 0, (cov > skb->len)? skb->len : cov, 0);
}

extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);

extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb);

extern void dccp_send_ack(struct sock *sk);
Expand Down Expand Up @@ -214,14 +238,9 @@ extern void dccp_shutdown(struct sock *sk, int how);
extern int inet_dccp_listen(struct socket *sock, int backlog);
extern unsigned int dccp_poll(struct file *file, struct socket *sock,
poll_table *wait);
extern void dccp_v4_send_check(struct sock *sk, int len,
struct sk_buff *skb);
extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len);

extern int dccp_v4_checksum(const struct sk_buff *skb,
const __be32 saddr, const __be32 daddr);

extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
extern void dccp_send_close(struct sock *sk, const int active);
extern int dccp_invalid_packet(struct sk_buff *skb);
Expand Down
105 changes: 52 additions & 53 deletions trunk/net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,13 +349,19 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
sock_put(sk);
}

/* This routine computes an IPv4 DCCP checksum. */
void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
static inline u16 dccp_v4_csum_finish(struct sk_buff *skb,
__be32 src, __be32 dst)
{
return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum);
}

void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb)
{
const struct inet_sock *inet = inet_sk(sk);
struct dccp_hdr *dh = dccp_hdr(skb);

dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr, inet->daddr);
dccp_csum_outgoing(skb);
dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr);
}

EXPORT_SYMBOL_GPL(dccp_v4_send_check);
Expand Down Expand Up @@ -454,47 +460,6 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
return sk;
}

int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr,
const __be32 daddr)
{
const struct dccp_hdr* dh = dccp_hdr(skb);
int checksum_len;
u32 tmp;

if (dh->dccph_cscov == 0)
checksum_len = skb->len;
else {
checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
checksum_len = checksum_len < skb->len ? checksum_len :
skb->len;
}

tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
return csum_tcpudp_magic(saddr, daddr, checksum_len,
IPPROTO_DCCP, tmp);
}

EXPORT_SYMBOL_GPL(dccp_v4_checksum);

static int dccp_v4_verify_checksum(struct sk_buff *skb,
const __be32 saddr, const __be32 daddr)
{
struct dccp_hdr *dh = dccp_hdr(skb);
int checksum_len;
u32 tmp;

if (dh->dccph_cscov == 0)
checksum_len = skb->len;
else {
checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
checksum_len = checksum_len < skb->len ? checksum_len :
skb->len;
}
tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
return csum_tcpudp_magic(saddr, daddr, checksum_len,
IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
}

static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
struct sk_buff *skb)
{
Expand Down Expand Up @@ -536,8 +501,8 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
const struct inet_request_sock *ireq = inet_rsk(req);
struct dccp_hdr *dh = dccp_hdr(skb);

dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr,
ireq->rmt_addr);
dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr,
ireq->rmt_addr);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
ireq->rmt_addr,
Expand Down Expand Up @@ -602,8 +567,9 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
DCCP_SKB_CB(rxskb)->dccpd_seq);

dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
rxskb->nh.iph->daddr);
dccp_csum_outgoing(skb);
dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr,
rxskb->nh.iph->daddr);

bh_lock_sock(dccp_v4_ctl_socket->sk);
err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
Expand Down Expand Up @@ -779,6 +745,7 @@ EXPORT_SYMBOL_GPL(dccp_v4_do_rcv);
int dccp_invalid_packet(struct sk_buff *skb)
{
const struct dccp_hdr *dh;
unsigned int cscov;

if (skb->pkt_type != PACKET_HOST)
return 1;
Expand Down Expand Up @@ -830,6 +797,22 @@ int dccp_invalid_packet(struct sk_buff *skb)
return 1;
}

/*
* If P.CsCov is too large for the packet size, drop packet and return.
* This must come _before_ checksumming (not as RFC 4340 suggests).
*/
cscov = dccp_csum_coverage(skb);
if (cscov > skb->len) {
LIMIT_NETDEBUG(KERN_WARNING
"DCCP: P.CsCov %u exceeds packet length %d\n",
dh->dccph_cscov, skb->len);
return 1;
}

/* If header checksum is incorrect, drop packet and return.
* (This step is completed in the AF-dependent functions.) */
skb->csum = skb_checksum(skb, 0, cscov, 0);

return 0;
}

Expand All @@ -840,16 +823,17 @@ static int dccp_v4_rcv(struct sk_buff *skb)
{
const struct dccp_hdr *dh;
struct sock *sk;
int min_cov;

/* Step 1: Check header basics: */
/* Step 1: Check header basics */

if (dccp_invalid_packet(skb))
goto discard_it;

/* If the header checksum is incorrect, drop packet and return */
if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
skb->nh.iph->daddr) < 0) {
LIMIT_NETDEBUG(KERN_WARNING "%s: incorrect header checksum\n",
/* Step 1: If header checksum is incorrect, drop packet and return */
if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) {
LIMIT_NETDEBUG(KERN_WARNING
"%s: dropped packet with invalid checksum\n",
__FUNCTION__);
goto discard_it;
}
Expand Down Expand Up @@ -905,6 +889,21 @@ static int dccp_v4_rcv(struct sk_buff *skb)
goto no_dccp_socket;
}

/*
* RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
* o if MinCsCov = 0, only packets with CsCov = 0 are accepted
* o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
*/
min_cov = dccp_sk(sk)->dccps_pcrlen;
if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",
dh->dccph_cscov, min_cov);
/* FIXME: "Such packets SHOULD be reported using Data Dropped
* options (Section 11.7) with Drop Code 0, Protocol
* Constraints." */
goto discard_and_relse;
}

if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse;
nf_reset(skb);
Expand Down
Loading

0 comments on commit e9cf397

Please sign in to comment.