diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sctp/associola.c | 27 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 47 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 6 |
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. |