patch-2.4.26 linux-2.4.26/net/sctp/output.c
Next file: linux-2.4.26/net/sctp/outqueue.c
Previous file: linux-2.4.26/net/sctp/objcnt.c
Back to the patch index
Back to the overall index
- Lines: 262
- Date:
2004-04-14 06:05:41.000000000 -0700
- Orig file:
linux-2.4.25/net/sctp/output.c
- Orig date:
2003-11-28 10:26:21.000000000 -0800
diff -urN linux-2.4.25/net/sctp/output.c linux-2.4.26/net/sctp/output.c
@@ -1,7 +1,7 @@
/* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
@@ -97,6 +97,7 @@
packet->source_port = sport;
packet->destination_port = dport;
skb_queue_head_init(&packet->chunks);
+ packet->size = SCTP_IP_OVERHEAD;
packet->vtag = 0;
packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL;
@@ -114,7 +115,7 @@
struct sctp_chunk *chunk;
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
- sctp_free_chunk(chunk);
+ sctp_chunk_free(chunk);
if (packet->malloced)
kfree(packet);
@@ -138,7 +139,7 @@
if (!packet->has_cookie_echo) {
error = sctp_packet_transmit(packet);
if (error < 0)
- chunk->skb->sk->err = -error;
+ chunk->skb->sk->sk_err = -error;
/* If we have an empty packet, then we can NOT ever
* return PMTU_FULL.
@@ -219,22 +220,16 @@
/* Both control chunks and data chunks with TSNs are
* non-fragmentable.
*/
- int fragmentable = sctp_chunk_is_data(chunk) &&
- (!chunk->has_tsn);
- if (packet_empty) {
- if (fragmentable) {
- retval = SCTP_XMIT_MUST_FRAG;
- goto finish;
- } else {
- /* The packet is too big but we can
- * not fragment it--we have to just
- * transmit and rely on IP
- * fragmentation.
- */
- packet->ipfragok = 1;
- goto append;
- }
- } else { /* !packet_empty */
+ if (packet_empty || !sctp_chunk_is_data(chunk)) {
+ /* We no longer do re-fragmentation.
+ * Just fragment at the IP layer, if we
+ * actually hit this condition
+ */
+
+ packet->ipfragok = 1;
+ goto append;
+
+ } else {
retval = SCTP_XMIT_PMTU_FULL;
goto finish;
}
@@ -288,20 +283,18 @@
__u8 has_data = 0;
struct dst_entry *dst;
- /* Do NOT generate a chunkless packet... */
- if (skb_queue_empty(&packet->chunks))
+ /* Do NOT generate a chunkless packet. */
+ chunk = (struct sctp_chunk *)skb_peek(&packet->chunks);
+ if (unlikely(!chunk))
return err;
/* Set up convenience variables... */
- chunk = (struct sctp_chunk *) (packet->chunks.next);
sk = chunk->skb->sk;
/* Allocate the new skb. */
nskb = dev_alloc_skb(packet->size);
- if (!nskb) {
- err = -ENOMEM;
- goto out;
- }
+ if (!nskb)
+ goto nomem;
/* Make sure the outbound skb has enough header room reserved. */
skb_reserve(nskb, SCTP_IP_OVERHEAD);
@@ -327,7 +320,6 @@
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.
@@ -358,10 +350,11 @@
*/
SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
- chunk->num_times_sent++;
- chunk->sent_at = jiffies;
if (sctp_chunk_is_data(chunk)) {
- sctp_chunk_assign_tsn(chunk);
+
+ if (!chunk->has_tsn) {
+ sctp_chunk_assign_ssn(chunk);
+ sctp_chunk_assign_tsn(chunk);
/* 6.3.1 C4) When data is in flight and when allowed
* by rule C5, a new RTT measurement MUST be made each
@@ -369,23 +362,27 @@
* SHOULD be made no more than once per round-trip
* for a given destination transport address.
*/
- if ((1 == chunk->num_times_sent) &&
- (!tp->rto_pending)) {
- chunk->rtt_in_progress = 1;
- tp->rto_pending = 1;
- }
+
+ if (!tp->rto_pending) {
+ chunk->rtt_in_progress = 1;
+ tp->rto_pending = 1;
+ }
+ } else
+ chunk->resent = 1;
+
+ chunk->sent_at = jiffies;
has_data = 1;
}
+
padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len;
if (padding)
- memset(skb_put(chunk->skb, padding), 0, 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->data,
chunk->skb->len, crc32);
-
- SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, "
- "%s %d\n",
+
+ SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
"*** Chunk", chunk,
sctp_cname(SCTP_ST_CHUNK(
chunk->chunk_hdr->type)),
@@ -394,7 +391,6 @@
ntohl(chunk->subh.data_hdr->tsn) : 0,
"length", ntohs(chunk->chunk_hdr->length),
"chunk->skb->len", chunk->skb->len,
- "num_times_sent", chunk->num_times_sent,
"rtt_in_progress", chunk->rtt_in_progress);
/*
@@ -403,7 +399,7 @@
* acknowledged or have failed.
*/
if (!sctp_chunk_is_data(chunk))
- sctp_free_chunk(chunk);
+ sctp_chunk_free(chunk);
}
/* Perform final transformation on checksum. */
@@ -420,21 +416,17 @@
* data sender to indicate that the end-points of the
* transport protocol are ECN-capable."
*
- * If ECN capable && negotiated && it makes sense for
- * this packet to support it (e.g. post ECN negotiation)
- * then lets set the ECT bit
+ * Now setting the ECT bit all the time, as it should not cause
+ * any problems protocol-wise even if our peer ignores it.
*
- * FIXME: Need to do something else for IPv6
+ * Note: The works for IPv6 layer checks this bit too later
+ * in transmission. See IP6_ECN_flow_xmit().
*/
- if (packet->ecn_capable) {
- INET_ECN_xmit(nskb->sk);
- } else {
- INET_ECN_dontxmit(nskb->sk);
- }
+ INET_ECN_xmit(nskb->sk);
/* Set up the IP options. */
/* BUG: not implemented
- * For v4 this all lives somewhere in sk->opt...
+ * For v4 this all lives somewhere in sk->sk_opt...
*/
/* Dump that on IP! */
@@ -452,8 +444,7 @@
tp->last_time_used = jiffies;
/* Restart the AUTOCLOSE timer when sending data. */
- if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
- (asoc->autoclose)) {
+ if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
@@ -474,9 +465,11 @@
if (!nskb->dst)
goto no_route;
- SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
+ SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n",
nskb->len);
+
(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
+
out:
packet->size = SCTP_IP_OVERHEAD;
return err;
@@ -492,7 +485,20 @@
* required.
*/
/* err = -EHOSTUNREACH; */
+err:
+ /* Control chunks are unreliable so just drop them. DATA chunks
+ * will get resent or dropped later.
+ */
+
+ while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
+ if (!sctp_chunk_is_data(chunk))
+ sctp_chunk_free(chunk);
+ }
goto out;
+nomem:
+ err = -ENOMEM;
+ printk("%s alloc_skb failed.\n", __FUNCTION__);
+ goto err;
}
/********************************************************************
@@ -604,7 +610,7 @@
* unacknowledged.
*/
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
- q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) {
+ q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
unsigned len = datasize + q->out_qlen;
/* Check whether this chunk and all the rest of pending
@@ -630,6 +636,8 @@
rwnd = 0;
asoc->peer.rwnd = rwnd;
+ /* Has been accepted for transmission. */
+ chunk->msg->can_expire = 0;
finish:
return retval;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)