mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	af_iucv: add shutdown for HS transport
AF_IUCV sockets offer a shutdown function. This patch makes sure shutdown works for HS transport as well. Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									9fbd87d413
								
							
						
					
					
						commit
						82492a355f
					
				
					 2 changed files with 53 additions and 27 deletions
				
			
		| 
						 | 
					@ -62,6 +62,7 @@ struct sock_msg_q {
 | 
				
			||||||
#define AF_IUCV_FLAG_SYN 0x2
 | 
					#define AF_IUCV_FLAG_SYN 0x2
 | 
				
			||||||
#define AF_IUCV_FLAG_FIN 0x4
 | 
					#define AF_IUCV_FLAG_FIN 0x4
 | 
				
			||||||
#define AF_IUCV_FLAG_WIN 0x8
 | 
					#define AF_IUCV_FLAG_WIN 0x8
 | 
				
			||||||
 | 
					#define AF_IUCV_FLAG_SHT 0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct af_iucv_trans_hdr {
 | 
					struct af_iucv_trans_hdr {
 | 
				
			||||||
	u16 magic;
 | 
						u16 magic;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,8 +165,6 @@ static int afiucv_pm_freeze(struct device *dev)
 | 
				
			||||||
	read_lock(&iucv_sk_list.lock);
 | 
						read_lock(&iucv_sk_list.lock);
 | 
				
			||||||
	sk_for_each(sk, node, &iucv_sk_list.head) {
 | 
						sk_for_each(sk, node, &iucv_sk_list.head) {
 | 
				
			||||||
		iucv = iucv_sk(sk);
 | 
							iucv = iucv_sk(sk);
 | 
				
			||||||
		skb_queue_purge(&iucv->send_skb_q);
 | 
					 | 
				
			||||||
		skb_queue_purge(&iucv->backlog_skb_q);
 | 
					 | 
				
			||||||
		switch (sk->sk_state) {
 | 
							switch (sk->sk_state) {
 | 
				
			||||||
		case IUCV_DISCONN:
 | 
							case IUCV_DISCONN:
 | 
				
			||||||
		case IUCV_CLOSING:
 | 
							case IUCV_CLOSING:
 | 
				
			||||||
| 
						 | 
					@ -405,7 +403,19 @@ static struct sock *__iucv_get_sock_by_name(char *nm)
 | 
				
			||||||
static void iucv_sock_destruct(struct sock *sk)
 | 
					static void iucv_sock_destruct(struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	skb_queue_purge(&sk->sk_receive_queue);
 | 
						skb_queue_purge(&sk->sk_receive_queue);
 | 
				
			||||||
	skb_queue_purge(&sk->sk_write_queue);
 | 
						skb_queue_purge(&sk->sk_error_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sk_mem_reclaim(sk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sock_flag(sk, SOCK_DEAD)) {
 | 
				
			||||||
 | 
							pr_err("Attempt to release alive iucv socket %p\n", sk);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						WARN_ON(atomic_read(&sk->sk_rmem_alloc));
 | 
				
			||||||
 | 
						WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 | 
				
			||||||
 | 
						WARN_ON(sk->sk_wmem_queued);
 | 
				
			||||||
 | 
						WARN_ON(sk->sk_forward_alloc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Cleanup Listen */
 | 
					/* Cleanup Listen */
 | 
				
			||||||
| 
						 | 
					@ -1342,6 +1352,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rlen   = skb->len;		/* real length of skb */
 | 
						rlen   = skb->len;		/* real length of skb */
 | 
				
			||||||
	copied = min_t(unsigned int, rlen, len);
 | 
						copied = min_t(unsigned int, rlen, len);
 | 
				
			||||||
 | 
						if (!rlen)
 | 
				
			||||||
 | 
							sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cskb = skb;
 | 
						cskb = skb;
 | 
				
			||||||
	if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
 | 
						if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
 | 
				
			||||||
| 
						 | 
					@ -1493,42 +1505,47 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lock_sock(sk);
 | 
						lock_sock(sk);
 | 
				
			||||||
	switch (sk->sk_state) {
 | 
						switch (sk->sk_state) {
 | 
				
			||||||
 | 
						case IUCV_LISTEN:
 | 
				
			||||||
	case IUCV_DISCONN:
 | 
						case IUCV_DISCONN:
 | 
				
			||||||
	case IUCV_CLOSING:
 | 
						case IUCV_CLOSING:
 | 
				
			||||||
	case IUCV_CLOSED:
 | 
						case IUCV_CLOSED:
 | 
				
			||||||
		err = -ENOTCONN;
 | 
							err = -ENOTCONN;
 | 
				
			||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		sk->sk_shutdown |= how;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
 | 
						if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
 | 
				
			||||||
		txmsg.class = 0;
 | 
							if (iucv->transport == AF_IUCV_TRANS_IUCV) {
 | 
				
			||||||
		txmsg.tag = 0;
 | 
								txmsg.class = 0;
 | 
				
			||||||
		err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
 | 
								txmsg.tag = 0;
 | 
				
			||||||
					0, (void *) iprm_shutdown, 8);
 | 
								err = pr_iucv->message_send(iucv->path, &txmsg,
 | 
				
			||||||
		if (err) {
 | 
									IUCV_IPRMDATA, 0, (void *) iprm_shutdown, 8);
 | 
				
			||||||
			switch (err) {
 | 
								if (err) {
 | 
				
			||||||
			case 1:
 | 
									switch (err) {
 | 
				
			||||||
				err = -ENOTCONN;
 | 
									case 1:
 | 
				
			||||||
				break;
 | 
										err = -ENOTCONN;
 | 
				
			||||||
			case 2:
 | 
										break;
 | 
				
			||||||
				err = -ECONNRESET;
 | 
									case 2:
 | 
				
			||||||
				break;
 | 
										err = -ECONNRESET;
 | 
				
			||||||
			default:
 | 
										break;
 | 
				
			||||||
				err = -ENOTCONN;
 | 
									default:
 | 
				
			||||||
				break;
 | 
										err = -ENOTCONN;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							} else
 | 
				
			||||||
 | 
								iucv_send_ctrl(sk, AF_IUCV_FLAG_SHT);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sk->sk_shutdown |= how;
 | 
				
			||||||
	if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
 | 
						if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
 | 
				
			||||||
		err = pr_iucv->path_quiesce(iucv->path, NULL);
 | 
							if (iucv->transport == AF_IUCV_TRANS_IUCV) {
 | 
				
			||||||
		if (err)
 | 
								err = pr_iucv->path_quiesce(iucv->path, NULL);
 | 
				
			||||||
			err = -ENOTCONN;
 | 
								if (err)
 | 
				
			||||||
 | 
									err = -ENOTCONN;
 | 
				
			||||||
 | 
					/*			skb_queue_purge(&sk->sk_receive_queue); */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		skb_queue_purge(&sk->sk_receive_queue);
 | 
							skb_queue_purge(&sk->sk_receive_queue);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2066,8 +2083,13 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
		return NET_RX_SUCCESS;
 | 
							return NET_RX_SUCCESS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sk->sk_shutdown & RCV_SHUTDOWN) {
 | 
				
			||||||
 | 
							kfree_skb(skb);
 | 
				
			||||||
 | 
							return NET_RX_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* write stuff from iucv_msg to skb cb */
 | 
							/* write stuff from iucv_msg to skb cb */
 | 
				
			||||||
	if (skb->len <= sizeof(struct af_iucv_trans_hdr)) {
 | 
						if (skb->len < sizeof(struct af_iucv_trans_hdr)) {
 | 
				
			||||||
		kfree_skb(skb);
 | 
							kfree_skb(skb);
 | 
				
			||||||
		return NET_RX_SUCCESS;
 | 
							return NET_RX_SUCCESS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2173,7 +2195,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
			kfree_skb(skb);
 | 
								kfree_skb(skb);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* fall through */
 | 
							/* fall through and receive non-zero length data */
 | 
				
			||||||
 | 
						case (AF_IUCV_FLAG_SHT):
 | 
				
			||||||
 | 
							/* shutdown request */
 | 
				
			||||||
 | 
							/* fall through and receive zero length data */
 | 
				
			||||||
	case 0:
 | 
						case 0:
 | 
				
			||||||
		/* plain data frame */
 | 
							/* plain data frame */
 | 
				
			||||||
		memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
 | 
							memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue