diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 57 | 
1 files changed, 34 insertions, 23 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6552f986774c..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;  	}  } @@ -2432,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; @@ -2643,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));  | 
