diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 89 | 
1 files changed, 52 insertions, 37 deletions
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));  | 
