diff options
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r-- | net/sctp/associola.c | 93 |
1 files changed, 80 insertions, 13 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 525864bf4f07..8450960df24f 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -112,6 +112,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
112 | asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) | 112 | asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) |
113 | * 1000; | 113 | * 1000; |
114 | asoc->frag_point = 0; | 114 | asoc->frag_point = 0; |
115 | asoc->user_frag = sp->user_frag; | ||
115 | 116 | ||
116 | /* Set the association max_retrans and RTO values from the | 117 | /* Set the association max_retrans and RTO values from the |
117 | * socket values. | 118 | * socket values. |
@@ -202,6 +203,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
202 | asoc->a_rwnd = asoc->rwnd; | 203 | asoc->a_rwnd = asoc->rwnd; |
203 | 204 | ||
204 | asoc->rwnd_over = 0; | 205 | asoc->rwnd_over = 0; |
206 | asoc->rwnd_press = 0; | ||
205 | 207 | ||
206 | /* Use my own max window until I learn something better. */ | 208 | /* Use my own max window until I learn something better. */ |
207 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; | 209 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; |
@@ -582,6 +584,33 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, | |||
582 | asoc->addip_last_asconf->transport == peer) | 584 | asoc->addip_last_asconf->transport == peer) |
583 | asoc->addip_last_asconf->transport = NULL; | 585 | asoc->addip_last_asconf->transport = NULL; |
584 | 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 | |||
585 | asoc->peer.transport_count--; | 614 | asoc->peer.transport_count--; |
586 | 615 | ||
587 | sctp_transport_free(peer); | 616 | sctp_transport_free(peer); |
@@ -651,13 +680,15 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
651 | */ | 680 | */ |
652 | peer->param_flags = asoc->param_flags; | 681 | peer->param_flags = asoc->param_flags; |
653 | 682 | ||
683 | sctp_transport_route(peer, NULL, sp); | ||
684 | |||
654 | /* Initialize the pmtu of the transport. */ | 685 | /* Initialize the pmtu of the transport. */ |
655 | if (peer->param_flags & SPP_PMTUD_ENABLE) | 686 | if (peer->param_flags & SPP_PMTUD_DISABLE) { |
656 | sctp_transport_pmtu(peer); | 687 | if (asoc->pathmtu) |
657 | else if (asoc->pathmtu) | 688 | peer->pathmtu = asoc->pathmtu; |
658 | peer->pathmtu = asoc->pathmtu; | 689 | else |
659 | else | 690 | peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
660 | peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT; | 691 | } |
661 | 692 | ||
662 | /* If this is the first transport addr on this association, | 693 | /* If this is the first transport addr on this association, |
663 | * initialize the association PMTU to the peer's PMTU. | 694 | * initialize the association PMTU to the peer's PMTU. |
@@ -673,7 +704,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
673 | "%d\n", asoc, asoc->pathmtu); | 704 | "%d\n", asoc, asoc->pathmtu); |
674 | peer->pmtu_pending = 0; | 705 | peer->pmtu_pending = 0; |
675 | 706 | ||
676 | asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); | 707 | asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu); |
677 | 708 | ||
678 | /* The asoc->peer.port might not be meaningful yet, but | 709 | /* The asoc->peer.port might not be meaningful yet, but |
679 | * initialize the packet structure anyway. | 710 | * initialize the packet structure anyway. |
@@ -810,11 +841,16 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
810 | break; | 841 | break; |
811 | 842 | ||
812 | case SCTP_TRANSPORT_DOWN: | 843 | case SCTP_TRANSPORT_DOWN: |
813 | /* if the transort was never confirmed, do not transition it | 844 | /* If the transport was never confirmed, do not transition it |
814 | * to inactive state. | 845 | * to inactive state. Also, release the cached route since |
846 | * there may be a better route next time. | ||
815 | */ | 847 | */ |
816 | if (transport->state != SCTP_UNCONFIRMED) | 848 | if (transport->state != SCTP_UNCONFIRMED) |
817 | transport->state = SCTP_INACTIVE; | 849 | transport->state = SCTP_INACTIVE; |
850 | else { | ||
851 | dst_release(transport->dst); | ||
852 | transport->dst = NULL; | ||
853 | } | ||
818 | 854 | ||
819 | spc_state = SCTP_ADDR_UNREACHABLE; | 855 | spc_state = SCTP_ADDR_UNREACHABLE; |
820 | break; | 856 | break; |
@@ -1324,9 +1360,8 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) | |||
1324 | } | 1360 | } |
1325 | 1361 | ||
1326 | if (pmtu) { | 1362 | if (pmtu) { |
1327 | struct sctp_sock *sp = sctp_sk(asoc->base.sk); | ||
1328 | asoc->pathmtu = pmtu; | 1363 | asoc->pathmtu = pmtu; |
1329 | asoc->frag_point = sctp_frag_point(sp, pmtu); | 1364 | asoc->frag_point = sctp_frag_point(asoc, pmtu); |
1330 | } | 1365 | } |
1331 | 1366 | ||
1332 | SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", | 1367 | SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", |
@@ -1369,6 +1404,17 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) | |||
1369 | asoc->rwnd += len; | 1404 | asoc->rwnd += len; |
1370 | } | 1405 | } |
1371 | 1406 | ||
1407 | /* If we had window pressure, start recovering it | ||
1408 | * once our rwnd had reached the accumulated pressure | ||
1409 | * threshold. The idea is to recover slowly, but up | ||
1410 | * to the initial advertised window. | ||
1411 | */ | ||
1412 | if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) { | ||
1413 | int change = min(asoc->pathmtu, asoc->rwnd_press); | ||
1414 | asoc->rwnd += change; | ||
1415 | asoc->rwnd_press -= change; | ||
1416 | } | ||
1417 | |||
1372 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " | 1418 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " |
1373 | "- %u\n", __func__, asoc, len, asoc->rwnd, | 1419 | "- %u\n", __func__, asoc, len, asoc->rwnd, |
1374 | asoc->rwnd_over, asoc->a_rwnd); | 1420 | asoc->rwnd_over, asoc->a_rwnd); |
@@ -1401,17 +1447,38 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) | |||
1401 | /* Decrease asoc's rwnd by len. */ | 1447 | /* Decrease asoc's rwnd by len. */ |
1402 | void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) | 1448 | void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) |
1403 | { | 1449 | { |
1450 | int rx_count; | ||
1451 | int over = 0; | ||
1452 | |||
1404 | SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); | 1453 | SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); |
1405 | SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); | 1454 | SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); |
1455 | |||
1456 | if (asoc->ep->rcvbuf_policy) | ||
1457 | rx_count = atomic_read(&asoc->rmem_alloc); | ||
1458 | else | ||
1459 | rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); | ||
1460 | |||
1461 | /* If we've reached or overflowed our receive buffer, announce | ||
1462 | * a 0 rwnd if rwnd would still be positive. Store the | ||
1463 | * the pottential pressure overflow so that the window can be restored | ||
1464 | * back to original value. | ||
1465 | */ | ||
1466 | if (rx_count >= asoc->base.sk->sk_rcvbuf) | ||
1467 | over = 1; | ||
1468 | |||
1406 | if (asoc->rwnd >= len) { | 1469 | if (asoc->rwnd >= len) { |
1407 | asoc->rwnd -= len; | 1470 | asoc->rwnd -= len; |
1471 | if (over) { | ||
1472 | asoc->rwnd_press = asoc->rwnd; | ||
1473 | asoc->rwnd = 0; | ||
1474 | } | ||
1408 | } else { | 1475 | } else { |
1409 | asoc->rwnd_over = len - asoc->rwnd; | 1476 | asoc->rwnd_over = len - asoc->rwnd; |
1410 | asoc->rwnd = 0; | 1477 | asoc->rwnd = 0; |
1411 | } | 1478 | } |
1412 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n", | 1479 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u, %u)\n", |
1413 | __func__, asoc, len, asoc->rwnd, | 1480 | __func__, asoc, len, asoc->rwnd, |
1414 | asoc->rwnd_over); | 1481 | asoc->rwnd_over, asoc->rwnd_press); |
1415 | } | 1482 | } |
1416 | 1483 | ||
1417 | /* Build the bind address list for the association based on info from the | 1484 | /* Build the bind address list for the association based on info from the |