diff options
| author | Jon Grimm <jgrimm@touki.austin.ibm.com> | 2003-04-24 22:15:15 -0500 |
|---|---|---|
| committer | Jon Grimm <jgrimm@touki.austin.ibm.com> | 2003-04-24 22:15:15 -0500 |
| commit | a93aba9ba0ca6cf1e1fecdb36f4ffa83ee57dc82 (patch) | |
| tree | ec278187a2c02a20b3b9bae098687609bc271a1b | |
| parent | 96a4ef027fe86905fe5a7f4799be0ffb9492ec30 (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.h | 33 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 17 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 30 | ||||
| -rw-r--r-- | net/sctp/socket.c | 4 | ||||
| -rw-r--r-- | net/sctp/ulpevent.c | 8 |
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); |
