aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c68
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)
221void sctp_outq_teardown(struct sctp_outq *q) 221void 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,
1037static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, 1038static __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 }