summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshifumi Nishida <nishida@csl.sony.co.jp>2005-08-10 07:15:35 +0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-30 02:49:55 +0400
commit95b81ef794278c835b321f6376b0522cd5df59b7 (patch)
treec2163130b2a2e1bc8ced9ee70b4c87fcbe7cdf8e
parenta019d6fe2b9da68ea4ba6cf3c4e86fc1dbf554c3 (diff)
downloadlinux-95b81ef794278c835b321f6376b0522cd5df59b7.tar.xz
[DCCP]: Fix checksum routines
Signed-off-by: Yoshifumi Nishida <nishida@csl.sony.co.jp> Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/dccp/dccp.h3
-rw-r--r--net/dccp/ipv4.c38
-rw-r--r--net/dccp/output.c9
3 files changed, 28 insertions, 22 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index fb83454102c1..55b690ab61ae 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -242,7 +242,8 @@ extern int dccp_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen);
extern void dccp_shutdown(struct sock *sk, int how);
-extern int dccp_v4_checksum(struct sk_buff *skb);
+extern int dccp_v4_checksum(const struct sk_buff *skb,
+ const u32 saddr, const u32 daddr);
extern int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code);
extern void dccp_send_close(struct sock *sk);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 083bacaecb3b..7b90606ec10e 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -802,9 +802,9 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
return sk;
}
-int dccp_v4_checksum(struct sk_buff *skb)
+int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr)
{
- struct dccp_hdr* dh = dccp_hdr(skb);
+ const struct dccp_hdr* dh = dccp_hdr(skb);
int checksum_len;
u32 tmp;
@@ -816,24 +816,24 @@ int dccp_v4_checksum(struct sk_buff *skb)
}
tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
- return csum_fold(tmp);
+ return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp);
}
-static int dccp_v4_verify_checksum(struct sk_buff *skb)
+static int dccp_v4_verify_checksum(struct sk_buff *skb,
+ const u32 saddr, const u32 daddr)
{
- struct dccp_hdr *th = dccp_hdr(skb);
- const u16 remote_checksum = th->dccph_checksum;
- u16 local_checksum;
-
- /* FIXME: don't mess with skb payload */
- th->dccph_checksum = 0; /* zero it for computation */
-
- local_checksum = dccp_v4_checksum(skb);
-
- /* FIXME: don't mess with skb payload */
- th->dccph_checksum = remote_checksum; /* put it back */
+ struct dccp_hdr *dh = dccp_hdr(skb);
+ int checksum_len;
+ u32 tmp;
- return remote_checksum == local_checksum ? 0 : -1;
+ 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,
@@ -902,7 +902,8 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
- dh->dccph_checksum = dccp_v4_checksum(skb);
+ dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
+ rxskb->nh.iph->daddr);
bh_lock_sock(dccp_ctl_socket->sk);
err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
@@ -1024,7 +1025,8 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
}
/* If the header checksum is incorrect, drop packet and return */
- if (dccp_v4_verify_checksum(skb) < 0) {
+ if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
+ skb->nh.iph->daddr) < 0) {
dccp_pr_debug("header checksum is incorrect\n");
return 1;
}
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 22ca2910d4f2..4945eaa9d1a4 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -93,7 +93,8 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
break;
}
- dh->dccph_checksum = dccp_v4_checksum(skb);
+ dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr,
+ inet->daddr);
if (dcb->dccpd_type == DCCP_PKT_ACK ||
dcb->dccpd_type == DCCP_PKT_DATAACK)
@@ -193,7 +194,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss);
dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr);
- dh->dccph_checksum = dccp_v4_checksum(skb);
+ dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
+ inet_rsk(req)->rmt_addr);
DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
return skb;
@@ -242,7 +244,8 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
dccp_hdr_reset(skb)->dccph_reset_code = code;
- dh->dccph_checksum = dccp_v4_checksum(skb);
+ dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr,
+ inet_sk(sk)->daddr);
DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
return skb;