diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/Makefile | 4 | ||||
| -rw-r--r-- | net/tipc/bcast.c | 24 | ||||
| -rw-r--r-- | net/tipc/discover.c | 6 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 279 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 4 | ||||
| -rw-r--r-- | net/tipc/socket.c | 89 | 
6 files changed, 252 insertions, 154 deletions
diff --git a/net/tipc/Makefile b/net/tipc/Makefile index 11255e970dd4..ee49a9f1dd4f 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile @@ -9,7 +9,7 @@ tipc-y	+= addr.o bcast.o bearer.o \  	   core.o link.o discover.o msg.o  \  	   name_distr.o  subscr.o monitor.o name_table.o net.o  \  	   netlink.o netlink_compat.o node.o socket.o eth_media.o \ -	   topsrv.o socket.o group.o trace.o +	   topsrv.o group.o trace.o  CFLAGS_trace.o += -I$(src) @@ -20,5 +20,3 @@ tipc-$(CONFIG_TIPC_CRYPTO)	+= crypto.o  obj-$(CONFIG_TIPC_DIAG)	+= diag.o - -tipc_diag-y	:= diag.o diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 55aeba681cf4..656ebc79c64e 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -305,17 +305,17 @@ static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,   * @skb: socket buffer to copy   * @method: send method to be used   * @dests: destination nodes for message. - * @cong_link_cnt: returns number of encountered congested destination links   * Returns 0 if success, otherwise errno   */  static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb,  				struct tipc_mc_method *method, -				struct tipc_nlist *dests, -				u16 *cong_link_cnt) +				struct tipc_nlist *dests)  {  	struct tipc_msg *hdr, *_hdr;  	struct sk_buff_head tmpq;  	struct sk_buff *_skb; +	u16 cong_link_cnt; +	int rc = 0;  	/* Is a cluster supporting with new capabilities ? */  	if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL)) @@ -343,18 +343,19 @@ static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb,  	_hdr = buf_msg(_skb);  	msg_set_size(_hdr, MCAST_H_SIZE);  	msg_set_is_rcast(_hdr, !msg_is_rcast(hdr)); +	msg_set_errcode(_hdr, TIPC_ERR_NO_PORT);  	__skb_queue_head_init(&tmpq);  	__skb_queue_tail(&tmpq, _skb);  	if (method->rcast) -		tipc_bcast_xmit(net, &tmpq, cong_link_cnt); +		rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt);  	else -		tipc_rcast_xmit(net, &tmpq, dests, cong_link_cnt); +		rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt);  	/* This queue should normally be empty by now */  	__skb_queue_purge(&tmpq); -	return 0; +	return rc;  }  /* tipc_mcast_xmit - deliver message to indicated destination nodes @@ -396,9 +397,14 @@ int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,  		msg_set_is_rcast(hdr, method->rcast);  		/* Switch method ? */ -		if (rcast != method->rcast) -			tipc_mcast_send_sync(net, skb, method, -					     dests, cong_link_cnt); +		if (rcast != method->rcast) { +			rc = tipc_mcast_send_sync(net, skb, method, dests); +			if (unlikely(rc)) { +				pr_err("Unable to send SYN: method %d, rc %d\n", +				       rcast, rc); +				goto exit; +			} +		}  		if (method->rcast)  			rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt); diff --git a/net/tipc/discover.c b/net/tipc/discover.c index b043e8c6397a..bfe43da127c0 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -194,6 +194,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,  {  	struct tipc_net *tn = tipc_net(net);  	struct tipc_msg *hdr = buf_msg(skb); +	u32 pnet_hash = msg_peer_net_hash(hdr);  	u16 caps = msg_node_capabilities(hdr);  	bool legacy = tn->legacy_addr_format;  	u32 sugg = msg_sugg_node_addr(hdr); @@ -242,9 +243,8 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,  		return;  	if (!tipc_in_scope(legacy, b->domain, src))  		return; -	tipc_node_check_dest(net, src, peer_id, b, caps, signature, -			     msg_peer_net_hash(hdr), &maddr, &respond, -			     &dupl_addr); +	tipc_node_check_dest(net, src, peer_id, b, caps, signature, pnet_hash, +			     &maddr, &respond, &dupl_addr);  	if (dupl_addr)  		disc_dupl_alert(b, src, &maddr);  	if (!respond) diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 92d04dc2a44b..359b2bc888cf 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -36,6 +36,7 @@  #include <net/sock.h>  #include <linux/list_sort.h> +#include <linux/rbtree_augmented.h>  #include "core.h"  #include "netlink.h"  #include "name_table.h" @@ -51,6 +52,7 @@   * @lower: service range lower bound   * @upper: service range upper bound   * @tree_node: member of service range RB tree + * @max: largest 'upper' in this node subtree   * @local_publ: list of identical publications made from this node   *   Used by closest_first lookup and multicast lookup algorithm   * @all_publ: all publications identical to this one, whatever node and scope @@ -60,6 +62,7 @@ struct service_range {  	u32 lower;  	u32 upper;  	struct rb_node tree_node; +	u32 max;  	struct list_head local_publ;  	struct list_head all_publ;  }; @@ -84,6 +87,130 @@ struct tipc_service {  	struct rcu_head rcu;  }; +#define service_range_upper(sr) ((sr)->upper) +RB_DECLARE_CALLBACKS_MAX(static, sr_callbacks, +			 struct service_range, tree_node, u32, max, +			 service_range_upper) + +#define service_range_entry(rbtree_node)				\ +	(container_of(rbtree_node, struct service_range, tree_node)) + +#define service_range_overlap(sr, start, end)				\ +	((sr)->lower <= (end) && (sr)->upper >= (start)) + +/** + * service_range_foreach_match - iterate over tipc service rbtree for each + *                               range match + * @sr: the service range pointer as a loop cursor + * @sc: the pointer to tipc service which holds the service range rbtree + * @start, end: the range (end >= start) for matching + */ +#define service_range_foreach_match(sr, sc, start, end)			\ +	for (sr = service_range_match_first((sc)->ranges.rb_node,	\ +					    start,			\ +					    end);			\ +	     sr;							\ +	     sr = service_range_match_next(&(sr)->tree_node,		\ +					   start,			\ +					   end)) + +/** + * service_range_match_first - find first service range matching a range + * @n: the root node of service range rbtree for searching + * @start, end: the range (end >= start) for matching + * + * Return: the leftmost service range node in the rbtree that overlaps the + * specific range if any. Otherwise, returns NULL. + */ +static struct service_range *service_range_match_first(struct rb_node *n, +						       u32 start, u32 end) +{ +	struct service_range *sr; +	struct rb_node *l, *r; + +	/* Non overlaps in tree at all? */ +	if (!n || service_range_entry(n)->max < start) +		return NULL; + +	while (n) { +		l = n->rb_left; +		if (l && service_range_entry(l)->max >= start) { +			/* A leftmost overlap range node must be one in the left +			 * subtree. If not, it has lower > end, then nodes on +			 * the right side cannot satisfy the condition either. +			 */ +			n = l; +			continue; +		} + +		/* No one in the left subtree can match, return if this node is +		 * an overlap i.e. leftmost. +		 */ +		sr = service_range_entry(n); +		if (service_range_overlap(sr, start, end)) +			return sr; + +		/* Ok, try to lookup on the right side */ +		r = n->rb_right; +		if (sr->lower <= end && +		    r && service_range_entry(r)->max >= start) { +			n = r; +			continue; +		} +		break; +	} + +	return NULL; +} + +/** + * service_range_match_next - find next service range matching a range + * @n: a node in service range rbtree from which the searching starts + * @start, end: the range (end >= start) for matching + * + * Return: the next service range node to the given node in the rbtree that + * overlaps the specific range if any. Otherwise, returns NULL. + */ +static struct service_range *service_range_match_next(struct rb_node *n, +						      u32 start, u32 end) +{ +	struct service_range *sr; +	struct rb_node *p, *r; + +	while (n) { +		r = n->rb_right; +		if (r && service_range_entry(r)->max >= start) +			/* A next overlap range node must be one in the right +			 * subtree. If not, it has lower > end, then any next +			 * successor (- an ancestor) of this node cannot +			 * satisfy the condition either. +			 */ +			return service_range_match_first(r, start, end); + +		/* No one in the right subtree can match, go up to find an +		 * ancestor of this node which is parent of a left-hand child. +		 */ +		while ((p = rb_parent(n)) && n == p->rb_right) +			n = p; +		if (!p) +			break; + +		/* Return if this ancestor is an overlap */ +		sr = service_range_entry(p); +		if (service_range_overlap(sr, start, end)) +			return sr; + +		/* Ok, try to lookup more from this ancestor */ +		if (sr->lower <= end) { +			n = p; +			continue; +		} +		break; +	} + +	return NULL; +} +  static int hash(int x)  {  	return x & (TIPC_NAMETBL_SIZE - 1); @@ -139,84 +266,51 @@ static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)  	return service;  } -/** - * tipc_service_first_range - find first service range in tree matching instance - * - * Very time-critical, so binary search through range rb tree - */ -static struct service_range *tipc_service_first_range(struct tipc_service *sc, -						      u32 instance) -{ -	struct rb_node *n = sc->ranges.rb_node; -	struct service_range *sr; - -	while (n) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->lower > instance) -			n = n->rb_left; -		else if (sr->upper < instance) -			n = n->rb_right; -		else -			return sr; -	} -	return NULL; -} -  /*  tipc_service_find_range - find service range matching publication parameters   */  static struct service_range *tipc_service_find_range(struct tipc_service *sc,  						     u32 lower, u32 upper)  { -	struct rb_node *n = sc->ranges.rb_node;  	struct service_range *sr; -	sr = tipc_service_first_range(sc, lower); -	if (!sr) -		return NULL; - -	/* Look for exact match */ -	for (n = &sr->tree_node; n; n = rb_next(n)) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->upper == upper) -			break; +	service_range_foreach_match(sr, sc, lower, upper) { +		/* Look for exact match */ +		if (sr->lower == lower && sr->upper == upper) +			return sr;  	} -	if (!n || sr->lower != lower || sr->upper != upper) -		return NULL; -	return sr; +	return NULL;  }  static struct service_range *tipc_service_create_range(struct tipc_service *sc,  						       u32 lower, u32 upper)  {  	struct rb_node **n, *parent = NULL; -	struct service_range *sr, *tmp; +	struct service_range *sr;  	n = &sc->ranges.rb_node;  	while (*n) { -		tmp = container_of(*n, struct service_range, tree_node);  		parent = *n; -		tmp = container_of(parent, struct service_range, tree_node); -		if (lower < tmp->lower) -			n = &(*n)->rb_left; -		else if (lower > tmp->lower) -			n = &(*n)->rb_right; -		else if (upper < tmp->upper) -			n = &(*n)->rb_left; -		else if (upper > tmp->upper) -			n = &(*n)->rb_right; +		sr = service_range_entry(parent); +		if (lower == sr->lower && upper == sr->upper) +			return sr; +		if (sr->max < upper) +			sr->max = upper; +		if (lower <= sr->lower) +			n = &parent->rb_left;  		else -			return tmp; +			n = &parent->rb_right;  	}  	sr = kzalloc(sizeof(*sr), GFP_ATOMIC);  	if (!sr)  		return NULL;  	sr->lower = lower;  	sr->upper = upper; +	sr->max = upper;  	INIT_LIST_HEAD(&sr->local_publ);  	INIT_LIST_HEAD(&sr->all_publ);  	rb_link_node(&sr->tree_node, parent, n); -	rb_insert_color(&sr->tree_node, &sc->ranges); +	rb_insert_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);  	return sr;  } @@ -310,7 +404,6 @@ static void tipc_service_subscribe(struct tipc_service *service,  	struct list_head publ_list;  	struct service_range *sr;  	struct tipc_name_seq ns; -	struct rb_node *n;  	u32 filter;  	ns.type = tipc_sub_read(sb, seq.type); @@ -325,13 +418,7 @@ static void tipc_service_subscribe(struct tipc_service *service,  		return;  	INIT_LIST_HEAD(&publ_list); -	for (n = rb_first(&service->ranges); n; n = rb_next(n)) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->lower > ns.upper) -			break; -		if (!tipc_sub_check_overlap(&ns, sr->lower, sr->upper)) -			continue; - +	service_range_foreach_match(sr, service, ns.lower, ns.upper) {  		first = NULL;  		list_for_each_entry(p, &sr->all_publ, all_publ) {  			if (filter & TIPC_SUB_PORTS) @@ -425,7 +512,7 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,  	/* Remove service range item if this was its last publication */  	if (list_empty(&sr->all_publ)) { -		rb_erase(&sr->tree_node, &sc->ranges); +		rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);  		kfree(sr);  	} @@ -473,34 +560,39 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)  	rcu_read_lock();  	sc = tipc_service_find(net, type);  	if (unlikely(!sc)) -		goto not_found; +		goto exit;  	spin_lock_bh(&sc->lock); -	sr = tipc_service_first_range(sc, instance); -	if (unlikely(!sr)) -		goto no_match; - -	/* Select lookup algorithm: local, closest-first or round-robin */ -	if (*dnode == self) { -		list = &sr->local_publ; -		if (list_empty(list)) -			goto no_match; -		p = list_first_entry(list, struct publication, local_publ); -		list_move_tail(&p->local_publ, &sr->local_publ); -	} else if (legacy && !*dnode && !list_empty(&sr->local_publ)) { -		list = &sr->local_publ; -		p = list_first_entry(list, struct publication, local_publ); -		list_move_tail(&p->local_publ, &sr->local_publ); -	} else { -		list = &sr->all_publ; -		p = list_first_entry(list, struct publication, all_publ); -		list_move_tail(&p->all_publ, &sr->all_publ); +	service_range_foreach_match(sr, sc, instance, instance) { +		/* Select lookup algo: local, closest-first or round-robin */ +		if (*dnode == self) { +			list = &sr->local_publ; +			if (list_empty(list)) +				continue; +			p = list_first_entry(list, struct publication, +					     local_publ); +			list_move_tail(&p->local_publ, &sr->local_publ); +		} else if (legacy && !*dnode && !list_empty(&sr->local_publ)) { +			list = &sr->local_publ; +			p = list_first_entry(list, struct publication, +					     local_publ); +			list_move_tail(&p->local_publ, &sr->local_publ); +		} else { +			list = &sr->all_publ; +			p = list_first_entry(list, struct publication, +					     all_publ); +			list_move_tail(&p->all_publ, &sr->all_publ); +		} +		port = p->port; +		node = p->node; +		/* Todo: as for legacy, pick the first matching range only, a +		 * "true" round-robin will be performed as needed. +		 */ +		break;  	} -	port = p->port; -	node = p->node; -no_match:  	spin_unlock_bh(&sc->lock); -not_found: + +exit:  	rcu_read_unlock();  	*dnode = node;  	return port; @@ -523,7 +615,8 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,  	spin_lock_bh(&sc->lock); -	sr = tipc_service_first_range(sc, instance); +	/* Todo: a full search i.e. service_range_foreach_match() instead? */ +	sr = service_range_match_first(sc->ranges.rb_node, instance, instance);  	if (!sr)  		goto no_match; @@ -552,7 +645,6 @@ void tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper,  	struct service_range *sr;  	struct tipc_service *sc;  	struct publication *p; -	struct rb_node *n;  	rcu_read_lock();  	sc = tipc_service_find(net, type); @@ -560,13 +652,7 @@ void tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper,  		goto exit;  	spin_lock_bh(&sc->lock); - -	for (n = rb_first(&sc->ranges); n; n = rb_next(n)) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->upper < lower) -			continue; -		if (sr->lower > upper) -			break; +	service_range_foreach_match(sr, sc, lower, upper) {  		list_for_each_entry(p, &sr->local_publ, local_publ) {  			if (p->scope == scope || (!exact && p->scope < scope))  				tipc_dest_push(dports, 0, p->port); @@ -587,7 +673,6 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,  	struct service_range *sr;  	struct tipc_service *sc;  	struct publication *p; -	struct rb_node *n;  	rcu_read_lock();  	sc = tipc_service_find(net, type); @@ -595,13 +680,7 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,  		goto exit;  	spin_lock_bh(&sc->lock); - -	for (n = rb_first(&sc->ranges); n; n = rb_next(n)) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->upper < lower) -			continue; -		if (sr->lower > upper) -			break; +	service_range_foreach_match(sr, sc, lower, upper) {  		list_for_each_entry(p, &sr->all_publ, all_publ) {  			tipc_nlist_add(nodes, p->node);  		} @@ -799,7 +878,7 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)  			tipc_service_remove_publ(sr, p->node, p->key);  			kfree_rcu(p, rcu);  		} -		rb_erase(&sr->tree_node, &sc->ranges); +		rb_erase_augmented(&sr->tree_node, &sc->ranges, &sr_callbacks);  		kfree(sr);  	}  	hlist_del_init_rcu(&sc->service_list); diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 0254bb7e418b..217516357ef2 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -204,8 +204,8 @@ static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,  		return -ENOMEM;  	} -	attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1, -				sizeof(struct nlattr *), GFP_KERNEL); +	attrbuf = kcalloc(tipc_genl_family.maxattr + 1, +			  sizeof(struct nlattr *), GFP_KERNEL);  	if (!attrbuf) {  		err = -ENOMEM;  		goto err_out; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 41688da233ab..f9b4fb92c0b1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -287,12 +287,12 @@ static void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err)   *   * Caller must hold socket lock   */ -static void tsk_rej_rx_queue(struct sock *sk) +static void tsk_rej_rx_queue(struct sock *sk, int error)  {  	struct sk_buff *skb;  	while ((skb = __skb_dequeue(&sk->sk_receive_queue))) -		tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); +		tipc_sk_respond(sk, skb, error);  }  static bool tipc_sk_connected(struct sock *sk) @@ -545,34 +545,45 @@ static void __tipc_shutdown(struct socket *sock, int error)  	/* Remove pending SYN */  	__skb_queue_purge(&sk->sk_write_queue); -	/* Reject all unreceived messages, except on an active connection -	 * (which disconnects locally & sends a 'FIN+' to peer). -	 */ -	while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { -		if (TIPC_SKB_CB(skb)->bytes_read) { -			kfree_skb(skb); -			continue; -		} -		if (!tipc_sk_type_connectionless(sk) && -		    sk->sk_state != TIPC_DISCONNECTING) { -			tipc_set_sk_state(sk, TIPC_DISCONNECTING); -			tipc_node_remove_conn(net, dnode, tsk->portid); -		} -		tipc_sk_respond(sk, skb, error); +	/* Remove partially received buffer if any */ +	skb = skb_peek(&sk->sk_receive_queue); +	if (skb && TIPC_SKB_CB(skb)->bytes_read) { +		__skb_unlink(skb, &sk->sk_receive_queue); +		kfree_skb(skb);  	} -	if (tipc_sk_type_connectionless(sk)) +	/* Reject all unreceived messages if connectionless */ +	if (tipc_sk_type_connectionless(sk)) { +		tsk_rej_rx_queue(sk, error);  		return; +	} -	if (sk->sk_state != TIPC_DISCONNECTING) { +	switch (sk->sk_state) { +	case TIPC_CONNECTING: +	case TIPC_ESTABLISHED: +		tipc_set_sk_state(sk, TIPC_DISCONNECTING); +		tipc_node_remove_conn(net, dnode, tsk->portid); +		/* Send a FIN+/- to its peer */ +		skb = __skb_dequeue(&sk->sk_receive_queue); +		if (skb) { +			__skb_queue_purge(&sk->sk_receive_queue); +			tipc_sk_respond(sk, skb, error); +			break; +		}  		skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,  				      TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode,  				      tsk_own_node(tsk), tsk_peer_port(tsk),  				      tsk->portid, error);  		if (skb)  			tipc_node_xmit_skb(net, skb, dnode, tsk->portid); -		tipc_node_remove_conn(net, dnode, tsk->portid); -		tipc_set_sk_state(sk, TIPC_DISCONNECTING); +		break; +	case TIPC_LISTEN: +		/* Reject all SYN messages */ +		tsk_rej_rx_queue(sk, error); +		break; +	default: +		__skb_queue_purge(&sk->sk_receive_queue); +		break;  	}  } @@ -1364,8 +1375,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  	struct tipc_msg *hdr = &tsk->phdr;  	struct tipc_name_seq *seq;  	struct sk_buff_head pkts; -	u32 dport, dnode = 0; -	u32 type, inst; +	u32 dport = 0, dnode = 0; +	u32 type = 0, inst = 0;  	int mtu, rc;  	if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE)) @@ -1418,23 +1429,11 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  		type = dest->addr.name.name.type;  		inst = dest->addr.name.name.instance;  		dnode = dest->addr.name.domain; -		msg_set_type(hdr, TIPC_NAMED_MSG); -		msg_set_hdr_sz(hdr, NAMED_H_SIZE); -		msg_set_nametype(hdr, type); -		msg_set_nameinst(hdr, inst); -		msg_set_lookup_scope(hdr, tipc_node2scope(dnode));  		dport = tipc_nametbl_translate(net, type, inst, &dnode); -		msg_set_destnode(hdr, dnode); -		msg_set_destport(hdr, dport);  		if (unlikely(!dport && !dnode))  			return -EHOSTUNREACH;  	} else if (dest->addrtype == TIPC_ADDR_ID) {  		dnode = dest->addr.id.node; -		msg_set_type(hdr, TIPC_DIRECT_MSG); -		msg_set_lookup_scope(hdr, 0); -		msg_set_destnode(hdr, dnode); -		msg_set_destport(hdr, dest->addr.id.ref); -		msg_set_hdr_sz(hdr, BASIC_H_SIZE);  	} else {  		return -EINVAL;  	} @@ -1445,6 +1444,22 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)  	if (unlikely(rc))  		return rc; +	if (dest->addrtype == TIPC_ADDR_NAME) { +		msg_set_type(hdr, TIPC_NAMED_MSG); +		msg_set_hdr_sz(hdr, NAMED_H_SIZE); +		msg_set_nametype(hdr, type); +		msg_set_nameinst(hdr, inst); +		msg_set_lookup_scope(hdr, tipc_node2scope(dnode)); +		msg_set_destnode(hdr, dnode); +		msg_set_destport(hdr, dport); +	} else { /* TIPC_ADDR_ID */ +		msg_set_type(hdr, TIPC_DIRECT_MSG); +		msg_set_lookup_scope(hdr, 0); +		msg_set_destnode(hdr, dnode); +		msg_set_destport(hdr, dest->addr.id.ref); +		msg_set_hdr_sz(hdr, BASIC_H_SIZE); +	} +  	__skb_queue_head_init(&pkts);  	mtu = tipc_node_get_mtu(net, dnode, tsk->portid, false);  	rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts); @@ -2428,8 +2443,8 @@ static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)  			return sock_intr_errno(*timeo_p);  		add_wait_queue(sk_sleep(sk), &wait); -		done = sk_wait_event(sk, timeo_p, -				     sk->sk_state != TIPC_CONNECTING, &wait); +		done = sk_wait_event(sk, timeo_p, tipc_sk_connected(sk), +				     &wait);  		remove_wait_queue(sk_sleep(sk), &wait);  	} while (!done);  	return 0; @@ -2639,7 +2654,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,  	 * Reject any stray messages received by new socket  	 * before the socket lock was taken (very, very unlikely)  	 */ -	tsk_rej_rx_queue(new_sk); +	tsk_rej_rx_queue(new_sk, TIPC_ERR_NO_PORT);  	/* Connect new socket to it's peer */  	tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg));  | 
