Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82492a35 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller
Browse files

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: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9fbd87d4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct sock_msg_q {
#define AF_IUCV_FLAG_SYN 0x2
#define AF_IUCV_FLAG_FIN 0x4
#define AF_IUCV_FLAG_WIN 0x8
#define AF_IUCV_FLAG_SHT 0x10

struct af_iucv_trans_hdr {
	u16 magic;
+52 −27
Original line number Diff line number Diff line
@@ -165,8 +165,6 @@ static int afiucv_pm_freeze(struct device *dev)
	read_lock(&iucv_sk_list.lock);
	sk_for_each(sk, node, &iucv_sk_list.head) {
		iucv = iucv_sk(sk);
		skb_queue_purge(&iucv->send_skb_q);
		skb_queue_purge(&iucv->backlog_skb_q);
		switch (sk->sk_state) {
		case IUCV_DISCONN:
		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)
{
	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 */
@@ -1342,6 +1352,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,

	rlen   = skb->len;		/* real length of skb */
	copied = min_t(unsigned int, rlen, len);
	if (!rlen)
		sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;

	cskb = skb;
	if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
@@ -1493,22 +1505,22 @@ static int iucv_sock_shutdown(struct socket *sock, int how)

	lock_sock(sk);
	switch (sk->sk_state) {
	case IUCV_LISTEN:
	case IUCV_DISCONN:
	case IUCV_CLOSING:
	case IUCV_CLOSED:
		err = -ENOTCONN;
		goto fail;

	default:
		sk->sk_shutdown |= how;
		break;
	}

	if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
		if (iucv->transport == AF_IUCV_TRANS_IUCV) {
			txmsg.class = 0;
			txmsg.tag = 0;
		err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
					0, (void *) iprm_shutdown, 8);
			err = pr_iucv->message_send(iucv->path, &txmsg,
				IUCV_IPRMDATA, 0, (void *) iprm_shutdown, 8);
			if (err) {
				switch (err) {
				case 1:
@@ -1522,13 +1534,18 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
					break;
				}
			}
		} else
			iucv_send_ctrl(sk, AF_IUCV_FLAG_SHT);
	}

	sk->sk_shutdown |= how;
	if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
		if (iucv->transport == AF_IUCV_TRANS_IUCV) {
			err = pr_iucv->path_quiesce(iucv->path, NULL);
			if (err)
				err = -ENOTCONN;

/*			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;
	}

	if (sk->sk_shutdown & RCV_SHUTDOWN) {
		kfree_skb(skb);
		return NET_RX_SUCCESS;
	}

		/* 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);
		return NET_RX_SUCCESS;
	}
@@ -2173,7 +2195,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
			kfree_skb(skb);
			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:
		/* plain data frame */
		memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,