Commit e7ee91fd authored by Jon Grimm's avatar Jon Grimm

[SCTP] Receiver SWS prevention.

Still had a bit of receiver SWS as the 'SACK every other packet' & 
'delayed SACK timer' advertise the true buffer size.   So while the 
'rwnd update' code wasn't sending SACKS, small reads in 
combination with many incoming packets would still generate small 
windows advertisements.  Don't advertise a larger a_rwnd until a 
segment opens up.  Also, fix bug over in the Nagle that was preventing 
most Nagling from occuring.
parent ab52120b
......@@ -181,7 +181,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
else
asoc->rwnd = sk->rcvbuf;
asoc->a_rwnd = 0;
asoc->a_rwnd = asoc->rwnd;
asoc->rwnd_over = 0;
......@@ -994,6 +994,24 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
__FUNCTION__, asoc, asoc->pmtu, asoc->frag_point);
}
/* Should we send a SACK to update our peer? */
static inline int sctp_peer_needs_update(struct sctp_association *asoc)
{
switch (asoc->state) {
case SCTP_STATE_ESTABLISHED:
case SCTP_STATE_SHUTDOWN_PENDING:
case SCTP_STATE_SHUTDOWN_RECEIVED:
if ((asoc->rwnd > asoc->a_rwnd) &&
((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu)))
return 1;
break;
default:
break;
}
return 0;
}
/* Increase asoc's rwnd by len and send any window update SACK if needed. */
void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
{
......@@ -1020,10 +1038,8 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
* The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122.
*/
if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
(asoc->rwnd > asoc->a_rwnd) &&
((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) {
if (sctp_peer_needs_update(asoc)) {
asoc->a_rwnd = asoc->rwnd;
SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u\n", __FUNCTION__,
asoc, asoc->rwnd, asoc->a_rwnd);
......@@ -1031,9 +1047,6 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
if (!sack)
return;
/* Update the last advertised rwnd value. */
asoc->a_rwnd = asoc->rwnd;
asoc->peer.sack_needed = 0;
sctp_outq_tail(&asoc->outqueue, sack);
......@@ -1057,7 +1070,8 @@ void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
asoc->rwnd = 0;
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
__FUNCTION__, asoc, len, asoc->rwnd, asoc->rwnd_over);
__FUNCTION__, asoc, len, asoc->rwnd,
asoc->rwnd_over);
}
/* Build the bind address list for the association based on info from the
......
......@@ -554,13 +554,14 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if any previously transmitted data on the connection remains
* unacknowledged.
*/
if (!sp->nodelay && q->outstanding_bytes) {
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) {
unsigned len = datasize + q->out_qlen;
/* Check whether this chunk and all the rest of pending
* data will fit or delay in hopes of bundling a full
* sized packet.
*/
if (len < asoc->pmtu - SCTP_IP_OVERHEAD) {
retval = SCTP_XMIT_NAGLE_DELAY;
goto finish;
......
......@@ -598,7 +598,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Initialize the SACK header. */
sack.cum_tsn_ack = htonl(ctsn);
sack.a_rwnd = htonl(asoc->rwnd);
sack.a_rwnd = htonl(asoc->a_rwnd);
sack.num_gap_ack_blocks = htons(num_gabs);
sack.num_dup_tsns = htons(num_dup_tsns);
......
......@@ -716,13 +716,12 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc->peer.sack_needed = 1;
goto out;
} else {
if (asoc->a_rwnd > asoc->rwnd)
asoc->a_rwnd = asoc->rwnd;
sack = sctp_make_sack(asoc);
if (!sack)
goto nomem;
/* Update the last advertised rwnd value. */
asoc->a_rwnd = asoc->rwnd;
asoc->peer.sack_needed = 0;
error = sctp_outq_tail(&asoc->outqueue, sack);
......
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