Commit 276829d1 authored by Jon Grimm's avatar Jon Grimm Committed by Sridhar Samudrala

[SCTP] Add a generic csum_copy for sctp.

Do the sctp checksum while copying. 
parent 845401fc
...@@ -153,6 +153,7 @@ extern int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg) ...@@ -153,6 +153,7 @@ extern int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg)
extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count); extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
extern __u32 sctp_end_cksum(__u32 cksum); extern __u32 sctp_end_cksum(__u32 cksum);
extern __u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum);
/* /*
* sctp/input.c * sctp/input.c
......
...@@ -2,43 +2,43 @@ ...@@ -2,43 +2,43 @@
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp. * Copyright (c) 2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This file has direct heritage from the SCTP user-level reference * This file has direct heritage from the SCTP user-level reference
* implementation by R. Stewart, et al. These functions implement the * implementation by R. Stewart, et al. These functions implement the
* Adler-32 algorithm as specified by RFC 2960. * Adler-32 algorithm as specified by RFC 2960.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* Randall Stewart <rstewar1@email.mot.com> * Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com> * Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com> * Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
* tad, but I have commented the original lines below * tad, but I have commented the original lines below
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#define BASE 65521 /* largest prime smaller than 65536 */ #define BASE 65521 /* largest prime smaller than 65536 */
...@@ -111,7 +111,7 @@ unsigned long update_adler32(unsigned long adler, ...@@ -111,7 +111,7 @@ unsigned long update_adler32(unsigned long adler,
* This would then be (2 * BASE) - 2, which * This would then be (2 * BASE) - 2, which
* will still only do one subtract. On Intel * will still only do one subtract. On Intel
* this is much better to do this way and * this is much better to do this way and
* avoid the divide. Have not -pg'd on * avoid the divide. Have not -pg'd on
* sparc. * sparc.
*/ */
if (s2 >= BASE) { if (s2 >= BASE) {
...@@ -135,7 +135,7 @@ __u32 sctp_start_cksum(__u8 *ptr, __u16 count) ...@@ -135,7 +135,7 @@ __u32 sctp_start_cksum(__u8 *ptr, __u16 count)
__u32 zero = 0L; __u32 zero = 0L;
/* Calculate the CRC up to the checksum field. */ /* Calculate the CRC up to the checksum field. */
adler = update_adler32(adler, ptr, adler = update_adler32(adler, ptr,
sizeof(struct sctphdr) - sizeof(__u32)); sizeof(struct sctphdr) - sizeof(__u32));
/* Skip over the checksum field. */ /* Skip over the checksum field. */
adler = update_adler32(adler, (unsigned char *) &zero, adler = update_adler32(adler, (unsigned char *) &zero,
...@@ -156,6 +156,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler) ...@@ -156,6 +156,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
return adler; return adler;
} }
__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 count, __u32 adler)
{
/* Its not worth it to try harder. Adler32 is obsolescent. */
adler = update_adler32(adler, from, count);
memcpy(to, from, count);
return adler;
}
__u32 sctp_end_cksum(__u32 adler) __u32 sctp_end_cksum(__u32 adler)
{ {
return adler; return adler;
......
...@@ -170,6 +170,23 @@ __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) ...@@ -170,6 +170,23 @@ __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
return crc32; return crc32;
} }
__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 length, __u32 crc32)
{
__u32 i;
__u32 *_to = (__u32 *)to;
__u32 *_from = (__u32 *)from;
for (i = 0; i < (length/4); i++) {
_to[i] = _from[i];
CRC32C(crc32, from[i*4]);
CRC32C(crc32, from[i*4+1]);
CRC32C(crc32, from[i*4+2]);
CRC32C(crc32, from[i*4+3]);
}
return crc32;
}
__u32 sctp_end_cksum(__u32 crc32) __u32 sctp_end_cksum(__u32 crc32)
{ {
__u32 result; __u32 result;
......
...@@ -166,11 +166,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt, ...@@ -166,11 +166,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
/* If sending DATA and haven't aleady bundled a SACK, try to /* If sending DATA and haven't aleady bundled a SACK, try to
* bundle one in to the packet. * bundle one in to the packet.
*/ */
if (sctp_chunk_is_data(chunk) && !pkt->has_sack && if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
!pkt->has_cookie_echo) { !pkt->has_cookie_echo) {
struct sctp_association *asoc; struct sctp_association *asoc;
asoc = pkt->transport->asoc; asoc = pkt->transport->asoc;
if (asoc->a_rwnd > asoc->rwnd) { if (asoc->a_rwnd > asoc->rwnd) {
struct sctp_chunk *sack; struct sctp_chunk *sack;
asoc->a_rwnd = asoc->rwnd; asoc->a_rwnd = asoc->rwnd;
...@@ -205,7 +205,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -205,7 +205,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
if (retval != SCTP_XMIT_OK) if (retval != SCTP_XMIT_OK)
goto finish; goto finish;
pmtu = ((packet->transport->asoc) ? pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) : (packet->transport->asoc->pmtu) :
(packet->transport->pmtu)); (packet->transport->pmtu));
...@@ -259,7 +259,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -259,7 +259,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
goto finish; goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
packet->has_cookie_echo = 1; packet->has_cookie_echo = 1;
else if (SCTP_CID_SACK == chunk->chunk_hdr->type) else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
packet->has_sack = 1; packet->has_sack = 1;
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
...@@ -276,8 +276,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -276,8 +276,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
*/ */
int sctp_packet_transmit(struct sctp_packet *packet) int sctp_packet_transmit(struct sctp_packet *packet)
{ {
struct sctp_transport *transport = packet->transport; struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = transport->asoc; struct sctp_association *asoc = tp->asoc;
struct sctphdr *sh; struct sctphdr *sh;
__u32 crc32; __u32 crc32;
struct sk_buff *nskb; struct sk_buff *nskb;
...@@ -311,6 +311,32 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -311,6 +311,32 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
skb_set_owner_w(nskb, sk); skb_set_owner_w(nskb, sk);
/* Build the SCTP header. */
sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port);
/* From 6.8 Adler-32 Checksum Calculation:
* After the packet is constructed (containing the SCTP common
* header and one or more control or DATA chunks), the
* transmitter shall:
*
* 1) Fill in the proper Verification Tag in the SCTP common
* header and initialize the checksum field to 0's.
*/
sh->vtag = htonl(packet->vtag);
sh->checksum = 0;
/* 2) Calculate the Adler-32 checksum of the whole packet,
* including the SCTP common header and all the
* chunks.
*
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
/** /**
* 6.10 Bundling * 6.10 Bundling
* *
...@@ -344,16 +370,20 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -344,16 +370,20 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* for a given destination transport address. * for a given destination transport address.
*/ */
if ((1 == chunk->num_times_sent) && if ((1 == chunk->num_times_sent) &&
(!transport->rto_pending)) { (!tp->rto_pending)) {
chunk->rtt_in_progress = 1; chunk->rtt_in_progress = 1;
transport->rto_pending = 1; tp->rto_pending = 1;
} }
has_data = 1; has_data = 1;
} }
memcpy(skb_put(nskb, chunk->skb->len),
chunk->skb->data, chunk->skb->len);
padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len;
memset(skb_put(nskb, padding), 0, padding); if (padding)
memset(skb_put(chunk->skb, padding), 0, padding);
crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len),
chunk->skb->data,
chunk->skb->len, crc32);
SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, "
"%s %d\n", "%s %d\n",
"*** Chunk", chunk, "*** Chunk", chunk,
...@@ -376,30 +406,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -376,30 +406,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
} }
/* Build the SCTP header. */ /* Perform final transformation on checksum. */
sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port);
/* From 6.8 Adler-32 Checksum Calculation:
* After the packet is constructed (containing the SCTP common
* header and one or more control or DATA chunks), the
* transmitter shall:
*
* 1) Fill in the proper Verification Tag in the SCTP common
* header and initialize the checksum field to 0's.
*/
sh->vtag = htonl(packet->vtag);
sh->checksum = 0;
/* 2) Calculate the Adler-32 checksum of the whole packet,
* including the SCTP common header and all the
* chunks.
*
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = sctp_start_cksum((__u8 *)sh, nskb->len);
crc32 = sctp_end_cksum(crc32); crc32 = sctp_end_cksum(crc32);
/* 3) Put the resultant value into the checksum field in the /* 3) Put the resultant value into the checksum field in the
...@@ -431,18 +438,18 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -431,18 +438,18 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
/* Dump that on IP! */ /* Dump that on IP! */
if (asoc && asoc->peer.last_sent_to != transport) { if (asoc && asoc->peer.last_sent_to != tp) {
/* Considering the multiple CPU scenario, this is a /* Considering the multiple CPU scenario, this is a
* "correcter" place for last_sent_to. --xguo * "correcter" place for last_sent_to. --xguo
*/ */
asoc->peer.last_sent_to = transport; asoc->peer.last_sent_to = tp;
} }
if (has_data) { if (has_data) {
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
transport->last_time_used = jiffies; tp->last_time_used = jiffies;
/* Restart the AUTOCLOSE timer when sending data. */ /* Restart the AUTOCLOSE timer when sending data. */
if ((SCTP_STATE_ESTABLISHED == asoc->state) && if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
...@@ -455,21 +462,21 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -455,21 +462,21 @@ int sctp_packet_transmit(struct sctp_packet *packet)
} }
} }
dst = transport->dst; dst = tp->dst;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */ /* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if (!dst || (dst->obsolete > 1)) { if (!dst || (dst->obsolete > 1)) {
dst_release(dst); dst_release(dst);
sctp_transport_route(transport, NULL, sctp_sk(sk)); sctp_transport_route(tp, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
} }
nskb->dst = dst_clone(transport->dst); nskb->dst = dst_clone(tp->dst);
if (!nskb->dst) if (!nskb->dst)
goto no_route; goto no_route;
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
nskb->len); nskb->len);
(*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok); (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
out: out:
packet->size = SCTP_IP_OVERHEAD; packet->size = SCTP_IP_OVERHEAD;
return err; return err;
...@@ -596,7 +603,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -596,7 +603,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if any previously transmitted data on the connection remains * if any previously transmitted data on the connection remains
* unacknowledged. * unacknowledged.
*/ */
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) {
unsigned len = datasize + q->out_qlen; unsigned len = datasize + q->out_qlen;
......
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