summaryrefslogtreecommitdiff
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2008-06-19 16:08:18 -0700
committerDavid S. Miller <davem@davemloft.net>2008-06-19 16:08:18 -0700
commit2e3216cd54b142ba605e87522e15f42e0c4e3996 (patch)
treeda4d7a6ff4811d9f38b81c70f08b221b575e1254 /net/sctp/outqueue.c
parent7115e632f90952454ab6426e0d2151327162a30f (diff)
sctp: Follow security requirement of responding with 1 packet
RFC 4960, Section 11.4. Protection of Non-SCTP-Capable Hosts When an SCTP stack receives a packet containing multiple control or DATA chunks and the processing of the packet requires the sending of multiple chunks in response, the sender of the response chunk(s) MUST NOT send more than one packet. If bundling is supported, multiple response chunks that fit into a single packet MAY be bundled together into one single response packet. If bundling is not supported, then the sender MUST NOT send more than one response chunk and MUST discard all other responses. Note that this rule does NOT apply to a SACK chunk, since a SACK chunk is, in itself, a response to DATA and a SACK does not require a response of more DATA. We implement this by not servicing our outqueue until we reach the end of the packet. This enables maximum bundling. We also identify 'response' chunks and make sure that we only send 1 packet when sending such chunks. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index ace6770e9048..70ead8dc3485 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -702,6 +702,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
return error;
}
+
/*
* Try to flush an outqueue.
*
@@ -725,6 +726,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
sctp_xmit_t status;
int error = 0;
int start_timer = 0;
+ int one_packet = 0;
/* These transports have chunks to send. */
struct list_head transport_list;
@@ -830,20 +832,33 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
if (sctp_test_T_bit(chunk)) {
packet->vtag = asoc->c.my_vtag;
}
- case SCTP_CID_SACK:
- case SCTP_CID_HEARTBEAT:
+ /* The following chunks are "response" chunks, i.e.
+ * they are generated in response to something we
+ * received. If we are sending these, then we can
+ * send only 1 packet containing these chunks.
+ */
case SCTP_CID_HEARTBEAT_ACK:
- case SCTP_CID_SHUTDOWN:
case SCTP_CID_SHUTDOWN_ACK:
- case SCTP_CID_ERROR:
- case SCTP_CID_COOKIE_ECHO:
case SCTP_CID_COOKIE_ACK:
- case SCTP_CID_ECN_ECNE:
+ case SCTP_CID_COOKIE_ECHO:
+ case SCTP_CID_ERROR:
case SCTP_CID_ECN_CWR:
- case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK:
+ one_packet = 1;
+ /* Fall throught */
+
+ case SCTP_CID_SACK:
+ case SCTP_CID_HEARTBEAT:
+ case SCTP_CID_SHUTDOWN:
+ case SCTP_CID_ECN_ECNE:
+ case SCTP_CID_ASCONF:
case SCTP_CID_FWD_TSN:
- sctp_packet_transmit_chunk(packet, chunk);
+ status = sctp_packet_transmit_chunk(packet, chunk,
+ one_packet);
+ if (status != SCTP_XMIT_OK) {
+ /* put the chunk back */
+ list_add(&chunk->list, &q->control_chunk_list);
+ }
break;
default:
@@ -974,7 +989,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
atomic_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */
- status = sctp_packet_transmit_chunk(packet, chunk);
+ status = sctp_packet_transmit_chunk(packet, chunk, 0);
switch (status) {
case SCTP_XMIT_PMTU_FULL:
@@ -1239,7 +1254,6 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
* Make sure the empty queue handler will get run later.
*/
q->empty = (list_empty(&q->out_chunk_list) &&
- list_empty(&q->control_chunk_list) &&
list_empty(&q->retransmit));
if (!q->empty)
goto finish;