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>
This commit is contained in:
Vlad Yasevich
2008-06-19 16:08:18 -07:00
committed by David S. Miller
parent 7115e632f9
commit 2e3216cd54
6 changed files with 54 additions and 33 deletions

View File

@ -664,7 +664,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc,
struct sctp_sackhdr *sackh)
{
int err;
int err = 0;
if (sctp_outq_sack(&asoc->outqueue, sackh)) {
/* There are no more TSNs awaiting SACK. */
@ -672,11 +672,6 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
asoc->state, asoc->ep, asoc, NULL,
GFP_ATOMIC);
} else {
/* Windows may have opened, so we need
* to check if we have DATA to transmit
*/
err = sctp_outq_flush(&asoc->outqueue, 0);
}
return err;
@ -1481,8 +1476,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
break;
case SCTP_CMD_DISCARD_PACKET:
/* We need to discard the whole packet. */
/* We need to discard the whole packet.
* Uncork the queue since there might be
* responses pending
*/
chunk->pdiscard = 1;
if (asoc) {
sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
}
break;
case SCTP_CMD_RTO_PENDING:
@ -1553,8 +1555,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
}
out:
if (local_cork)
sctp_outq_uncork(&asoc->outqueue);
/* If this is in response to a received chunk, wait until
* we are done with the packet to open the queue so that we don't
* send multiple packets in response to a single request.
*/
if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) {
if (chunk->end_of_packet || chunk->singleton)
sctp_outq_uncork(&asoc->outqueue);
} else if (local_cork)
sctp_outq_uncork(&asoc->outqueue);
return error;
nomem:
error = -ENOMEM;