summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Grimm <jgrimm@touki.austin.ibm.com>2003-04-24 22:15:15 -0500
committerJon Grimm <jgrimm@touki.austin.ibm.com>2003-04-24 22:15:15 -0500
commita93aba9ba0ca6cf1e1fecdb36f4ffa83ee57dc82 (patch)
treeec278187a2c02a20b3b9bae098687609bc271a1b
parent96a4ef027fe86905fe5a7f4799be0ffb9492ec30 (diff)
[SCTP] Control chunk bundling.
Control chunks should be bundled (implementor's guide advises specifically of case were ERROR should be bundled with CE to avoid race condition. Patch introduces a outq_cork/outq_uncork to immediate transferral of control chunks and then release to the packet bundling code.
-rw-r--r--include/net/sctp/structs.h33
-rw-r--r--net/sctp/outqueue.c17
-rw-r--r--net/sctp/sm_sideeffect.c30
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/sctp/ulpevent.c8
5 files changed, 63 insertions, 29 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 6ab0aabd68ed..81f3b83c47cf 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -963,11 +963,14 @@ struct sctp_outq {
/* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes;
+ /* Corked? */
+ char cork;
+
/* Is this structure empty? */
- int empty;
+ char empty;
/* Are we kfree()able? */
- int malloced;
+ char malloced;
};
struct sctp_outq *sctp_outq_new(struct sctp_association *);
@@ -985,10 +988,16 @@ int sctp_outq_set_output_handlers(struct sctp_outq *,
sctp_outq_ohandler_t build,
sctp_outq_ohandler_force_t force);
void sctp_outq_restart(struct sctp_outq *);
+
void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
sctp_retransmit_reason_t);
void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
-
+int sctp_outq_uncork(struct sctp_outq *);
+/* Uncork and flush an outqueue. */
+static inline void sctp_outq_cork(struct sctp_outq *q)
+{
+ q->cork = 1;
+}
/* These bind address data fields common between endpoints and associations */
struct sctp_bind_addr {
@@ -1393,7 +1402,6 @@ struct sctp_association {
/* The largest timeout or RTO value to use in attempting an INIT */
__u16 max_init_timeo;
-
int timeouts[SCTP_NUM_TIMEOUT_TYPES];
struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];
@@ -1494,9 +1502,6 @@ struct sctp_association {
*/
struct sctp_ulpq ulpq;
- /* Need to send an ECNE Chunk? */
- int need_ecne;
-
/* Last TSN that caused an ECNE Chunk to be sent. */
__u32 last_ecne_tsn;
@@ -1509,9 +1514,6 @@ struct sctp_association {
/* Number of seconds of idle time before an association is closed. */
__u32 autoclose;
- /* Name for debugging output... */
- char *debug_name;
-
/* These are to support
* "SCTP Extensions for Dynamic Reconfiguration of IP Addresses
* and Enforcement of Flow and Message Limits"
@@ -1519,8 +1521,7 @@ struct sctp_association {
* or "ADDIP" for short.
*/
- /* Is the ADDIP extension enabled for this association? */
- int addip_enable;
+
/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
*
@@ -1605,8 +1606,14 @@ struct sctp_association {
*/
__u32 addip_serial;
+ /* Is the ADDIP extension enabled for this association? */
+ char addip_enable;
+
+ /* Need to send an ECNE Chunk? */
+ char need_ecne;
+
/* Is it a temporary association? */
- __u8 temp;
+ char temp;
};
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 7acc78bb407d..a43b02ba7bec 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -230,6 +230,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
q->outstanding_bytes = 0;
q->empty = 1;
+ q->cork = 0;
q->malloced = 0;
q->out_qlen = 0;
@@ -365,7 +366,8 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
if (error < 0)
return error;
- error = sctp_outq_flush(q, 0);
+ if (!q->cork)
+ error = sctp_outq_flush(q, 0);
return error;
}
@@ -816,8 +818,19 @@ err:
return NULL;
}
+/* Cork the outqueue so queued chunks are really queued. */
+int sctp_outq_uncork(struct sctp_outq *q)
+{
+ int error = 0;
+ if (q->cork) {
+ q->cork = 0;
+ error = sctp_outq_flush(q, 0);
+ }
+ return error;
+}
+
/*
- * sctp_outq_flush - Try to flush an outqueue.
+ * Try to flush an outqueue.
*
* Description: Send everything in q which we legally can, subject to
* congestion limitations.
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 30e9e8bc501f..5be6fc92ee6a 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -844,6 +844,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
unsigned long timeout;
struct sctp_transport *t;
sctp_sackhdr_t sackh;
+ int local_cork = 0;
if (SCTP_EVENT_T_TIMEOUT != event_type)
chunk = (struct sctp_chunk *) event_arg;
@@ -863,6 +864,10 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_NEW_ASOC:
/* Register a new association. */
+ if (local_cork) {
+ sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
+ }
asoc = cmd->obj.ptr;
/* Register with the endpoint. */
sctp_endpoint_add_asoc(ep, asoc);
@@ -877,7 +882,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_outq_teardown(&asoc->outqueue);
break;
- case SCTP_CMD_DELETE_TCB:
+ case SCTP_CMD_DELETE_TCB:
+ if (local_cork) {
+ sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
+ }
/* Delete the current association. */
sctp_cmd_delete_tcb(commands, asoc);
asoc = NULL;
@@ -981,9 +990,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_CMD_REPLY:
+ /* If an caller has not already corked, do cork. */
+ if (!asoc->outqueue.cork) {
+ sctp_outq_cork(&asoc->outqueue);
+ local_cork = 1;
+ }
/* Send a chunk to our peer. */
- error = sctp_outq_tail(&asoc->outqueue,
- cmd->obj.ptr);
+ error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
break;
case SCTP_CMD_SEND_PKT:
@@ -1001,7 +1014,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_TRANSMIT:
/* Kick start transmission. */
- error = sctp_outq_flush(&asoc->outqueue, 0);
+ error = sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
break;
case SCTP_CMD_ECN_CE:
@@ -1172,13 +1186,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
};
if (error)
- return error;
+ break;
}
+out:
+ if (local_cork)
+ sctp_outq_uncork(&asoc->outqueue);
return error;
-
nomem:
error = -ENOMEM;
- return error;
+ goto out;
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 53692a1b2118..b183f1773378 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -891,8 +891,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
if (asoc) {
- SCTP_DEBUG_PRINTK("Just looked up association: "
- "%s. \n", asoc->debug_name);
+ SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);
/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED
* socket that has an association in CLOSED state. This can
@@ -1092,6 +1091,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_primitive_SEND(asoc, chunk);
SCTP_DEBUG_PRINTK("We sent primitively.\n");
}
+
sctp_datamsg_free(datamsg);
err = msg_len;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 4fd424e383de..936cebb87519 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -328,7 +328,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
ch = (sctp_errhdr_t *)(chunk->skb->data);
cause = ch->cause;
- elen = ntohs(ch->length) - sizeof(sctp_errhdr_t);
+ elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);
/* Pull off the ERROR header. */
skb_pull(chunk->skb, sizeof(sctp_errhdr_t));
@@ -336,10 +336,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
/* Copy the skb to a new skb with room for us to prepend
* notification with.
*/
- skb = skb_copy_expand(chunk->skb,
- sizeof(struct sctp_remote_error), /* headroom */
- 0, /* tailroom */
- gfp);
+ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),
+ 0, gfp);
/* Pull off the rest of the cause TLV from the chunk. */
skb_pull(chunk->skb, elen);