diff options
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r-- | net/sctp/outqueue.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 582585393d35..8081476ed313 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -382,17 +382,18 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, | |||
382 | } | 382 | } |
383 | 383 | ||
384 | static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, | 384 | static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, |
385 | struct sctp_sndrcvinfo *sinfo, | 385 | struct sctp_sndrcvinfo *sinfo, int msg_len) |
386 | struct list_head *queue, int msg_len) | ||
387 | { | 386 | { |
387 | struct sctp_outq *q = &asoc->outqueue; | ||
388 | struct sctp_chunk *chk, *temp; | 388 | struct sctp_chunk *chk, *temp; |
389 | 389 | ||
390 | list_for_each_entry_safe(chk, temp, queue, list) { | 390 | list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) { |
391 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || | 391 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || |
392 | chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) | 392 | chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) |
393 | continue; | 393 | continue; |
394 | 394 | ||
395 | list_del_init(&chk->list); | 395 | list_del_init(&chk->list); |
396 | q->out_qlen -= chk->skb->len; | ||
396 | asoc->sent_cnt_removable--; | 397 | asoc->sent_cnt_removable--; |
397 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; | 398 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; |
398 | 399 | ||
@@ -431,9 +432,7 @@ void sctp_prsctp_prune(struct sctp_association *asoc, | |||
431 | return; | 432 | return; |
432 | } | 433 | } |
433 | 434 | ||
434 | sctp_prsctp_prune_unsent(asoc, sinfo, | 435 | sctp_prsctp_prune_unsent(asoc, sinfo, msg_len); |
435 | &asoc->outqueue.out_chunk_list, | ||
436 | msg_len); | ||
437 | } | 436 | } |
438 | 437 | ||
439 | /* Mark all the eligible packets on a transport for retransmission. */ | 438 | /* Mark all the eligible packets on a transport for retransmission. */ |
@@ -507,8 +506,6 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
507 | transport->rto_pending = 0; | 506 | transport->rto_pending = 0; |
508 | } | 507 | } |
509 | 508 | ||
510 | chunk->resent = 1; | ||
511 | |||
512 | /* Move the chunk to the retransmit queue. The chunks | 509 | /* Move the chunk to the retransmit queue. The chunks |
513 | * on the retransmit queue are always kept in order. | 510 | * on the retransmit queue are always kept in order. |
514 | */ | 511 | */ |
@@ -917,22 +914,28 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
917 | case SCTP_CID_ECN_ECNE: | 914 | case SCTP_CID_ECN_ECNE: |
918 | case SCTP_CID_ASCONF: | 915 | case SCTP_CID_ASCONF: |
919 | case SCTP_CID_FWD_TSN: | 916 | case SCTP_CID_FWD_TSN: |
917 | case SCTP_CID_RECONF: | ||
920 | status = sctp_packet_transmit_chunk(packet, chunk, | 918 | status = sctp_packet_transmit_chunk(packet, chunk, |
921 | one_packet, gfp); | 919 | one_packet, gfp); |
922 | if (status != SCTP_XMIT_OK) { | 920 | if (status != SCTP_XMIT_OK) { |
923 | /* put the chunk back */ | 921 | /* put the chunk back */ |
924 | list_add(&chunk->list, &q->control_chunk_list); | 922 | list_add(&chunk->list, &q->control_chunk_list); |
925 | } else { | 923 | break; |
926 | asoc->stats.octrlchunks++; | ||
927 | /* PR-SCTP C5) If a FORWARD TSN is sent, the | ||
928 | * sender MUST assure that at least one T3-rtx | ||
929 | * timer is running. | ||
930 | */ | ||
931 | if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) { | ||
932 | sctp_transport_reset_t3_rtx(transport); | ||
933 | transport->last_time_sent = jiffies; | ||
934 | } | ||
935 | } | 924 | } |
925 | |||
926 | asoc->stats.octrlchunks++; | ||
927 | /* PR-SCTP C5) If a FORWARD TSN is sent, the | ||
928 | * sender MUST assure that at least one T3-rtx | ||
929 | * timer is running. | ||
930 | */ | ||
931 | if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) { | ||
932 | sctp_transport_reset_t3_rtx(transport); | ||
933 | transport->last_time_sent = jiffies; | ||
934 | } | ||
935 | |||
936 | if (chunk == asoc->strreset_chunk) | ||
937 | sctp_transport_reset_reconf_timer(transport); | ||
938 | |||
936 | break; | 939 | break; |
937 | 940 | ||
938 | default: | 941 | default: |
@@ -1018,11 +1021,12 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
1018 | 1021 | ||
1019 | /* Finally, transmit new packets. */ | 1022 | /* Finally, transmit new packets. */ |
1020 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { | 1023 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { |
1024 | __u32 sid = ntohs(chunk->subh.data_hdr->stream); | ||
1025 | |||
1021 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
1022 | * stream identifier. | 1027 | * stream identifier. |
1023 | */ | 1028 | */ |
1024 | if (chunk->sinfo.sinfo_stream >= | 1029 | if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { |
1025 | asoc->c.sinit_num_ostreams) { | ||
1026 | 1030 | ||
1027 | /* Mark as failed send. */ | 1031 | /* Mark as failed send. */ |
1028 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1032 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); |
@@ -1040,6 +1044,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
1040 | continue; | 1044 | continue; |
1041 | } | 1045 | } |
1042 | 1046 | ||
1047 | if (asoc->stream->out[sid].state == SCTP_STREAM_CLOSED) { | ||
1048 | sctp_outq_head_data(q, chunk); | ||
1049 | goto sctp_flush_out; | ||
1050 | } | ||
1051 | |||
1043 | /* If there is a specified transport, use it. | 1052 | /* If there is a specified transport, use it. |
1044 | * Otherwise, we want to use the active path. | 1053 | * Otherwise, we want to use the active path. |
1045 | */ | 1054 | */ |
@@ -1050,7 +1059,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
1050 | (new_transport->state == SCTP_PF))) | 1059 | (new_transport->state == SCTP_PF))) |
1051 | new_transport = asoc->peer.active_path; | 1060 | new_transport = asoc->peer.active_path; |
1052 | if (new_transport->state == SCTP_UNCONFIRMED) { | 1061 | if (new_transport->state == SCTP_UNCONFIRMED) { |
1053 | WARN_ONCE(1, "Atempt to send packet on unconfirmed path."); | 1062 | WARN_ONCE(1, "Attempt to send packet on unconfirmed path."); |
1054 | sctp_chunk_fail(chunk, 0); | 1063 | sctp_chunk_fail(chunk, 0); |
1055 | sctp_chunk_free(chunk); | 1064 | sctp_chunk_free(chunk); |
1056 | continue; | 1065 | continue; |
@@ -1439,7 +1448,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1439 | * instance). | 1448 | * instance). |
1440 | */ | 1449 | */ |
1441 | if (!tchunk->tsn_gap_acked && | 1450 | if (!tchunk->tsn_gap_acked && |
1442 | !tchunk->resent && | 1451 | !sctp_chunk_retransmitted(tchunk) && |
1443 | tchunk->rtt_in_progress) { | 1452 | tchunk->rtt_in_progress) { |
1444 | tchunk->rtt_in_progress = 0; | 1453 | tchunk->rtt_in_progress = 0; |
1445 | rtt = jiffies - tchunk->sent_at; | 1454 | rtt = jiffies - tchunk->sent_at; |
@@ -1643,7 +1652,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1643 | 1652 | ||
1644 | if (forward_progress) { | 1653 | if (forward_progress) { |
1645 | if (transport->dst) | 1654 | if (transport->dst) |
1646 | dst_confirm(transport->dst); | 1655 | sctp_transport_dst_confirm(transport); |
1647 | } | 1656 | } |
1648 | } | 1657 | } |
1649 | 1658 | ||