Commit a93aba9b authored by Jon Grimm's avatar Jon Grimm

[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. 
parent 96a4ef02
......@@ -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;
};
......
......@@ -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 @@ struct sctp_chunk *sctp_fragment_chunk(struct sctp_chunk *chunk,
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.
......
......@@ -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;
}
......@@ -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;
......
......@@ -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);
......
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