aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,
242 char *optval, int optlen); 242 char *optval, int optlen);
243extern void dccp_shutdown(struct sock *sk, int how); 243extern void dccp_shutdown(struct sock *sk, int how);
244 244
245extern int dccp_v4_checksum(struct sk_buff *skb); 245extern int dccp_v4_checksum(const struct sk_buff *skb,
246 const u32 saddr, const u32 daddr);
246 247
247extern int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code); 248extern int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code);
248extern void dccp_send_close(struct sock *sk); 249extern 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)
802 return sk; 802 return sk;
803} 803}
804 804
805int dccp_v4_checksum(struct sk_buff *skb) 805int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr)
806{ 806{
807 struct dccp_hdr* dh = dccp_hdr(skb); 807 const struct dccp_hdr* dh = dccp_hdr(skb);
808 int checksum_len; 808 int checksum_len;
809 u32 tmp; 809 u32 tmp;
810 810
@@ -816,24 +816,24 @@ int dccp_v4_checksum(struct sk_buff *skb)
816 } 816 }
817 817
818 tmp = csum_partial((unsigned char *)dh, checksum_len, 0); 818 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
819 return csum_fold(tmp); 819 return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp);
820} 820}
821 821
822static int dccp_v4_verify_checksum(struct sk_buff *skb) 822static int dccp_v4_verify_checksum(struct sk_buff *skb,
823 const u32 saddr, const u32 daddr)
823{ 824{
824 struct dccp_hdr *th = dccp_hdr(skb); 825 struct dccp_hdr *dh = dccp_hdr(skb);
825 const u16 remote_checksum = th->dccph_checksum; 826 int checksum_len;
826 u16 local_checksum; 827 u32 tmp;
827
828 /* FIXME: don't mess with skb payload */
829 th->dccph_checksum = 0; /* zero it for computation */
830
831 local_checksum = dccp_v4_checksum(skb);
832
833 /* FIXME: don't mess with skb payload */
834 th->dccph_checksum = remote_checksum; /* put it back */
835 828
836 return remote_checksum == local_checksum ? 0 : -1; 829 if (dh->dccph_cscov == 0)
830 checksum_len = skb->len;
831 else {
832 checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
833 checksum_len = checksum_len < skb->len ? checksum_len : skb->len;
834 }
835 tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
836 return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
837} 837}
838 838
839static struct dst_entry* dccp_v4_route_skb(struct sock *sk, 839static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
@@ -902,7 +902,8 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
902 dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); 902 dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
903 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); 903 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
904 904
905 dh->dccph_checksum = dccp_v4_checksum(skb); 905 dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
906 rxskb->nh.iph->daddr);
906 907
907 bh_lock_sock(dccp_ctl_socket->sk); 908 bh_lock_sock(dccp_ctl_socket->sk);
908 err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, 909 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)
1024 } 1025 }
1025 1026
1026 /* If the header checksum is incorrect, drop packet and return */ 1027 /* If the header checksum is incorrect, drop packet and return */
1027 if (dccp_v4_verify_checksum(skb) < 0) { 1028 if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
1029 skb->nh.iph->daddr) < 0) {
1028 dccp_pr_debug("header checksum is incorrect\n"); 1030 dccp_pr_debug("header checksum is incorrect\n");
1029 return 1; 1031 return 1;
1030 } 1032 }
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)
93 break; 93 break;
94 } 94 }
95 95
96 dh->dccph_checksum = dccp_v4_checksum(skb); 96 dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr,
97 inet->daddr);
97 98
98 if (dcb->dccpd_type == DCCP_PKT_ACK || 99 if (dcb->dccpd_type == DCCP_PKT_ACK ||
99 dcb->dccpd_type == DCCP_PKT_DATAACK) 100 dcb->dccpd_type == DCCP_PKT_DATAACK)
@@ -193,7 +194,8 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
193 dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss); 194 dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss);
194 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr); 195 dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr);
195 196
196 dh->dccph_checksum = dccp_v4_checksum(skb); 197 dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
198 inet_rsk(req)->rmt_addr);
197 199
198 DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 200 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
199 return skb; 201 return skb;
@@ -242,7 +244,8 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
242 244
243 dccp_hdr_reset(skb)->dccph_reset_code = code; 245 dccp_hdr_reset(skb)->dccph_reset_code = code;
244 246
245 dh->dccph_checksum = dccp_v4_checksum(skb); 247 dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr,
248 inet_sk(sk)->daddr);
246 249
247 DCCP_INC_STATS(DCCP_MIB_OUTSEGS); 250 DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
248 return skb; 251 return skb;