aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/associola.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r--net/sctp/associola.c82
1 files changed, 17 insertions, 65 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5ae609200674..f558433537b8 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1367,44 +1367,35 @@ static inline bool sctp_peer_needs_update(struct sctp_association *asoc)
1367 return false; 1367 return false;
1368} 1368}
1369 1369
1370/* Increase asoc's rwnd by len and send any window update SACK if needed. */ 1370/* Update asoc's rwnd for the approximated state in the buffer,
1371void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len) 1371 * and check whether SACK needs to be sent.
1372 */
1373void sctp_assoc_rwnd_update(struct sctp_association *asoc, bool update_peer)
1372{ 1374{
1375 int rx_count;
1373 struct sctp_chunk *sack; 1376 struct sctp_chunk *sack;
1374 struct timer_list *timer; 1377 struct timer_list *timer;
1375 1378
1376 if (asoc->rwnd_over) { 1379 if (asoc->ep->rcvbuf_policy)
1377 if (asoc->rwnd_over >= len) { 1380 rx_count = atomic_read(&asoc->rmem_alloc);
1378 asoc->rwnd_over -= len; 1381 else
1379 } else { 1382 rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
1380 asoc->rwnd += (len - asoc->rwnd_over);
1381 asoc->rwnd_over = 0;
1382 }
1383 } else {
1384 asoc->rwnd += len;
1385 }
1386 1383
1387 /* If we had window pressure, start recovering it 1384 if ((asoc->base.sk->sk_rcvbuf - rx_count) > 0)
1388 * once our rwnd had reached the accumulated pressure 1385 asoc->rwnd = (asoc->base.sk->sk_rcvbuf - rx_count) >> 1;
1389 * threshold. The idea is to recover slowly, but up 1386 else
1390 * to the initial advertised window. 1387 asoc->rwnd = 0;
1391 */
1392 if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) {
1393 int change = min(asoc->pathmtu, asoc->rwnd_press);
1394 asoc->rwnd += change;
1395 asoc->rwnd_press -= change;
1396 }
1397 1388
1398 pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n", 1389 pr_debug("%s: asoc:%p rwnd=%u, rx_count=%d, sk_rcvbuf=%d\n",
1399 __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, 1390 __func__, asoc, asoc->rwnd, rx_count,
1400 asoc->a_rwnd); 1391 asoc->base.sk->sk_rcvbuf);
1401 1392
1402 /* Send a window update SACK if the rwnd has increased by at least the 1393 /* Send a window update SACK if the rwnd has increased by at least the
1403 * minimum of the association's PMTU and half of the receive buffer. 1394 * minimum of the association's PMTU and half of the receive buffer.
1404 * The algorithm used is similar to the one described in 1395 * The algorithm used is similar to the one described in
1405 * Section 4.2.3.3 of RFC 1122. 1396 * Section 4.2.3.3 of RFC 1122.
1406 */ 1397 */
1407 if (sctp_peer_needs_update(asoc)) { 1398 if (update_peer && sctp_peer_needs_update(asoc)) {
1408 asoc->a_rwnd = asoc->rwnd; 1399 asoc->a_rwnd = asoc->rwnd;
1409 1400
1410 pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u " 1401 pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u "
@@ -1426,45 +1417,6 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
1426 } 1417 }
1427} 1418}
1428 1419
1429/* Decrease asoc's rwnd by len. */
1430void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
1431{
1432 int rx_count;
1433 int over = 0;
1434
1435 if (unlikely(!asoc->rwnd || asoc->rwnd_over))
1436 pr_debug("%s: association:%p has asoc->rwnd:%u, "
1437 "asoc->rwnd_over:%u!\n", __func__, asoc,
1438 asoc->rwnd, asoc->rwnd_over);
1439
1440 if (asoc->ep->rcvbuf_policy)
1441 rx_count = atomic_read(&asoc->rmem_alloc);
1442 else
1443 rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
1444
1445 /* If we've reached or overflowed our receive buffer, announce
1446 * a 0 rwnd if rwnd would still be positive. Store the
1447 * the potential pressure overflow so that the window can be restored
1448 * back to original value.
1449 */
1450 if (rx_count >= asoc->base.sk->sk_rcvbuf)
1451 over = 1;
1452
1453 if (asoc->rwnd >= len) {
1454 asoc->rwnd -= len;
1455 if (over) {
1456 asoc->rwnd_press += asoc->rwnd;
1457 asoc->rwnd = 0;
1458 }
1459 } else {
1460 asoc->rwnd_over = len - asoc->rwnd;
1461 asoc->rwnd = 0;
1462 }
1463
1464 pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n",
1465 __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
1466 asoc->rwnd_press);
1467}
1468 1420
1469/* Build the bind address list for the association based on info from the 1421/* Build the bind address list for the association based on info from the
1470 * local endpoint and the remote peer. 1422 * local endpoint and the remote peer.