Commit 69cad59d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tipc-fixes'



Tuong Lien says:

====================
tipc: add some patches

This series adds patches to fix some issues in TIPC streaming & service
subscription.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f3fbc5a3 88690b10
Loading
Loading
Loading
Loading
+31 −11
Original line number Diff line number Diff line
@@ -1739,22 +1739,21 @@ static int tipc_sk_anc_data_recv(struct msghdr *m, struct sk_buff *skb,
	return 0;
}

static void tipc_sk_send_ack(struct tipc_sock *tsk)
static struct sk_buff *tipc_sk_build_ack(struct tipc_sock *tsk)
{
	struct sock *sk = &tsk->sk;
	struct net *net = sock_net(sk);
	struct sk_buff *skb = NULL;
	struct tipc_msg *msg;
	u32 peer_port = tsk_peer_port(tsk);
	u32 dnode = tsk_peer_node(tsk);

	if (!tipc_sk_connected(sk))
		return;
		return NULL;
	skb = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0,
			      dnode, tsk_own_node(tsk), peer_port,
			      tsk->portid, TIPC_OK);
	if (!skb)
		return;
		return NULL;
	msg = buf_msg(skb);
	msg_set_conn_ack(msg, tsk->rcv_unacked);
	tsk->rcv_unacked = 0;
@@ -1764,7 +1763,19 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk)
		tsk->rcv_win = tsk_adv_blocks(tsk->sk.sk_rcvbuf);
		msg_set_adv_win(msg, tsk->rcv_win);
	}
	tipc_node_xmit_skb(net, skb, dnode, msg_link_selector(msg));
	return skb;
}

static void tipc_sk_send_ack(struct tipc_sock *tsk)
{
	struct sk_buff *skb;

	skb = tipc_sk_build_ack(tsk);
	if (!skb)
		return;

	tipc_node_xmit_skb(sock_net(&tsk->sk), skb, tsk_peer_node(tsk),
			   msg_link_selector(buf_msg(skb)));
}

static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
@@ -1938,7 +1949,6 @@ static int tipc_recvstream(struct socket *sock, struct msghdr *m,
	bool peek = flags & MSG_PEEK;
	int offset, required, copy, copied = 0;
	int hlen, dlen, err, rc;
	bool ack = false;
	long timeout;

	/* Catch invalid receive attempts */
@@ -1983,7 +1993,6 @@ static int tipc_recvstream(struct socket *sock, struct msghdr *m,

		/* Copy data if msg ok, otherwise return error/partial data */
		if (likely(!err)) {
			ack = msg_ack_required(hdr);
			offset = skb_cb->bytes_read;
			copy = min_t(int, dlen - offset, buflen - copied);
			rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy);
@@ -2011,7 +2020,7 @@ static int tipc_recvstream(struct socket *sock, struct msghdr *m,

		/* Send connection flow control advertisement when applicable */
		tsk->rcv_unacked += tsk_inc(tsk, hlen + dlen);
		if (ack || tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
		if (tsk->rcv_unacked >= tsk->rcv_win / TIPC_ACK_RATE)
			tipc_sk_send_ack(tsk);

		/* Exit if all requested data or FIN/error received */
@@ -2105,9 +2114,11 @@ static void tipc_sk_proto_rcv(struct sock *sk,
 * tipc_sk_filter_connect - check incoming message for a connection-based socket
 * @tsk: TIPC socket
 * @skb: pointer to message buffer.
 * @xmitq: for Nagle ACK if any
 * Returns true if message should be added to receive queue, false otherwise
 */
static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb,
				   struct sk_buff_head *xmitq)
{
	struct sock *sk = &tsk->sk;
	struct net *net = sock_net(sk);
@@ -2171,8 +2182,17 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
		if (!skb_queue_empty(&sk->sk_write_queue))
			tipc_sk_push_backlog(tsk);
		/* Accept only connection-based messages sent by peer */
		if (likely(con_msg && !err && pport == oport && pnode == onode))
		if (likely(con_msg && !err && pport == oport &&
			   pnode == onode)) {
			if (msg_ack_required(hdr)) {
				struct sk_buff *skb;

				skb = tipc_sk_build_ack(tsk);
				if (skb)
					__skb_queue_tail(xmitq, skb);
			}
			return true;
		}
		if (!tsk_peer_msg(tsk, hdr))
			return false;
		if (!err)
@@ -2267,7 +2287,7 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,
	while ((skb = __skb_dequeue(&inputq))) {
		hdr = buf_msg(skb);
		limit = rcvbuf_limit(sk, skb);
		if ((sk_conn && !tipc_sk_filter_connect(tsk, skb)) ||
		if ((sk_conn && !tipc_sk_filter_connect(tsk, skb, xmitq)) ||
		    (!sk_conn && msg_connected(hdr)) ||
		    (!grp && msg_in_group(hdr)))
			err = TIPC_ERR_NO_PORT;
+10 −0
Original line number Diff line number Diff line
@@ -96,6 +96,16 @@ void tipc_sub_get(struct tipc_subscription *subscription);
		(swap_ ? swab32(val__) : val__);			\
	})

/* tipc_sub_write - write val_ to field_ of struct sub_ in user endian format
 */
#define tipc_sub_write(sub_, field_, val_)				\
	({								\
		struct tipc_subscr *sub__ = sub_;			\
		u32 val__ = val_;					\
		int swap_ = !((sub__)->filter & TIPC_FILTER_MASK);	\
		(sub__)->field_ = swap_ ? swab32(val__) : val__;	\
	})

/* tipc_evt_write - write val_ to field_ of struct evt_ in user endian format
 */
#define tipc_evt_write(evt_, field_, val_)				\
+8 −5
Original line number Diff line number Diff line
@@ -237,7 +237,7 @@ static void tipc_conn_delete_sub(struct tipc_conn *con, struct tipc_subscr *s)
		if (!s || !memcmp(s, &sub->evt.s, sizeof(*s))) {
			tipc_sub_unsubscribe(sub);
			atomic_dec(&tn->subscription_count);
		} else if (s) {
			if (s)
				break;
		}
	}
@@ -362,9 +362,10 @@ static int tipc_conn_rcv_sub(struct tipc_topsrv *srv,
{
	struct tipc_net *tn = tipc_net(srv->net);
	struct tipc_subscription *sub;
	u32 s_filter = tipc_sub_read(s, filter);

	if (tipc_sub_read(s, filter) & TIPC_SUB_CANCEL) {
		s->filter &= __constant_ntohl(~TIPC_SUB_CANCEL);
	if (s_filter & TIPC_SUB_CANCEL) {
		tipc_sub_write(s, filter, s_filter & ~TIPC_SUB_CANCEL);
		tipc_conn_delete_sub(con, s);
		return 0;
	}
@@ -400,6 +401,8 @@ static int tipc_conn_rcv_from_sock(struct tipc_conn *con)
		return -EWOULDBLOCK;
	if (ret == sizeof(s)) {
		read_lock_bh(&sk->sk_callback_lock);
		/* RACE: the connection can be closed in the meantime */
		if (likely(connected(con)))
			ret = tipc_conn_rcv_sub(srv, con, &s);
		read_unlock_bh(&sk->sk_callback_lock);
		if (!ret)