aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:21:00 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:21:00 -0400
commit31b02e1549406efa346534acad956a42bc3f28c4 (patch)
tree3acc807275810eb2efdc5fc2744bdfc3528488c2 /net/sctp
parentf68b2e05f326971cd76c65aa91a1a41771dd7485 (diff)
sctp: Failover transmitted list on transport delete
Add-IP feature allows users to delete an active transport. If that transport has chunks in flight, those chunks need to be moved to another transport or association may get into unrecoverable state. Reported-by: Rafael Laufer <rlaufer@cisco.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c27
-rw-r--r--net/sctp/outqueue.c47
-rw-r--r--net/sctp/sm_statefuns.c6
3 files changed, 67 insertions, 13 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 1f05b942564e..caba989f4e76 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -584,6 +584,33 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
584 asoc->addip_last_asconf->transport == peer) 584 asoc->addip_last_asconf->transport == peer)
585 asoc->addip_last_asconf->transport = NULL; 585 asoc->addip_last_asconf->transport = NULL;
586 586
587 /* If we have something on the transmitted list, we have to
588 * save it off. The best place is the active path.
589 */
590 if (!list_empty(&peer->transmitted)) {
591 struct sctp_transport *active = asoc->peer.active_path;
592 struct sctp_chunk *ch;
593
594 /* Reset the transport of each chunk on this list */
595 list_for_each_entry(ch, &peer->transmitted,
596 transmitted_list) {
597 ch->transport = NULL;
598 ch->rtt_in_progress = 0;
599 }
600
601 list_splice_tail_init(&peer->transmitted,
602 &active->transmitted);
603
604 /* Start a T3 timer here in case it wasn't running so
605 * that these migrated packets have a chance to get
606 * retrnasmitted.
607 */
608 if (!timer_pending(&active->T3_rtx_timer))
609 if (!mod_timer(&active->T3_rtx_timer,
610 jiffies + active->rto))
611 sctp_transport_hold(active);
612 }
613
587 asoc->peer.transport_count--; 614 asoc->peer.transport_count--;
588 615
589 sctp_transport_free(peer); 616 sctp_transport_free(peer);
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index d765fc53e74d..c9f20e28521b 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -406,8 +406,9 @@ void sctp_retransmit_mark(struct sctp_outq *q,
406 * not be retransmitted 406 * not be retransmitted
407 */ 407 */
408 if (!chunk->tsn_gap_acked) { 408 if (!chunk->tsn_gap_acked) {
409 chunk->transport->flight_size -= 409 if (chunk->transport)
410 sctp_data_size(chunk); 410 chunk->transport->flight_size -=
411 sctp_data_size(chunk);
411 q->outstanding_bytes -= sctp_data_size(chunk); 412 q->outstanding_bytes -= sctp_data_size(chunk);
412 q->asoc->peer.rwnd += (sctp_data_size(chunk) + 413 q->asoc->peer.rwnd += (sctp_data_size(chunk) +
413 sizeof(struct sk_buff)); 414 sizeof(struct sk_buff));
@@ -443,7 +444,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
443 q->asoc->peer.rwnd += (sctp_data_size(chunk) + 444 q->asoc->peer.rwnd += (sctp_data_size(chunk) +
444 sizeof(struct sk_buff)); 445 sizeof(struct sk_buff));
445 q->outstanding_bytes -= sctp_data_size(chunk); 446 q->outstanding_bytes -= sctp_data_size(chunk);
446 transport->flight_size -= sctp_data_size(chunk); 447 if (chunk->transport)
448 transport->flight_size -= sctp_data_size(chunk);
447 449
448 /* sctpimpguide-05 Section 2.8.2 450 /* sctpimpguide-05 Section 2.8.2
449 * M5) If a T3-rtx timer expires, the 451 * M5) If a T3-rtx timer expires, the
@@ -1310,6 +1312,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1310 __u32 rtt; 1312 __u32 rtt;
1311 __u8 restart_timer = 0; 1313 __u8 restart_timer = 0;
1312 int bytes_acked = 0; 1314 int bytes_acked = 0;
1315 int migrate_bytes = 0;
1313 1316
1314 /* These state variables are for coherent debug output. --xguo */ 1317 /* These state variables are for coherent debug output. --xguo */
1315 1318
@@ -1343,8 +1346,9 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1343 * considering it as 'outstanding'. 1346 * considering it as 'outstanding'.
1344 */ 1347 */
1345 if (!tchunk->tsn_gap_acked) { 1348 if (!tchunk->tsn_gap_acked) {
1346 tchunk->transport->flight_size -= 1349 if (tchunk->transport)
1347 sctp_data_size(tchunk); 1350 tchunk->transport->flight_size -=
1351 sctp_data_size(tchunk);
1348 q->outstanding_bytes -= sctp_data_size(tchunk); 1352 q->outstanding_bytes -= sctp_data_size(tchunk);
1349 } 1353 }
1350 continue; 1354 continue;
@@ -1378,6 +1382,20 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1378 rtt); 1382 rtt);
1379 } 1383 }
1380 } 1384 }
1385
1386 /* If the chunk hasn't been marked as ACKED,
1387 * mark it and account bytes_acked if the
1388 * chunk had a valid transport (it will not
1389 * have a transport if ASCONF had deleted it
1390 * while DATA was outstanding).
1391 */
1392 if (!tchunk->tsn_gap_acked) {
1393 tchunk->tsn_gap_acked = 1;
1394 bytes_acked += sctp_data_size(tchunk);
1395 if (!tchunk->transport)
1396 migrate_bytes += sctp_data_size(tchunk);
1397 }
1398
1381 if (TSN_lte(tsn, sack_ctsn)) { 1399 if (TSN_lte(tsn, sack_ctsn)) {
1382 /* RFC 2960 6.3.2 Retransmission Timer Rules 1400 /* RFC 2960 6.3.2 Retransmission Timer Rules
1383 * 1401 *
@@ -1391,8 +1409,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1391 restart_timer = 1; 1409 restart_timer = 1;
1392 1410
1393 if (!tchunk->tsn_gap_acked) { 1411 if (!tchunk->tsn_gap_acked) {
1394 tchunk->tsn_gap_acked = 1;
1395 bytes_acked += sctp_data_size(tchunk);
1396 /* 1412 /*
1397 * SFR-CACC algorithm: 1413 * SFR-CACC algorithm:
1398 * 2) If the SACK contains gap acks 1414 * 2) If the SACK contains gap acks
@@ -1432,10 +1448,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1432 * older than that newly acknowledged DATA 1448 * older than that newly acknowledged DATA
1433 * chunk, are qualified as 'Stray DATA chunks'. 1449 * chunk, are qualified as 'Stray DATA chunks'.
1434 */ 1450 */
1435 if (!tchunk->tsn_gap_acked) {
1436 tchunk->tsn_gap_acked = 1;
1437 bytes_acked += sctp_data_size(tchunk);
1438 }
1439 list_add_tail(lchunk, &tlist); 1451 list_add_tail(lchunk, &tlist);
1440 } 1452 }
1441 1453
@@ -1491,7 +1503,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1491 tsn); 1503 tsn);
1492 tchunk->tsn_gap_acked = 0; 1504 tchunk->tsn_gap_acked = 0;
1493 1505
1494 bytes_acked -= sctp_data_size(tchunk); 1506 if (tchunk->transport)
1507 bytes_acked -= sctp_data_size(tchunk);
1495 1508
1496 /* RFC 2960 6.3.2 Retransmission Timer Rules 1509 /* RFC 2960 6.3.2 Retransmission Timer Rules
1497 * 1510 *
@@ -1561,6 +1574,14 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1561#endif /* SCTP_DEBUG */ 1574#endif /* SCTP_DEBUG */
1562 if (transport) { 1575 if (transport) {
1563 if (bytes_acked) { 1576 if (bytes_acked) {
1577 /* We may have counted DATA that was migrated
1578 * to this transport due to DEL-IP operation.
1579 * Subtract those bytes, since the were never
1580 * send on this transport and shouldn't be
1581 * credited to this transport.
1582 */
1583 bytes_acked -= migrate_bytes;
1584
1564 /* 8.2. When an outstanding TSN is acknowledged, 1585 /* 8.2. When an outstanding TSN is acknowledged,
1565 * the endpoint shall clear the error counter of 1586 * the endpoint shall clear the error counter of
1566 * the destination transport address to which the 1587 * the destination transport address to which the
@@ -1589,7 +1610,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1589 transport->flight_size -= bytes_acked; 1610 transport->flight_size -= bytes_acked;
1590 if (transport->flight_size == 0) 1611 if (transport->flight_size == 0)
1591 transport->partial_bytes_acked = 0; 1612 transport->partial_bytes_acked = 0;
1592 q->outstanding_bytes -= bytes_acked; 1613 q->outstanding_bytes -= bytes_acked + migrate_bytes;
1593 } else { 1614 } else {
1594 /* RFC 2960 6.1, sctpimpguide-06 2.15.2 1615 /* RFC 2960 6.1, sctpimpguide-06 2.15.2
1595 * When a sender is doing zero window probing, it 1616 * When a sender is doing zero window probing, it
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 45b8bcafd827..a7f18a352364 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3543,6 +3543,12 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
3543 asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial); 3543 asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial);
3544 if (!asconf_ack) 3544 if (!asconf_ack)
3545 return SCTP_DISPOSITION_DISCARD; 3545 return SCTP_DISPOSITION_DISCARD;
3546
3547 /* Reset the transport so that we select the correct one
3548 * this time around. This is to make sure that we don't
3549 * accidentally use a stale transport that's been removed.
3550 */
3551 asconf_ack->transport = NULL;
3546 } else { 3552 } else {
3547 /* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since 3553 /* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since
3548 * it must be either a stale packet or from an attacker. 3554 * it must be either a stale packet or from an attacker.