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)
extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
extern __u32 sctp_end_cksum(__u32 cksum);
extern __u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum);
/*
* sctp/input.c
......
......@@ -2,43 +2,43 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
*
*
* 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
* Adler-32 algorithm as specified by RFC 2960.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* Adler-32 algorithm as specified by RFC 2960.
*
* The SCTP reference implementation 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, or (at your option)
* 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
* ************************
* 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 GNU CC; see the file COPYING. If not, write to
* 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
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Written or modified by:
* Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
......@@ -65,7 +65,7 @@
* tad, but I have commented the original lines below
*/
#include <linux/types.h>
#include <linux/types.h>
#include <net/sctp/sctp.h>
#define BASE 65521 /* largest prime smaller than 65536 */
......@@ -111,7 +111,7 @@ unsigned long update_adler32(unsigned long adler,
* This would then be (2 * BASE) - 2, which
* will still only do one subtract. On Intel
* 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.
*/
if (s2 >= BASE) {
......@@ -135,7 +135,7 @@ __u32 sctp_start_cksum(__u8 *ptr, __u16 count)
__u32 zero = 0L;
/* Calculate the CRC up to the checksum field. */
adler = update_adler32(adler, ptr,
adler = update_adler32(adler, ptr,
sizeof(struct sctphdr) - sizeof(__u32));
/* Skip over the checksum field. */
adler = update_adler32(adler, (unsigned char *) &zero,
......@@ -156,6 +156,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 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)
{
return adler;
......
......@@ -170,6 +170,23 @@ __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 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 result;
......
......@@ -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
* 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) {
struct sctp_association *asoc;
asoc = pkt->transport->asoc;
if (asoc->a_rwnd > asoc->rwnd) {
struct sctp_chunk *sack;
asoc->a_rwnd = asoc->rwnd;
......@@ -205,7 +205,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
if (retval != SCTP_XMIT_OK)
goto finish;
pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) :
(packet->transport->pmtu));
......@@ -259,7 +259,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
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;
/* It is OK to send this chunk. */
......@@ -276,8 +276,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
*/
int sctp_packet_transmit(struct sctp_packet *packet)
{
struct sctp_transport *transport = packet->transport;
struct sctp_association *asoc = transport->asoc;
struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = tp->asoc;
struct sctphdr *sh;
__u32 crc32;
struct sk_buff *nskb;
......@@ -311,6 +311,32 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/
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
*
......@@ -344,16 +370,20 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* for a given destination transport address.
*/
if ((1 == chunk->num_times_sent) &&
(!transport->rto_pending)) {
(!tp->rto_pending)) {
chunk->rtt_in_progress = 1;
transport->rto_pending = 1;
tp->rto_pending = 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;
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, "
"%s %d\n",
"*** Chunk", chunk,
......@@ -376,30 +406,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
sctp_free_chunk(chunk);
}
/* 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, nskb->len);
/* Perform final transformation on checksum. */
crc32 = sctp_end_cksum(crc32);
/* 3) Put the resultant value into the checksum field in the
......@@ -431,18 +438,18 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/
/* 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
* "correcter" place for last_sent_to. --xguo
*/
asoc->peer.last_sent_to = transport;
asoc->peer.last_sent_to = tp;
}
if (has_data) {
struct timer_list *timer;
unsigned long timeout;
transport->last_time_used = jiffies;
tp->last_time_used = jiffies;
/* Restart the AUTOCLOSE timer when sending data. */
if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
......@@ -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. */
if (!dst || (dst->obsolete > 1)) {
dst_release(dst);
sctp_transport_route(transport, NULL, sctp_sk(sk));
sctp_transport_route(tp, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc);
}
nskb->dst = dst_clone(transport->dst);
nskb->dst = dst_clone(tp->dst);
if (!nskb->dst)
goto no_route;
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
nskb->len);
(*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok);
(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
out:
packet->size = SCTP_IP_OVERHEAD;
return err;
......@@ -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
* 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) {
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