diff options
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r-- | net/sctp/outqueue.c | 68 |
1 files changed, 28 insertions, 40 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index c0714469233c..59edfd25a19c 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -221,12 +221,12 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) | |||
221 | void sctp_outq_teardown(struct sctp_outq *q) | 221 | void sctp_outq_teardown(struct sctp_outq *q) |
222 | { | 222 | { |
223 | struct sctp_transport *transport; | 223 | struct sctp_transport *transport; |
224 | struct list_head *lchunk, *pos, *temp; | 224 | struct list_head *lchunk, *temp; |
225 | struct sctp_chunk *chunk, *tmp; | 225 | struct sctp_chunk *chunk, *tmp; |
226 | 226 | ||
227 | /* Throw away unacknowledged chunks. */ | 227 | /* Throw away unacknowledged chunks. */ |
228 | list_for_each(pos, &q->asoc->peer.transport_addr_list) { | 228 | list_for_each_entry(transport, &q->asoc->peer.transport_addr_list, |
229 | transport = list_entry(pos, struct sctp_transport, transports); | 229 | transports) { |
230 | while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { | 230 | while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { |
231 | chunk = list_entry(lchunk, struct sctp_chunk, | 231 | chunk = list_entry(lchunk, struct sctp_chunk, |
232 | transmitted_list); | 232 | transmitted_list); |
@@ -469,7 +469,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
469 | 469 | ||
470 | SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, " | 470 | SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, " |
471 | "cwnd: %d, ssthresh: %d, flight_size: %d, " | 471 | "cwnd: %d, ssthresh: %d, flight_size: %d, " |
472 | "pba: %d\n", __FUNCTION__, | 472 | "pba: %d\n", __func__, |
473 | transport, reason, | 473 | transport, reason, |
474 | transport->cwnd, transport->ssthresh, | 474 | transport->cwnd, transport->ssthresh, |
475 | transport->flight_size, | 475 | transport->flight_size, |
@@ -494,6 +494,8 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
494 | */ | 494 | */ |
495 | if (transport == transport->asoc->peer.retran_path) | 495 | if (transport == transport->asoc->peer.retran_path) |
496 | sctp_assoc_update_retran_path(transport->asoc); | 496 | sctp_assoc_update_retran_path(transport->asoc); |
497 | transport->asoc->rtx_data_chunks += | ||
498 | transport->asoc->unack_data; | ||
497 | break; | 499 | break; |
498 | case SCTP_RTXR_FAST_RTX: | 500 | case SCTP_RTXR_FAST_RTX: |
499 | SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); | 501 | SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); |
@@ -504,6 +506,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
504 | break; | 506 | break; |
505 | case SCTP_RTXR_T1_RTX: | 507 | case SCTP_RTXR_T1_RTX: |
506 | SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS); | 508 | SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS); |
509 | transport->asoc->init_retries++; | ||
507 | break; | 510 | break; |
508 | default: | 511 | default: |
509 | BUG(); | 512 | BUG(); |
@@ -535,7 +538,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
535 | int rtx_timeout, int *start_timer) | 538 | int rtx_timeout, int *start_timer) |
536 | { | 539 | { |
537 | struct list_head *lqueue; | 540 | struct list_head *lqueue; |
538 | struct list_head *lchunk, *lchunk1; | 541 | struct list_head *lchunk; |
539 | struct sctp_transport *transport = pkt->transport; | 542 | struct sctp_transport *transport = pkt->transport; |
540 | sctp_xmit_t status; | 543 | sctp_xmit_t status; |
541 | struct sctp_chunk *chunk, *chunk1; | 544 | struct sctp_chunk *chunk, *chunk1; |
@@ -646,9 +649,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
646 | * to be marked as ineligible for a subsequent fast retransmit. | 649 | * to be marked as ineligible for a subsequent fast retransmit. |
647 | */ | 650 | */ |
648 | if (rtx_timeout && !lchunk) { | 651 | if (rtx_timeout && !lchunk) { |
649 | list_for_each(lchunk1, lqueue) { | 652 | list_for_each_entry(chunk1, lqueue, transmitted_list) { |
650 | chunk1 = list_entry(lchunk1, struct sctp_chunk, | ||
651 | transmitted_list); | ||
652 | if (chunk1->fast_retransmit > 0) | 653 | if (chunk1->fast_retransmit > 0) |
653 | chunk1->fast_retransmit = -1; | 654 | chunk1->fast_retransmit = -1; |
654 | } | 655 | } |
@@ -1037,7 +1038,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc, | |||
1037 | static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, | 1038 | static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, |
1038 | struct sctp_association *asoc) | 1039 | struct sctp_association *asoc) |
1039 | { | 1040 | { |
1040 | struct list_head *ltransport, *lchunk; | ||
1041 | struct sctp_transport *transport; | 1041 | struct sctp_transport *transport; |
1042 | struct sctp_chunk *chunk; | 1042 | struct sctp_chunk *chunk; |
1043 | __u32 highest_new_tsn, tsn; | 1043 | __u32 highest_new_tsn, tsn; |
@@ -1045,12 +1045,9 @@ static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, | |||
1045 | 1045 | ||
1046 | highest_new_tsn = ntohl(sack->cum_tsn_ack); | 1046 | highest_new_tsn = ntohl(sack->cum_tsn_ack); |
1047 | 1047 | ||
1048 | list_for_each(ltransport, transport_list) { | 1048 | list_for_each_entry(transport, transport_list, transports) { |
1049 | transport = list_entry(ltransport, struct sctp_transport, | 1049 | list_for_each_entry(chunk, &transport->transmitted, |
1050 | transports); | 1050 | transmitted_list) { |
1051 | list_for_each(lchunk, &transport->transmitted) { | ||
1052 | chunk = list_entry(lchunk, struct sctp_chunk, | ||
1053 | transmitted_list); | ||
1054 | tsn = ntohl(chunk->subh.data_hdr->tsn); | 1051 | tsn = ntohl(chunk->subh.data_hdr->tsn); |
1055 | 1052 | ||
1056 | if (!chunk->tsn_gap_acked && | 1053 | if (!chunk->tsn_gap_acked && |
@@ -1073,7 +1070,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1073 | struct sctp_association *asoc = q->asoc; | 1070 | struct sctp_association *asoc = q->asoc; |
1074 | struct sctp_transport *transport; | 1071 | struct sctp_transport *transport; |
1075 | struct sctp_chunk *tchunk = NULL; | 1072 | struct sctp_chunk *tchunk = NULL; |
1076 | struct list_head *lchunk, *transport_list, *pos, *temp; | 1073 | struct list_head *lchunk, *transport_list, *temp; |
1077 | sctp_sack_variable_t *frags = sack->variable; | 1074 | sctp_sack_variable_t *frags = sack->variable; |
1078 | __u32 sack_ctsn, ctsn, tsn; | 1075 | __u32 sack_ctsn, ctsn, tsn; |
1079 | __u32 highest_tsn, highest_new_tsn; | 1076 | __u32 highest_tsn, highest_new_tsn; |
@@ -1099,9 +1096,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1099 | */ | 1096 | */ |
1100 | if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { | 1097 | if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { |
1101 | primary->cacc.changeover_active = 0; | 1098 | primary->cacc.changeover_active = 0; |
1102 | list_for_each(pos, transport_list) { | 1099 | list_for_each_entry(transport, transport_list, |
1103 | transport = list_entry(pos, struct sctp_transport, | 1100 | transports) { |
1104 | transports); | ||
1105 | transport->cacc.cycling_changeover = 0; | 1101 | transport->cacc.cycling_changeover = 0; |
1106 | } | 1102 | } |
1107 | } | 1103 | } |
@@ -1116,9 +1112,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1116 | */ | 1112 | */ |
1117 | if (sack->num_gap_ack_blocks && | 1113 | if (sack->num_gap_ack_blocks && |
1118 | primary->cacc.changeover_active) { | 1114 | primary->cacc.changeover_active) { |
1119 | list_for_each(pos, transport_list) { | 1115 | list_for_each_entry(transport, transport_list, transports) { |
1120 | transport = list_entry(pos, struct sctp_transport, | ||
1121 | transports); | ||
1122 | transport->cacc.cacc_saw_newack = 0; | 1116 | transport->cacc.cacc_saw_newack = 0; |
1123 | } | 1117 | } |
1124 | } | 1118 | } |
@@ -1147,9 +1141,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1147 | * | 1141 | * |
1148 | * This is a MASSIVE candidate for optimization. | 1142 | * This is a MASSIVE candidate for optimization. |
1149 | */ | 1143 | */ |
1150 | list_for_each(pos, transport_list) { | 1144 | list_for_each_entry(transport, transport_list, transports) { |
1151 | transport = list_entry(pos, struct sctp_transport, | ||
1152 | transports); | ||
1153 | sctp_check_transmitted(q, &transport->transmitted, | 1145 | sctp_check_transmitted(q, &transport->transmitted, |
1154 | transport, sack, highest_new_tsn); | 1146 | transport, sack, highest_new_tsn); |
1155 | /* | 1147 | /* |
@@ -1161,9 +1153,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1161 | count_of_newacks ++; | 1153 | count_of_newacks ++; |
1162 | } | 1154 | } |
1163 | 1155 | ||
1164 | list_for_each(pos, transport_list) { | 1156 | list_for_each_entry(transport, transport_list, transports) { |
1165 | transport = list_entry(pos, struct sctp_transport, | ||
1166 | transports); | ||
1167 | sctp_mark_missing(q, &transport->transmitted, transport, | 1157 | sctp_mark_missing(q, &transport->transmitted, transport, |
1168 | highest_new_tsn, count_of_newacks); | 1158 | highest_new_tsn, count_of_newacks); |
1169 | } | 1159 | } |
@@ -1206,10 +1196,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1206 | sctp_generate_fwdtsn(q, sack_ctsn); | 1196 | sctp_generate_fwdtsn(q, sack_ctsn); |
1207 | 1197 | ||
1208 | SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", | 1198 | SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", |
1209 | __FUNCTION__, sack_ctsn); | 1199 | __func__, sack_ctsn); |
1210 | SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, " | 1200 | SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, " |
1211 | "%p is 0x%x. Adv peer ack point: 0x%x\n", | 1201 | "%p is 0x%x. Adv peer ack point: 0x%x\n", |
1212 | __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point); | 1202 | __func__, asoc, ctsn, asoc->adv_peer_ack_point); |
1213 | 1203 | ||
1214 | /* See if all chunks are acked. | 1204 | /* See if all chunks are acked. |
1215 | * Make sure the empty queue handler will get run later. | 1205 | * Make sure the empty queue handler will get run later. |
@@ -1220,9 +1210,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
1220 | if (!q->empty) | 1210 | if (!q->empty) |
1221 | goto finish; | 1211 | goto finish; |
1222 | 1212 | ||
1223 | list_for_each(pos, transport_list) { | 1213 | list_for_each_entry(transport, transport_list, transports) { |
1224 | transport = list_entry(pos, struct sctp_transport, | ||
1225 | transports); | ||
1226 | q->empty = q->empty && list_empty(&transport->transmitted); | 1214 | q->empty = q->empty && list_empty(&transport->transmitted); |
1227 | if (!q->empty) | 1215 | if (!q->empty) |
1228 | goto finish; | 1216 | goto finish; |
@@ -1444,7 +1432,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1444 | if (tchunk->tsn_gap_acked) { | 1432 | if (tchunk->tsn_gap_acked) { |
1445 | SCTP_DEBUG_PRINTK("%s: Receiver reneged on " | 1433 | SCTP_DEBUG_PRINTK("%s: Receiver reneged on " |
1446 | "data TSN: 0x%x\n", | 1434 | "data TSN: 0x%x\n", |
1447 | __FUNCTION__, | 1435 | __func__, |
1448 | tsn); | 1436 | tsn); |
1449 | tchunk->tsn_gap_acked = 0; | 1437 | tchunk->tsn_gap_acked = 0; |
1450 | 1438 | ||
@@ -1544,6 +1532,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1544 | bytes_acked); | 1532 | bytes_acked); |
1545 | 1533 | ||
1546 | transport->flight_size -= bytes_acked; | 1534 | transport->flight_size -= bytes_acked; |
1535 | if (transport->flight_size == 0) | ||
1536 | transport->partial_bytes_acked = 0; | ||
1547 | q->outstanding_bytes -= bytes_acked; | 1537 | q->outstanding_bytes -= bytes_acked; |
1548 | } else { | 1538 | } else { |
1549 | /* RFC 2960 6.1, sctpimpguide-06 2.15.2 | 1539 | /* RFC 2960 6.1, sctpimpguide-06 2.15.2 |
@@ -1561,7 +1551,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1561 | (sack_ctsn+2 == q->asoc->next_tsn)) { | 1551 | (sack_ctsn+2 == q->asoc->next_tsn)) { |
1562 | SCTP_DEBUG_PRINTK("%s: SACK received for zero " | 1552 | SCTP_DEBUG_PRINTK("%s: SACK received for zero " |
1563 | "window probe: %u\n", | 1553 | "window probe: %u\n", |
1564 | __FUNCTION__, sack_ctsn); | 1554 | __func__, sack_ctsn); |
1565 | q->asoc->overall_error_count = 0; | 1555 | q->asoc->overall_error_count = 0; |
1566 | transport->error_count = 0; | 1556 | transport->error_count = 0; |
1567 | } | 1557 | } |
@@ -1596,14 +1586,12 @@ static void sctp_mark_missing(struct sctp_outq *q, | |||
1596 | int count_of_newacks) | 1586 | int count_of_newacks) |
1597 | { | 1587 | { |
1598 | struct sctp_chunk *chunk; | 1588 | struct sctp_chunk *chunk; |
1599 | struct list_head *pos; | ||
1600 | __u32 tsn; | 1589 | __u32 tsn; |
1601 | char do_fast_retransmit = 0; | 1590 | char do_fast_retransmit = 0; |
1602 | struct sctp_transport *primary = q->asoc->peer.primary_path; | 1591 | struct sctp_transport *primary = q->asoc->peer.primary_path; |
1603 | 1592 | ||
1604 | list_for_each(pos, transmitted_queue) { | 1593 | list_for_each_entry(chunk, transmitted_queue, transmitted_list) { |
1605 | 1594 | ||
1606 | chunk = list_entry(pos, struct sctp_chunk, transmitted_list); | ||
1607 | tsn = ntohl(chunk->subh.data_hdr->tsn); | 1595 | tsn = ntohl(chunk->subh.data_hdr->tsn); |
1608 | 1596 | ||
1609 | /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all | 1597 | /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all |
@@ -1626,7 +1614,7 @@ static void sctp_mark_missing(struct sctp_outq *q, | |||
1626 | 1614 | ||
1627 | SCTP_DEBUG_PRINTK( | 1615 | SCTP_DEBUG_PRINTK( |
1628 | "%s: TSN 0x%x missing counter: %d\n", | 1616 | "%s: TSN 0x%x missing counter: %d\n", |
1629 | __FUNCTION__, tsn, | 1617 | __func__, tsn, |
1630 | chunk->tsn_missing_report); | 1618 | chunk->tsn_missing_report); |
1631 | } | 1619 | } |
1632 | } | 1620 | } |
@@ -1649,7 +1637,7 @@ static void sctp_mark_missing(struct sctp_outq *q, | |||
1649 | 1637 | ||
1650 | SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " | 1638 | SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " |
1651 | "ssthresh: %d, flight_size: %d, pba: %d\n", | 1639 | "ssthresh: %d, flight_size: %d, pba: %d\n", |
1652 | __FUNCTION__, transport, transport->cwnd, | 1640 | __func__, transport, transport->cwnd, |
1653 | transport->ssthresh, transport->flight_size, | 1641 | transport->ssthresh, transport->flight_size, |
1654 | transport->partial_bytes_acked); | 1642 | transport->partial_bytes_acked); |
1655 | } | 1643 | } |