From 70b03759e9ecfae400605fa34f3d7154cccbbba3 Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Wed, 29 Mar 2017 11:22:16 +0200 Subject: tipc: add support for stream/seqpacket socketpairs sockets A and B are connected back-to-back, similar to what AF_UNIX does. Signed-off-by: Erik Hugne Signed-off-by: Parthasarathy Bhuvaragan Signed-off-by: David S. Miller --- net/tipc/socket.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 7130e73bd42c..1198dddf72e8 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2511,6 +2511,16 @@ static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } } +static int tipc_socketpair(struct socket *sock1, struct socket *sock2) +{ + struct tipc_sock *tsk2 = tipc_sk(sock2->sk); + struct tipc_sock *tsk1 = tipc_sk(sock1->sk); + + tipc_sk_finish_conn(tsk1, tsk2->portid, 0); + tipc_sk_finish_conn(tsk2, tsk1->portid, 0); + return 0; +} + /* Protocol switches for the various types of TIPC sockets */ static const struct proto_ops msg_ops = { @@ -2540,7 +2550,7 @@ static const struct proto_ops packet_ops = { .release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, - .socketpair = sock_no_socketpair, + .socketpair = tipc_socketpair, .accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, @@ -2561,7 +2571,7 @@ static const struct proto_ops stream_ops = { .release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, - .socketpair = sock_no_socketpair, + .socketpair = tipc_socketpair, .accept = tipc_accept, .getname = tipc_getname, .poll = tipc_poll, -- cgit From 66bc1e8d5d1d156b1e85d8c6925225ad8cbdf523 Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Wed, 29 Mar 2017 11:22:17 +0200 Subject: tipc: allow rdm/dgram socketpairs for socketpairs using connectionless transport, we cache the respective node local TIPC portid to use in subsequent calls to send() in the socket's private data. Signed-off-by: Erik Hugne Signed-off-by: Parthasarathy Bhuvaragan Signed-off-by: David S. Miller --- net/tipc/socket.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 1198dddf72e8..15f6ce7bf868 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2515,9 +2515,21 @@ static int tipc_socketpair(struct socket *sock1, struct socket *sock2) { struct tipc_sock *tsk2 = tipc_sk(sock2->sk); struct tipc_sock *tsk1 = tipc_sk(sock1->sk); - - tipc_sk_finish_conn(tsk1, tsk2->portid, 0); - tipc_sk_finish_conn(tsk2, tsk1->portid, 0); + u32 onode = tipc_own_addr(sock_net(sock1->sk)); + + tsk1->peer.family = AF_TIPC; + tsk1->peer.addrtype = TIPC_ADDR_ID; + tsk1->peer.scope = TIPC_NODE_SCOPE; + tsk1->peer.addr.id.ref = tsk2->portid; + tsk1->peer.addr.id.node = onode; + tsk2->peer.family = AF_TIPC; + tsk2->peer.addrtype = TIPC_ADDR_ID; + tsk2->peer.scope = TIPC_NODE_SCOPE; + tsk2->peer.addr.id.ref = tsk1->portid; + tsk2->peer.addr.id.node = onode; + + tipc_sk_finish_conn(tsk1, tsk2->portid, onode); + tipc_sk_finish_conn(tsk2, tsk1->portid, onode); return 0; } @@ -2529,7 +2541,7 @@ static const struct proto_ops msg_ops = { .release = tipc_release, .bind = tipc_bind, .connect = tipc_connect, - .socketpair = sock_no_socketpair, + .socketpair = tipc_socketpair, .accept = sock_no_accept, .getname = tipc_getname, .poll = tipc_poll, -- cgit From fceb6435e85298f747fee938415057af837f5a8a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Apr 2017 14:34:07 +0200 Subject: netlink: pass extended ACK struct to parsing functions Pass the new extended ACK reporting struct to all of the generic netlink parsing functions. For now, pass NULL in almost all callers (except for some in the core.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/tipc/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 15f6ce7bf868..740100abeec3 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2866,7 +2866,7 @@ int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb) err = nla_parse_nested(sock, TIPC_NLA_SOCK_MAX, attrs[TIPC_NLA_SOCK], - tipc_nl_sock_policy); + tipc_nl_sock_policy, NULL); if (err) return err; -- cgit From e9f8b10101c6da3ab000a2fb17162374c9bd2c69 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Tue, 2 May 2017 18:16:53 +0200 Subject: tipc: refactor function tipc_sk_recvmsg() We try to make this function more readable by improving variable names and comments, plus some minor changes to the logics. Reviewed-by: Parthasarathy Bhuvaragan Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 109 +++++++++++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 59 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 8a4e9fe5f9eb..3855bfd1fb1b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -51,6 +51,7 @@ #define TIPC_FWD_MSG 1 #define TIPC_MAX_PORT 0xffffffff #define TIPC_MIN_PORT 1 +#define TIPC_ACK_RATE 4 /* ACK at 1/4 of of rcv window size */ enum { TIPC_LISTEN = TCP_LISTEN, @@ -1290,7 +1291,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) /** * tipc_recvmsg - receive packet-oriented message * @m: descriptor for message info - * @buf_len: total size of user buffer area + * @buflen: length of user buffer area * @flags: receive flags * * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages. @@ -1298,89 +1299,79 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) * * Returns size of returned message data, errno otherwise */ -static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len, - int flags) +static int tipc_recvmsg(struct socket *sock, struct msghdr *m, + size_t buflen, int flags) { struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); - struct sk_buff *buf; - struct tipc_msg *msg; - bool is_connectionless = tipc_sk_type_connectionless(sk); - long timeo; - unsigned int sz; - u32 err; - int res, hlen; + struct sk_buff *skb; + struct tipc_msg *hdr; + bool connected = !tipc_sk_type_connectionless(sk); + int rc, err, hlen, dlen, copy; + long timeout; /* Catch invalid receive requests */ - if (unlikely(!buf_len)) + if (unlikely(!buflen)) return -EINVAL; lock_sock(sk); - - if (!is_connectionless && unlikely(sk->sk_state == TIPC_OPEN)) { - res = -ENOTCONN; + if (unlikely(connected && sk->sk_state == TIPC_OPEN)) { + rc = -ENOTCONN; goto exit; } + timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); -restart: - - /* Look for a message in receive queue; wait if necessary */ - res = tipc_wait_for_rcvmsg(sock, &timeo); - if (res) - goto exit; - - /* Look at first message in receive queue */ - buf = skb_peek(&sk->sk_receive_queue); - msg = buf_msg(buf); - sz = msg_data_sz(msg); - hlen = msg_hdr_sz(msg); - err = msg_errcode(msg); - - /* Discard an empty non-errored message & try again */ - if ((!sz) && (!err)) { + do { + /* Look at first msg in receive queue; wait if necessary */ + rc = tipc_wait_for_rcvmsg(sock, &timeout); + if (unlikely(rc)) + goto exit; + skb = skb_peek(&sk->sk_receive_queue); + hdr = buf_msg(skb); + dlen = msg_data_sz(hdr); + hlen = msg_hdr_sz(hdr); + err = msg_errcode(hdr); + if (likely(dlen || err)) + break; tsk_advance_rx_queue(sk); - goto restart; - } + } while (1); - /* Capture sender's address (optional) */ - set_orig_addr(m, msg); - - /* Capture ancillary data (optional) */ - res = tipc_sk_anc_data_recv(m, msg, tsk); - if (res) + /* Collect msg meta data, including error code and rejected data */ + set_orig_addr(m, hdr); + rc = tipc_sk_anc_data_recv(m, hdr, tsk); + if (unlikely(rc)) goto exit; - /* Capture message data (if valid) & compute return value (always) */ - if (!err) { - if (unlikely(buf_len < sz)) { - sz = buf_len; + /* Capture data if non-error msg, otherwise just set return value */ + if (likely(!err)) { + copy = min_t(int, dlen, buflen); + if (unlikely(copy != dlen)) m->msg_flags |= MSG_TRUNC; - } - res = skb_copy_datagram_msg(buf, hlen, m, sz); - if (res) - goto exit; - res = sz; + rc = skb_copy_datagram_msg(skb, hlen, m, copy); } else { - if (is_connectionless || err == TIPC_CONN_SHUTDOWN || - m->msg_control) - res = 0; - else - res = -ECONNRESET; + copy = 0; + rc = 0; + if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control) + rc = -ECONNRESET; } + if (unlikely(rc)) + goto exit; + /* Caption of data or error code/rejected data was successful */ if (unlikely(flags & MSG_PEEK)) goto exit; - if (likely(!is_connectionless)) { - tsk->rcv_unacked += tsk_inc(tsk, hlen + sz); - if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4))) - tipc_sk_send_ack(tsk); - } tsk_advance_rx_queue(sk); + if (likely(!connected)) + goto exit; + + /* Send connection flow control ack when applicable */ + tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen); + if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE) + tipc_sk_send_ack(tsk); exit: release_sock(sk); - return res; + return rc ? rc : copy; } /** -- cgit From ec8a09fbbeff252c80daf62c7a78342003dddf9c Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Tue, 2 May 2017 18:16:54 +0200 Subject: tipc: refactor function tipc_sk_recv_stream() We try to make this function more readable by improving variable names and comments, using more stack variables, and doing some smaller changes to the logics. We also rename the function to make it consistent with naming conventions used elsewhere in the code. Reviewed-by: Parthasarathy Bhuvaragan Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 155 +++++++++++++++++++++++++----------------------------- 1 file changed, 71 insertions(+), 84 deletions(-) (limited to 'net/tipc/socket.c') 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: } /** - * tipc_recv_stream - receive stream-oriented data + * tipc_recvstream - receive stream-oriented data * @m: descriptor for message info - * @buf_len: total size of user buffer area + * @buflen: total size of user buffer area * @flags: receive flags * * Used for SOCK_STREAM messages only. If not enough data is available @@ -1385,111 +1385,98 @@ exit: * * Returns size of returned message data, errno otherwise */ -static int tipc_recv_stream(struct socket *sock, struct msghdr *m, - size_t buf_len, int flags) +static int tipc_recvstream(struct socket *sock, struct msghdr *m, + size_t buflen, int flags) { struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); - struct sk_buff *buf; - struct tipc_msg *msg; - long timeo; - unsigned int sz; - int target; - int sz_copied = 0; - u32 err; - int res = 0, hlen; + struct sk_buff *skb; + struct tipc_msg *hdr; + struct tipc_skb_cb *skb_cb; + bool peek = flags & MSG_PEEK; + int offset, required, copy, copied = 0; + int hlen, dlen, err, rc; + long timeout; /* Catch invalid receive attempts */ - if (unlikely(!buf_len)) + if (unlikely(!buflen)) return -EINVAL; lock_sock(sk); if (unlikely(sk->sk_state == TIPC_OPEN)) { - res = -ENOTCONN; - goto exit; - } - - target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); - timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - -restart: - /* Look for a message in receive queue; wait if necessary */ - res = tipc_wait_for_rcvmsg(sock, &timeo); - if (res) + rc = -ENOTCONN; goto exit; - - /* Look at first message in receive queue */ - buf = skb_peek(&sk->sk_receive_queue); - msg = buf_msg(buf); - sz = msg_data_sz(msg); - hlen = msg_hdr_sz(msg); - err = msg_errcode(msg); - - /* Discard an empty non-errored message & try again */ - if ((!sz) && (!err)) { - tsk_advance_rx_queue(sk); - goto restart; } + required = sock_rcvlowat(sk, flags & MSG_WAITALL, buflen); + timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - /* Optionally capture sender's address & ancillary data of first msg */ - if (sz_copied == 0) { - set_orig_addr(m, msg); - res = tipc_sk_anc_data_recv(m, msg, tsk); - if (res) - goto exit; - } - - /* Capture message data (if valid) & compute return value (always) */ - if (!err) { - u32 offset = TIPC_SKB_CB(buf)->bytes_read; - u32 needed; - int sz_to_copy; - - sz -= offset; - needed = (buf_len - sz_copied); - sz_to_copy = min(sz, needed); + do { + /* Look at first msg in receive queue; wait if necessary */ + rc = tipc_wait_for_rcvmsg(sock, &timeout); + if (unlikely(rc)) + break; + skb = skb_peek(&sk->sk_receive_queue); + skb_cb = TIPC_SKB_CB(skb); + hdr = buf_msg(skb); + dlen = msg_data_sz(hdr); + hlen = msg_hdr_sz(hdr); + err = msg_errcode(hdr); - res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy); - if (res) - goto exit; + /* Discard any empty non-errored (SYN-) message */ + if (unlikely(!dlen && !err)) { + tsk_advance_rx_queue(sk); + continue; + } - sz_copied += sz_to_copy; + /* Collect msg meta data, incl. error code and rejected data */ + if (!copied) { + set_orig_addr(m, hdr); + rc = tipc_sk_anc_data_recv(m, hdr, tsk); + if (rc) + break; + } - if (sz_to_copy < sz) { - if (!(flags & MSG_PEEK)) - TIPC_SKB_CB(buf)->bytes_read = - offset + sz_to_copy; - goto exit; + /* Copy data if msg ok, otherwise return error/partial data */ + if (likely(!err)) { + offset = skb_cb->bytes_read; + copy = min_t(int, dlen - offset, buflen - copied); + rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy); + if (unlikely(rc)) + break; + copied += copy; + offset += copy; + if (unlikely(offset < dlen)) { + if (!peek) + skb_cb->bytes_read = offset; + break; + } + } else { + rc = 0; + if ((err != TIPC_CONN_SHUTDOWN) && !m->msg_control) + rc = -ECONNRESET; + if (copied || rc) + break; } - } else { - if (sz_copied != 0) - goto exit; /* can't add error msg to valid data */ - if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control) - res = 0; - else - res = -ECONNRESET; - } + if (unlikely(peek)) + break; - if (unlikely(flags & MSG_PEEK)) - goto exit; + tsk_advance_rx_queue(sk); - tsk->rcv_unacked += tsk_inc(tsk, hlen + msg_data_sz(msg)); - if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4))) - tipc_sk_send_ack(tsk); - tsk_advance_rx_queue(sk); + /* Send connection flow control advertisement when applicable */ + tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen); + if (unlikely(tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)) + tipc_sk_send_ack(tsk); - /* Loop around if more data is required */ - if ((sz_copied < buf_len) && /* didn't get all requested data */ - (!skb_queue_empty(&sk->sk_receive_queue) || - (sz_copied < target)) && /* and more is ready or required */ - (!err)) /* and haven't reached a FIN */ - goto restart; + /* Exit if all requested data or FIN/error received */ + if (copied == buflen || err) + break; + } while (!skb_queue_empty(&sk->sk_receive_queue) || copied < required); exit: release_sock(sk); - return sz_copied ? sz_copied : res; + return copied ? copied : rc; } /** @@ -2584,7 +2571,7 @@ static const struct proto_ops stream_ops = { .setsockopt = tipc_setsockopt, .getsockopt = tipc_getsockopt, .sendmsg = tipc_sendstream, - .recvmsg = tipc_recv_stream, + .recvmsg = tipc_recvstream, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage }; -- cgit