diff options
Diffstat (limited to 'net/sctp/sm_sideeffect.c')
-rw-r--r-- | net/sctp/sm_sideeffect.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 23a9f1a95b7d..9732c797e8ed 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, | |||
190 | * unacknowledged DATA chunk. ... | 190 | * unacknowledged DATA chunk. ... |
191 | */ | 191 | */ |
192 | if (!asoc->peer.sack_needed) { | 192 | if (!asoc->peer.sack_needed) { |
193 | /* We will need a SACK for the next packet. */ | 193 | asoc->peer.sack_cnt++; |
194 | asoc->peer.sack_needed = 1; | ||
195 | 194 | ||
196 | /* Set the SACK delay timeout based on the | 195 | /* Set the SACK delay timeout based on the |
197 | * SACK delay for the last transport | 196 | * SACK delay for the last transport |
198 | * data was received from, or the default | 197 | * data was received from, or the default |
199 | * for the association. | 198 | * for the association. |
200 | */ | 199 | */ |
201 | if (trans) | 200 | if (trans) { |
201 | /* We will need a SACK for the next packet. */ | ||
202 | if (asoc->peer.sack_cnt >= trans->sackfreq - 1) | ||
203 | asoc->peer.sack_needed = 1; | ||
204 | |||
202 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = | 205 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = |
203 | trans->sackdelay; | 206 | trans->sackdelay; |
204 | else | 207 | } else { |
208 | /* We will need a SACK for the next packet. */ | ||
209 | if (asoc->peer.sack_cnt >= asoc->sackfreq - 1) | ||
210 | asoc->peer.sack_needed = 1; | ||
211 | |||
205 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = | 212 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = |
206 | asoc->sackdelay; | 213 | asoc->sackdelay; |
214 | } | ||
207 | 215 | ||
208 | /* Restart the SACK timer. */ | 216 | /* Restart the SACK timer. */ |
209 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, | 217 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, |
@@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, | |||
216 | goto nomem; | 224 | goto nomem; |
217 | 225 | ||
218 | asoc->peer.sack_needed = 0; | 226 | asoc->peer.sack_needed = 0; |
227 | asoc->peer.sack_cnt = 0; | ||
219 | 228 | ||
220 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack)); | 229 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack)); |
221 | 230 | ||
@@ -655,7 +664,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, | |||
655 | struct sctp_association *asoc, | 664 | struct sctp_association *asoc, |
656 | struct sctp_sackhdr *sackh) | 665 | struct sctp_sackhdr *sackh) |
657 | { | 666 | { |
658 | int err; | 667 | int err = 0; |
659 | 668 | ||
660 | if (sctp_outq_sack(&asoc->outqueue, sackh)) { | 669 | if (sctp_outq_sack(&asoc->outqueue, sackh)) { |
661 | /* There are no more TSNs awaiting SACK. */ | 670 | /* There are no more TSNs awaiting SACK. */ |
@@ -663,11 +672,6 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, | |||
663 | SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), | 672 | SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), |
664 | asoc->state, asoc->ep, asoc, NULL, | 673 | asoc->state, asoc->ep, asoc, NULL, |
665 | GFP_ATOMIC); | 674 | GFP_ATOMIC); |
666 | } else { | ||
667 | /* Windows may have opened, so we need | ||
668 | * to check if we have DATA to transmit | ||
669 | */ | ||
670 | err = sctp_outq_flush(&asoc->outqueue, 0); | ||
671 | } | 675 | } |
672 | 676 | ||
673 | return err; | 677 | return err; |
@@ -1472,8 +1476,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1472 | break; | 1476 | break; |
1473 | 1477 | ||
1474 | case SCTP_CMD_DISCARD_PACKET: | 1478 | case SCTP_CMD_DISCARD_PACKET: |
1475 | /* We need to discard the whole packet. */ | 1479 | /* We need to discard the whole packet. |
1480 | * Uncork the queue since there might be | ||
1481 | * responses pending | ||
1482 | */ | ||
1476 | chunk->pdiscard = 1; | 1483 | chunk->pdiscard = 1; |
1484 | if (asoc) { | ||
1485 | sctp_outq_uncork(&asoc->outqueue); | ||
1486 | local_cork = 0; | ||
1487 | } | ||
1477 | break; | 1488 | break; |
1478 | 1489 | ||
1479 | case SCTP_CMD_RTO_PENDING: | 1490 | case SCTP_CMD_RTO_PENDING: |
@@ -1544,8 +1555,15 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1544 | } | 1555 | } |
1545 | 1556 | ||
1546 | out: | 1557 | out: |
1547 | if (local_cork) | 1558 | /* If this is in response to a received chunk, wait until |
1548 | sctp_outq_uncork(&asoc->outqueue); | 1559 | * we are done with the packet to open the queue so that we don't |
1560 | * send multiple packets in response to a single request. | ||
1561 | */ | ||
1562 | if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) { | ||
1563 | if (chunk->end_of_packet || chunk->singleton) | ||
1564 | sctp_outq_uncork(&asoc->outqueue); | ||
1565 | } else if (local_cork) | ||
1566 | sctp_outq_uncork(&asoc->outqueue); | ||
1549 | return error; | 1567 | return error; |
1550 | nomem: | 1568 | nomem: |
1551 | error = -ENOMEM; | 1569 | error = -ENOMEM; |