aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c155
1 files changed, 71 insertions, 84 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 3855bfd1fb1b..7e45ef938c18 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1375,9 +1375,9 @@ exit:
1375} 1375}
1376 1376
1377/** 1377/**
1378 * tipc_recv_stream - receive stream-oriented data 1378 * tipc_recvstream - receive stream-oriented data
1379 * @m: descriptor for message info 1379 * @m: descriptor for message info
1380 * @buf_len: total size of user buffer area 1380 * @buflen: total size of user buffer area
1381 * @flags: receive flags 1381 * @flags: receive flags
1382 * 1382 *
1383 * Used for SOCK_STREAM messages only. If not enough data is available 1383 * Used for SOCK_STREAM messages only. If not enough data is available
@@ -1385,111 +1385,98 @@ exit:
1385 * 1385 *
1386 * Returns size of returned message data, errno otherwise 1386 * Returns size of returned message data, errno otherwise
1387 */ 1387 */
1388static int tipc_recv_stream(struct socket *sock, struct msghdr *m, 1388static int tipc_recvstream(struct socket *sock, struct msghdr *m,
1389 size_t buf_len, int flags) 1389 size_t buflen, int flags)
1390{ 1390{
1391 struct sock *sk = sock->sk; 1391 struct sock *sk = sock->sk;
1392 struct tipc_sock *tsk = tipc_sk(sk); 1392 struct tipc_sock *tsk = tipc_sk(sk);
1393 struct sk_buff *buf; 1393 struct sk_buff *skb;
1394 struct tipc_msg *msg; 1394 struct tipc_msg *hdr;
1395 long timeo; 1395 struct tipc_skb_cb *skb_cb;
1396 unsigned int sz; 1396 bool peek = flags & MSG_PEEK;
1397 int target; 1397 int offset, required, copy, copied = 0;
1398 int sz_copied = 0; 1398 int hlen, dlen, err, rc;
1399 u32 err; 1399 long timeout;
1400 int res = 0, hlen;
1401 1400
1402 /* Catch invalid receive attempts */ 1401 /* Catch invalid receive attempts */
1403 if (unlikely(!buf_len)) 1402 if (unlikely(!buflen))
1404 return -EINVAL; 1403 return -EINVAL;
1405 1404
1406 lock_sock(sk); 1405 lock_sock(sk);
1407 1406
1408 if (unlikely(sk->sk_state == TIPC_OPEN)) { 1407 if (unlikely(sk->sk_state == TIPC_OPEN)) {
1409 res = -ENOTCONN; 1408 rc = -ENOTCONN;
1410 goto exit;
1411 }
1412
1413 target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
1414 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1415
1416restart:
1417 /* Look for a message in receive queue; wait if necessary */
1418 res = tipc_wait_for_rcvmsg(sock, &timeo);
1419 if (res)
1420 goto exit; 1409 goto exit;
1421
1422 /* Look at first message in receive queue */
1423 buf = skb_peek(&sk->sk_receive_queue);
1424 msg = buf_msg(buf);
1425 sz = msg_data_sz(msg);
1426 hlen = msg_hdr_sz(msg);
1427 err = msg_errcode(msg);
1428
1429 /* Discard an empty non-errored message & try again */
1430 if ((!sz) && (!err)) {
1431 tsk_advance_rx_queue(sk);
1432 goto restart;
1433 } 1410 }
1411 required = sock_rcvlowat(sk, flags & MSG_WAITALL, buflen);
1412 timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1434 1413
1435 /* Optionally capture sender's address & ancillary data of first msg */ 1414 do {
1436 if (sz_copied == 0) { 1415 /* Look at first msg in receive queue; wait if necessary */
1437 set_orig_addr(m, msg); 1416 rc = tipc_wait_for_rcvmsg(sock, &timeout);
1438 res = tipc_sk_anc_data_recv(m, msg, tsk); 1417 if (unlikely(rc))
1439 if (res) 1418 break;
1440 goto exit; 1419 skb = skb_peek(&sk->sk_receive_queue);
1441 } 1420 skb_cb = TIPC_SKB_CB(skb);
1442 1421 hdr = buf_msg(skb);
1443 /* Capture message data (if valid) & compute return value (always) */ 1422 dlen = msg_data_sz(hdr);
1444 if (!err) { 1423 hlen = msg_hdr_sz(hdr);
1445 u32 offset = TIPC_SKB_CB(buf)->bytes_read; 1424 err = msg_errcode(hdr);
1446 u32 needed;
1447 int sz_to_copy;
1448
1449 sz -= offset;
1450 needed = (buf_len - sz_copied);
1451 sz_to_copy = min(sz, needed);
1452 1425
1453 res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy); 1426 /* Discard any empty non-errored (SYN-) message */
1454 if (res) 1427 if (unlikely(!dlen && !err)) {
1455 goto exit; 1428 tsk_advance_rx_queue(sk);
1429 continue;
1430 }
1456 1431
1457 sz_copied += sz_to_copy; 1432 /* Collect msg meta data, incl. error code and rejected data */
1433 if (!copied) {
1434 set_orig_addr(m, hdr);
1435 rc = tipc_sk_anc_data_recv(m, hdr, tsk);
1436 if (rc)
1437 break;
1438 }
1458 1439
1459 if (sz_to_copy < sz) { 1440 /* Copy data if msg ok, otherwise return error/partial data */
1460 if (!(flags & MSG_PEEK)) 1441 if (likely(!err)) {
1461 TIPC_SKB_CB(buf)->bytes_read = 1442 offset = skb_cb->bytes_read;
1462 offset + sz_to_copy; 1443 copy = min_t(int, dlen - offset, buflen - copied);
1463 goto exit; 1444 rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
1445 if (unlikely(rc))
1446 break;
1447 copied += copy;
1448 offset += copy;
1449 if (unlikely(offset < dlen)) {
1450 if (!peek)
1451 skb_cb->bytes_read = offset;
1452 break;
1453 }
1454 } else {
1455 rc = 0;
1456 if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control)
1457 rc = -ECONNRESET;
1458 if (copied || rc)
1459 break;
1464 } 1460 }
1465 } else {
1466 if (sz_copied != 0)
1467 goto exit; /* can't add error msg to valid data */
1468 1461
1469 if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) 1462 if (unlikely(peek))
1470 res = 0; 1463 break;
1471 else
1472 res = -ECONNRESET;
1473 }
1474 1464
1475 if (unlikely(flags & MSG_PEEK)) 1465 tsk_advance_rx_queue(sk);
1476 goto exit;
1477 1466
1478 tsk->rcv_unacked += tsk_inc(tsk, hlen + msg_data_sz(msg)); 1467 /* Send connection flow control advertisement when applicable */
1479 if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4))) 1468 tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
1480 tipc_sk_send_ack(tsk); 1469 if (unlikely(tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE))
1481 tsk_advance_rx_queue(sk); 1470 tipc_sk_send_ack(tsk);
1482 1471
1483 /* Loop around if more data is required */ 1472 /* Exit if all requested data or FIN/error received */
1484 if ((sz_copied < buf_len) && /* didn't get all requested data */ 1473 if (copied == buflen || err)
1485 (!skb_queue_empty(&sk->sk_receive_queue) || 1474 break;
1486 (sz_copied < target)) && /* and more is ready or required */
1487 (!err)) /* and haven't reached a FIN */
1488 goto restart;
1489 1475
1476 } while (!skb_queue_empty(&sk->sk_receive_queue) || copied < required);
1490exit: 1477exit:
1491 release_sock(sk); 1478 release_sock(sk);
1492 return sz_copied ? sz_copied : res; 1479 return copied ? copied : rc;
1493} 1480}
1494 1481
1495/** 1482/**
@@ -2584,7 +2571,7 @@ static const struct proto_ops stream_ops = {
2584 .setsockopt = tipc_setsockopt, 2571 .setsockopt = tipc_setsockopt,
2585 .getsockopt = tipc_getsockopt, 2572 .getsockopt = tipc_getsockopt,
2586 .sendmsg = tipc_sendstream, 2573 .sendmsg = tipc_sendstream,
2587 .recvmsg = tipc_recv_stream, 2574 .recvmsg = tipc_recvstream,
2588 .mmap = sock_no_mmap, 2575 .mmap = sock_no_mmap,
2589 .sendpage = sock_no_sendpage 2576 .sendpage = sock_no_sendpage
2590}; 2577};