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
......
......@@ -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;
......
......@@ -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;
......
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