diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bearer.c | 2 | ||||
| -rw-r--r-- | net/tipc/msg.c | 78 | ||||
| -rw-r--r-- | net/tipc/msg.h | 11 | ||||
| -rw-r--r-- | net/tipc/name_distr.c | 18 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 1 | ||||
| -rw-r--r-- | net/tipc/name_table.h | 1 | ||||
| -rw-r--r-- | net/tipc/node.h | 12 | ||||
| -rw-r--r-- | net/tipc/socket.c | 209 | ||||
| -rw-r--r-- | net/tipc/topsrv.c | 12 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 18 | 
10 files changed, 222 insertions, 140 deletions
| diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 645c16052052..e65c3a8551e4 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -577,7 +577,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,  		rcu_dereference_rtnl(orig_dev->tipc_ptr);  	if (likely(b && test_bit(0, &b->up) &&  		   (skb->pkt_type <= PACKET_MULTICAST))) { -		skb->next = NULL; +		skb_mark_not_on_list(skb);  		tipc_rcv(dev_net(b->pt.dev), skb, b);  		rcu_read_unlock();  		return NET_RX_SUCCESS; diff --git a/net/tipc/msg.c b/net/tipc/msg.c index b61891054709..f48e5857210f 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -499,54 +499,56 @@ bool tipc_msg_make_bundle(struct sk_buff **skb,  struct tipc_msg *msg,  /**   * tipc_msg_reverse(): swap source and destination addresses and add error code   * @own_node: originating node id for reversed message - * @skb:  buffer containing message to be reversed; may be replaced. + * @skb:  buffer containing message to be reversed; will be consumed   * @err:  error code to be set in message, if any - * Consumes buffer at failure + * Replaces consumed buffer with new one when successful   * Returns true if success, otherwise false   */  bool tipc_msg_reverse(u32 own_node,  struct sk_buff **skb, int err)  {  	struct sk_buff *_skb = *skb; -	struct tipc_msg *hdr; -	struct tipc_msg ohdr; -	int dlen; +	struct tipc_msg *_hdr, *hdr; +	int hlen, dlen;  	if (skb_linearize(_skb))  		goto exit; -	hdr = buf_msg(_skb); -	dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE); -	if (msg_dest_droppable(hdr)) +	_hdr = buf_msg(_skb); +	dlen = min_t(uint, msg_data_sz(_hdr), MAX_FORWARD_SIZE); +	hlen = msg_hdr_sz(_hdr); + +	if (msg_dest_droppable(_hdr))  		goto exit; -	if (msg_errcode(hdr)) +	if (msg_errcode(_hdr))  		goto exit; -	/* Take a copy of original header before altering message */ -	memcpy(&ohdr, hdr, msg_hdr_sz(hdr)); - -	/* Never return SHORT header; expand by replacing buffer if necessary */ -	if (msg_short(hdr)) { -		*skb = tipc_buf_acquire(BASIC_H_SIZE + dlen, GFP_ATOMIC); -		if (!*skb) -			goto exit; -		memcpy((*skb)->data + BASIC_H_SIZE, msg_data(hdr), dlen); -		kfree_skb(_skb); -		_skb = *skb; -		hdr = buf_msg(_skb); -		memcpy(hdr, &ohdr, BASIC_H_SIZE); -		msg_set_hdr_sz(hdr, BASIC_H_SIZE); -	} +	/* Never return SHORT header */ +	if (hlen == SHORT_H_SIZE) +		hlen = BASIC_H_SIZE; + +	/* Don't return data along with SYN+, - sender has a clone */ +	if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD) +		dlen = 0; + +	/* Allocate new buffer to return */ +	*skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC); +	if (!*skb) +		goto exit; +	memcpy((*skb)->data, _skb->data, msg_hdr_sz(_hdr)); +	memcpy((*skb)->data + hlen, msg_data(_hdr), dlen); -	/* Now reverse the concerned fields */ +	/* Build reverse header in new buffer */ +	hdr = buf_msg(*skb); +	msg_set_hdr_sz(hdr, hlen);  	msg_set_errcode(hdr, err);  	msg_set_non_seq(hdr, 0); -	msg_set_origport(hdr, msg_destport(&ohdr)); -	msg_set_destport(hdr, msg_origport(&ohdr)); -	msg_set_destnode(hdr, msg_prevnode(&ohdr)); +	msg_set_origport(hdr, msg_destport(_hdr)); +	msg_set_destport(hdr, msg_origport(_hdr)); +	msg_set_destnode(hdr, msg_prevnode(_hdr));  	msg_set_prevnode(hdr, own_node);  	msg_set_orignode(hdr, own_node); -	msg_set_size(hdr, msg_hdr_sz(hdr) + dlen); -	skb_trim(_skb, msg_size(hdr)); +	msg_set_size(hdr, hlen + dlen);  	skb_orphan(_skb); +	kfree_skb(_skb);  	return true;  exit:  	kfree_skb(_skb); @@ -554,6 +556,22 @@ exit:  	return false;  } +bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy) +{ +	struct sk_buff *skb, *_skb; + +	skb_queue_walk(msg, skb) { +		_skb = skb_clone(skb, GFP_ATOMIC); +		if (!_skb) { +			__skb_queue_purge(cpy); +			pr_err_ratelimited("Failed to clone buffer chain\n"); +			return false; +		} +		__skb_queue_tail(cpy, _skb); +	} +	return true; +} +  /**   * tipc_msg_lookup_dest(): try to find new destination for named message   * @skb: the buffer containing the message. diff --git a/net/tipc/msg.h b/net/tipc/msg.h index a4e944d59394..a2879e6ec5b6 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -216,6 +216,16 @@ static inline void msg_set_non_seq(struct tipc_msg *m, u32 n)  	msg_set_bits(m, 0, 20, 1, n);  } +static inline int msg_is_syn(struct tipc_msg *m) +{ +	return msg_bits(m, 0, 17, 1); +} + +static inline void msg_set_syn(struct tipc_msg *m, u32 d) +{ +	msg_set_bits(m, 0, 17, 1, d); +} +  static inline int msg_dest_droppable(struct tipc_msg *m)  {  	return msg_bits(m, 0, 19, 1); @@ -970,6 +980,7 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,  			struct sk_buff_head *cpy);  void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,  			     struct sk_buff *skb); +bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy);  static inline u16 buf_seqno(struct sk_buff *skb)  { diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 3cfeb9df64b0..61219f0b9677 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -94,8 +94,9 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ)  		list_add_tail_rcu(&publ->binding_node, &nt->node_scope);  		return NULL;  	} -	list_add_tail_rcu(&publ->binding_node, &nt->cluster_scope); - +	write_lock_bh(&nt->cluster_scope_lock); +	list_add_tail(&publ->binding_node, &nt->cluster_scope); +	write_unlock_bh(&nt->cluster_scope_lock);  	skb = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);  	if (!skb) {  		pr_warn("Publication distribution failure\n"); @@ -112,11 +113,13 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ)   */  struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ)  { +	struct name_table *nt = tipc_name_table(net);  	struct sk_buff *buf;  	struct distr_item *item; -	list_del_rcu(&publ->binding_node); - +	write_lock_bh(&nt->cluster_scope_lock); +	list_del(&publ->binding_node); +	write_unlock_bh(&nt->cluster_scope_lock);  	if (publ->scope == TIPC_NODE_SCOPE)  		return NULL; @@ -147,7 +150,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,  			ITEM_SIZE) * ITEM_SIZE;  	u32 msg_rem = msg_dsz; -	list_for_each_entry_rcu(publ, pls, binding_node) { +	list_for_each_entry(publ, pls, binding_node) {  		/* Prepare next buffer: */  		if (!skb) {  			skb = named_prepare_buf(net, PUBLICATION, msg_rem, @@ -189,11 +192,10 @@ void tipc_named_node_up(struct net *net, u32 dnode)  	__skb_queue_head_init(&head); -	rcu_read_lock(); +	read_lock_bh(&nt->cluster_scope_lock);  	named_distribute(net, &head, dnode, &nt->cluster_scope); -	rcu_read_unlock(); -  	tipc_node_xmit(net, &head, dnode, 0); +	read_unlock_bh(&nt->cluster_scope_lock);  }  /** diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 66d5b2c5987a..bff241f03525 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -744,6 +744,7 @@ int tipc_nametbl_init(struct net *net)  	INIT_LIST_HEAD(&nt->node_scope);  	INIT_LIST_HEAD(&nt->cluster_scope); +	rwlock_init(&nt->cluster_scope_lock);  	tn->nametbl = nt;  	spin_lock_init(&tn->nametbl_lock);  	return 0; diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 892bd750b85f..f79066334cc8 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -100,6 +100,7 @@ struct name_table {  	struct hlist_head services[TIPC_NAMETBL_SIZE];  	struct list_head node_scope;  	struct list_head cluster_scope; +	rwlock_t cluster_scope_lock;  	u32 local_publ_count;  }; diff --git a/net/tipc/node.h b/net/tipc/node.h index 48b3298a248d..03f5efb62cfb 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -45,6 +45,7 @@  /* Optional capabilities supported by this code version   */  enum { +	TIPC_SYN_BIT          = (1),  	TIPC_BCAST_SYNCH      = (1 << 1),  	TIPC_BCAST_STATE_NACK = (1 << 2),  	TIPC_BLOCK_FLOWCTL    = (1 << 3), @@ -53,11 +54,12 @@ enum {  	TIPC_LINK_PROTO_SEQNO = (1 << 6)  }; -#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH       |  \ -				TIPC_BCAST_STATE_NACK  |  \ -				TIPC_BCAST_RCAST       |  \ -				TIPC_BLOCK_FLOWCTL     |  \ -				TIPC_NODE_ID128        |  \ +#define TIPC_NODE_CAPABILITIES (TIPC_SYN_BIT           |  \ +				TIPC_BCAST_SYNCH       |   \ +				TIPC_BCAST_STATE_NACK  |   \ +				TIPC_BCAST_RCAST       |   \ +				TIPC_BLOCK_FLOWCTL     |   \ +				TIPC_NODE_ID128        |   \  				TIPC_LINK_PROTO_SEQNO)  #define INVALID_BEARER_ID -1 diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 49810fdff4c5..636e6131769d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -47,7 +47,7 @@  #include "netlink.h"  #include "group.h" -#define CONN_TIMEOUT_DEFAULT	8000	/* default connect timeout = 8s */ +#define CONN_TIMEOUT_DEFAULT    8000    /* default connect timeout = 8s */  #define CONN_PROBING_INTV	msecs_to_jiffies(3600000)  /* [ms] => 1 h */  #define TIPC_FWD_MSG		1  #define TIPC_MAX_PORT		0xffffffff @@ -80,7 +80,6 @@ struct sockaddr_pair {   * @publications: list of publications for port   * @blocking_link: address of the congested link we are currently sleeping on   * @pub_count: total # of publications port has made during its lifetime - * @probing_state:   * @conn_timeout: the time we can wait for an unresponded setup request   * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue   * @cong_link_cnt: number of congested links @@ -102,8 +101,8 @@ struct tipc_sock {  	struct list_head cong_links;  	struct list_head publications;  	u32 pub_count; -	uint conn_timeout;  	atomic_t dupl_rcvcnt; +	u16 conn_timeout;  	bool probe_unacked;  	u16 cong_link_cnt;  	u16 snt_unacked; @@ -507,6 +506,9 @@ static void __tipc_shutdown(struct socket *sock, int error)  	tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt &&  					    !tsk_conn_cong(tsk))); +	/* Remove any pending SYN message */ +	__skb_queue_purge(&sk->sk_write_queue); +  	/* Reject all unreceived messages, except on an active connection  	 * (which disconnects locally & sends a 'FIN+' to peer).  	 */ @@ -715,7 +717,7 @@ static __poll_t tipc_poll(struct file *file, struct socket *sock,  	struct tipc_sock *tsk = tipc_sk(sk);  	__poll_t revents = 0; -	sock_poll_wait(file, wait); +	sock_poll_wait(file, sock, wait);  	if (sk->sk_shutdown & RCV_SHUTDOWN)  		revents |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; @@ -1329,6 +1331,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  			tsk->conn_type = dest->addr.name.name.type;  			tsk->conn_instance = dest->addr.name.name.instance;  		} +		msg_set_syn(hdr, 1);  	}  	seq = &dest->addr.nameseq; @@ -1371,6 +1374,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  	rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);  	if (unlikely(rc != dlen))  		return rc; +	if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue))) +		return -ENOMEM;  	rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);  	if (unlikely(rc == -ELINKCONG)) { @@ -1490,6 +1495,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,  	struct net *net = sock_net(sk);  	struct tipc_msg *msg = &tsk->phdr; +	msg_set_syn(msg, 0);  	msg_set_destnode(msg, peer_node);  	msg_set_destport(msg, peer_port);  	msg_set_type(msg, TIPC_CONN_MSG); @@ -1501,6 +1507,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,  	tipc_node_add_conn(net, peer_node, tsk->portid, peer_port);  	tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid);  	tsk->peer_caps = tipc_node_get_capabilities(net, peer_node); +	__skb_queue_purge(&sk->sk_write_queue);  	if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL)  		return; @@ -1971,91 +1978,90 @@ static void tipc_sk_proto_rcv(struct sock *sk,  }  /** - * tipc_filter_connect - Handle incoming message for a connection-based socket + * tipc_sk_filter_connect - check incoming message for a connection-based socket   * @tsk: TIPC socket - * @skb: pointer to message buffer. Set to NULL if buffer is consumed - * - * Returns true if everything ok, false otherwise + * @skb: pointer to message buffer. + * 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)  {  	struct sock *sk = &tsk->sk;  	struct net *net = sock_net(sk);  	struct tipc_msg *hdr = buf_msg(skb); -	u32 pport = msg_origport(hdr); -	u32 pnode = msg_orignode(hdr); +	bool con_msg = msg_connected(hdr); +	u32 pport = tsk_peer_port(tsk); +	u32 pnode = tsk_peer_node(tsk); +	u32 oport = msg_origport(hdr); +	u32 onode = msg_orignode(hdr); +	int err = msg_errcode(hdr); +	unsigned long delay;  	if (unlikely(msg_mcast(hdr)))  		return false;  	switch (sk->sk_state) {  	case TIPC_CONNECTING: -		/* Accept only ACK or NACK message */ -		if (unlikely(!msg_connected(hdr))) { -			if (pport != tsk_peer_port(tsk) || -			    pnode != tsk_peer_node(tsk)) -				return false; - -			tipc_set_sk_state(sk, TIPC_DISCONNECTING); -			sk->sk_err = ECONNREFUSED; -			sk->sk_state_change(sk); -			return true; -		} - -		if (unlikely(msg_errcode(hdr))) { -			tipc_set_sk_state(sk, TIPC_DISCONNECTING); -			sk->sk_err = ECONNREFUSED; -			sk->sk_state_change(sk); -			return true; -		} - -		if (unlikely(!msg_isdata(hdr))) { -			tipc_set_sk_state(sk, TIPC_DISCONNECTING); -			sk->sk_err = EINVAL; -			sk->sk_state_change(sk); -			return true; +		/* Setup ACK */ +		if (likely(con_msg)) { +			if (err) +				break; +			tipc_sk_finish_conn(tsk, oport, onode); +			msg_set_importance(&tsk->phdr, msg_importance(hdr)); +			/* ACK+ message with data is added to receive queue */ +			if (msg_data_sz(hdr)) +				return true; +			/* Empty ACK-, - wake up sleeping connect() and drop */ +			sk->sk_data_ready(sk); +			msg_set_dest_droppable(hdr, 1); +			return false;  		} +		/* Ignore connectionless message if not from listening socket */ +		if (oport != pport || onode != pnode) +			return false; -		tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr)); -		msg_set_importance(&tsk->phdr, msg_importance(hdr)); - -		/* If 'ACK+' message, add to socket receive queue */ -		if (msg_data_sz(hdr)) -			return true; - -		/* If empty 'ACK-' message, wake up sleeping connect() */ -		sk->sk_data_ready(sk); +		/* Rejected SYN */ +		if (err != TIPC_ERR_OVERLOAD) +			break; -		/* 'ACK-' message is neither accepted nor rejected: */ -		msg_set_dest_droppable(hdr, 1); +		/* Prepare for new setup attempt if we have a SYN clone */ +		if (skb_queue_empty(&sk->sk_write_queue)) +			break; +		get_random_bytes(&delay, 2); +		delay %= (tsk->conn_timeout / 4); +		delay = msecs_to_jiffies(delay + 100); +		sk_reset_timer(sk, &sk->sk_timer, jiffies + delay);  		return false; -  	case TIPC_OPEN:  	case TIPC_DISCONNECTING: -		break; +		return false;  	case TIPC_LISTEN:  		/* Accept only SYN message */ -		if (!msg_connected(hdr) && !(msg_errcode(hdr))) +		if (!msg_is_syn(hdr) && +		    tipc_node_get_capabilities(net, onode) & TIPC_SYN_BIT) +			return false; +		if (!con_msg && !err)  			return true; -		break; +		return false;  	case TIPC_ESTABLISHED:  		/* Accept only connection-based messages sent by peer */ -		if (unlikely(!tsk_peer_msg(tsk, hdr))) +		if (likely(con_msg && !err && pport == oport && pnode == onode)) +			return true; +		if (!tsk_peer_msg(tsk, hdr))  			return false; - -		if (unlikely(msg_errcode(hdr))) { -			tipc_set_sk_state(sk, TIPC_DISCONNECTING); -			/* Let timer expire on it's own */ -			tipc_node_remove_conn(net, tsk_peer_node(tsk), -					      tsk->portid); -			sk->sk_state_change(sk); -		} +		if (!err) +			return true; +		tipc_set_sk_state(sk, TIPC_DISCONNECTING); +		tipc_node_remove_conn(net, pnode, tsk->portid); +		sk->sk_state_change(sk);  		return true;  	default:  		pr_err("Unknown sk_state %u\n", sk->sk_state);  	} - -	return false; +	/* Abort connection setup attempt */ +	tipc_set_sk_state(sk, TIPC_DISCONNECTING); +	sk->sk_err = ECONNREFUSED; +	sk->sk_state_change(sk); +	return true;  }  /** @@ -2557,43 +2563,78 @@ static int tipc_shutdown(struct socket *sock, int how)  	return res;  } +static void tipc_sk_check_probing_state(struct sock *sk, +					struct sk_buff_head *list) +{ +	struct tipc_sock *tsk = tipc_sk(sk); +	u32 pnode = tsk_peer_node(tsk); +	u32 pport = tsk_peer_port(tsk); +	u32 self = tsk_own_node(tsk); +	u32 oport = tsk->portid; +	struct sk_buff *skb; + +	if (tsk->probe_unacked) { +		tipc_set_sk_state(sk, TIPC_DISCONNECTING); +		sk->sk_err = ECONNABORTED; +		tipc_node_remove_conn(sock_net(sk), pnode, pport); +		sk->sk_state_change(sk); +		return; +	} +	/* Prepare new probe */ +	skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE, 0, +			      pnode, self, pport, oport, TIPC_OK); +	if (skb) +		__skb_queue_tail(list, skb); +	tsk->probe_unacked = true; +	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); +} + +static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) +{ +	struct tipc_sock *tsk = tipc_sk(sk); + +	/* Try again later if dest link is congested */ +	if (tsk->cong_link_cnt) { +		sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); +		return; +	} +	/* Prepare SYN for retransmit */ +	tipc_msg_skb_clone(&sk->sk_write_queue, list); +} +  static void tipc_sk_timeout(struct timer_list *t)  {  	struct sock *sk = from_timer(sk, t, sk_timer);  	struct tipc_sock *tsk = tipc_sk(sk); -	u32 peer_port = tsk_peer_port(tsk); -	u32 peer_node = tsk_peer_node(tsk); -	u32 own_node = tsk_own_node(tsk); -	u32 own_port = tsk->portid; -	struct net *net = sock_net(sk); -	struct sk_buff *skb = NULL; +	u32 pnode = tsk_peer_node(tsk); +	struct sk_buff_head list; +	int rc = 0; +	skb_queue_head_init(&list);  	bh_lock_sock(sk); -	if (!tipc_sk_connected(sk)) -		goto exit;  	/* Try again later if socket is busy */  	if (sock_owned_by_user(sk)) {  		sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 20); -		goto exit; +		bh_unlock_sock(sk); +		return;  	} -	if (tsk->probe_unacked) { -		tipc_set_sk_state(sk, TIPC_DISCONNECTING); -		tipc_node_remove_conn(net, peer_node, peer_port); -		sk->sk_state_change(sk); -		goto exit; -	} -	/* Send new probe */ -	skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE, 0, -			      peer_node, own_node, peer_port, own_port, -			      TIPC_OK); -	tsk->probe_unacked = true; -	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); -exit: +	if (sk->sk_state == TIPC_ESTABLISHED) +		tipc_sk_check_probing_state(sk, &list); +	else if (sk->sk_state == TIPC_CONNECTING) +		tipc_sk_retry_connect(sk, &list); +  	bh_unlock_sock(sk); -	if (skb) -		tipc_node_xmit_skb(net, skb, peer_node, own_port); + +	if (!skb_queue_empty(&list)) +		rc = tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); + +	/* SYN messages may cause link congestion */ +	if (rc == -ELINKCONG) { +		tipc_dest_push(&tsk->cong_links, pnode, 0); +		tsk->cong_link_cnt = 1; +	}  	sock_put(sk);  } diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index 2627b5d812e9..4bdea0057171 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c @@ -57,16 +57,12 @@   * @idr_lock: protect the connection identifier set   * @idr_in_use: amount of allocated identifier entry   * @net: network namspace instance - * @rcvbuf_cache: memory cache of server receive buffer + * @awork: accept work item   * @rcv_wq: receive workqueue   * @send_wq: send workqueue   * @max_rcvbuf_size: maximum permitted receive message length - * @tipc_conn_new: callback will be called when new connection is incoming - * @tipc_conn_release: callback will be called before releasing the connection - * @tipc_conn_recvmsg: callback will be called when message arrives + * @listener: topsrv listener socket   * @name: server name - * @imp: message importance - * @type: socket type   */  struct tipc_topsrv {  	struct idr conn_idr; @@ -90,9 +86,7 @@ struct tipc_topsrv {   * @server: pointer to connected server   * @sub_list: lsit to all pertaing subscriptions   * @sub_lock: lock protecting the subscription list - * @outqueue_lock: control access to the outqueue   * @rwork: receive work item - * @rx_action: what to do when connection socket is active   * @outqueue: pointer to first outbound message in queue   * @outqueue_lock: control access to the outqueue   * @swork: send work item @@ -657,7 +651,7 @@ int tipc_topsrv_start(struct net *net)  	srv->max_rcvbuf_size = sizeof(struct tipc_subscr);  	INIT_WORK(&srv->awork, tipc_topsrv_accept); -	strncpy(srv->name, name, strlen(name) + 1); +	strscpy(srv->name, name, sizeof(srv->name));  	tn->topsrv = srv;  	atomic_set(&tn->subscription_count, 0); diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 9783101bc4a9..10dc59ce9c82 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -650,6 +650,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	struct udp_tunnel_sock_cfg tuncfg = {NULL};  	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];  	u8 node_id[NODE_ID_LEN] = {0,}; +	int rmcast = 0;  	ub = kzalloc(sizeof(*ub), GFP_ATOMIC);  	if (!ub) @@ -680,6 +681,9 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	if (err)  		goto err; +	/* Checking remote ip address */ +	rmcast = tipc_udp_is_mcast_addr(&remote); +  	/* Autoconfigure own node identity if needed */  	if (!tipc_own_id(net)) {  		memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16); @@ -705,7 +709,12 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  			goto err;  		}  		udp_conf.family = AF_INET; -		udp_conf.local_ip.s_addr = htonl(INADDR_ANY); + +		/* Switch to use ANY to receive packets from group */ +		if (rmcast) +			udp_conf.local_ip.s_addr = htonl(INADDR_ANY); +		else +			udp_conf.local_ip.s_addr = local.ipv4.s_addr;  		udp_conf.use_udp_checksums = false;  		ub->ifindex = dev->ifindex;  		if (tipc_mtu_bad(dev, sizeof(struct iphdr) + @@ -719,7 +728,10 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  		udp_conf.family = AF_INET6;  		udp_conf.use_udp6_tx_checksums = true;  		udp_conf.use_udp6_rx_checksums = true; -		udp_conf.local_ip6 = in6addr_any; +		if (rmcast) +			udp_conf.local_ip6 = in6addr_any; +		else +			udp_conf.local_ip6 = local.ipv6;  		b->mtu = 1280;  #endif  	} else { @@ -741,7 +753,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	 * is used if it's a multicast address.  	 */  	memcpy(&b->bcast_addr.value, &remote, sizeof(remote)); -	if (tipc_udp_is_mcast_addr(&remote)) +	if (rmcast)  		err = enable_mcast(ub, &remote);  	else  		err = tipc_udp_rcast_add(b, &remote); |