diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sctp/associola.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 215b56951d76..39c3821b7d3d 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -202,6 +202,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
202 | asoc->a_rwnd = asoc->rwnd; | 202 | asoc->a_rwnd = asoc->rwnd; |
203 | 203 | ||
204 | asoc->rwnd_over = 0; | 204 | asoc->rwnd_over = 0; |
205 | asoc->rwnd_press = 0; | ||
205 | 206 | ||
206 | /* Use my own max window until I learn something better. */ | 207 | /* Use my own max window until I learn something better. */ |
207 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; | 208 | asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; |
@@ -1374,6 +1375,17 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) | |||
1374 | asoc->rwnd += len; | 1375 | asoc->rwnd += len; |
1375 | } | 1376 | } |
1376 | 1377 | ||
1378 | /* If we had window pressure, start recovering it | ||
1379 | * once our rwnd had reached the accumulated pressure | ||
1380 | * threshold. The idea is to recover slowly, but up | ||
1381 | * to the initial advertised window. | ||
1382 | */ | ||
1383 | if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) { | ||
1384 | int change = min(asoc->pathmtu, asoc->rwnd_press); | ||
1385 | asoc->rwnd += change; | ||
1386 | asoc->rwnd_press -= change; | ||
1387 | } | ||
1388 | |||
1377 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " | 1389 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " |
1378 | "- %u\n", __func__, asoc, len, asoc->rwnd, | 1390 | "- %u\n", __func__, asoc, len, asoc->rwnd, |
1379 | asoc->rwnd_over, asoc->a_rwnd); | 1391 | asoc->rwnd_over, asoc->a_rwnd); |
@@ -1406,17 +1418,38 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) | |||
1406 | /* Decrease asoc's rwnd by len. */ | 1418 | /* Decrease asoc's rwnd by len. */ |
1407 | void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) | 1419 | void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) |
1408 | { | 1420 | { |
1421 | int rx_count; | ||
1422 | int over = 0; | ||
1423 | |||
1409 | SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); | 1424 | SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); |
1410 | SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); | 1425 | SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); |
1426 | |||
1427 | if (asoc->ep->rcvbuf_policy) | ||
1428 | rx_count = atomic_read(&asoc->rmem_alloc); | ||
1429 | else | ||
1430 | rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); | ||
1431 | |||
1432 | /* If we've reached or overflowed our receive buffer, announce | ||
1433 | * a 0 rwnd if rwnd would still be positive. Store the | ||
1434 | * the pottential pressure overflow so that the window can be restored | ||
1435 | * back to original value. | ||
1436 | */ | ||
1437 | if (rx_count >= asoc->base.sk->sk_rcvbuf) | ||
1438 | over = 1; | ||
1439 | |||
1411 | if (asoc->rwnd >= len) { | 1440 | if (asoc->rwnd >= len) { |
1412 | asoc->rwnd -= len; | 1441 | asoc->rwnd -= len; |
1442 | if (over) { | ||
1443 | asoc->rwnd_press = asoc->rwnd; | ||
1444 | asoc->rwnd = 0; | ||
1445 | } | ||
1413 | } else { | 1446 | } else { |
1414 | asoc->rwnd_over = len - asoc->rwnd; | 1447 | asoc->rwnd_over = len - asoc->rwnd; |
1415 | asoc->rwnd = 0; | 1448 | asoc->rwnd = 0; |
1416 | } | 1449 | } |
1417 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n", | 1450 | SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u, %u)\n", |
1418 | __func__, asoc, len, asoc->rwnd, | 1451 | __func__, asoc, len, asoc->rwnd, |
1419 | asoc->rwnd_over); | 1452 | asoc->rwnd_over, asoc->rwnd_press); |
1420 | } | 1453 | } |
1421 | 1454 | ||
1422 | /* Build the bind address list for the association based on info from the | 1455 | /* Build the bind address list for the association based on info from the |