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

Commit 7d316b94 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller
Browse files

af_iucv: remove IUCV-pathes completely



A SEVER is missing in the callback of a receiving SEVERED. This may
inhibit z/VM to remove the corresponding IUCV-path completely.
This patch adds a SEVER in iucv_callback_connrej (together with
additional locking.

Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@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 1ab0d2ec
Loading
Loading
Loading
Loading
+37 −34
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ do { \

static void iucv_sock_kill(struct sock *sk);
static void iucv_sock_close(struct sock *sk);
static void iucv_sever_path(struct sock *, int);

static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
	struct packet_type *pt, struct net_device *orig_dev);
@@ -181,11 +182,7 @@ static int afiucv_pm_freeze(struct device *dev)
		case IUCV_DISCONN:
		case IUCV_CLOSING:
		case IUCV_CONNECTED:
			if (iucv->path) {
				err = pr_iucv->path_sever(iucv->path, NULL);
				iucv_path_free(iucv->path);
				iucv->path = NULL;
			}
			iucv_sever_path(sk, 0);
			break;
		case IUCV_OPEN:
		case IUCV_BOUND:
@@ -194,6 +191,8 @@ static int afiucv_pm_freeze(struct device *dev)
		default:
			break;
		}
		skb_queue_purge(&iucv->send_skb_q);
		skb_queue_purge(&iucv->backlog_skb_q);
	}
	read_unlock(&iucv_sk_list.lock);
	return err;
@@ -447,10 +446,29 @@ static void iucv_sock_kill(struct sock *sk)
	sock_put(sk);
}

/* Terminate an IUCV path */
static void iucv_sever_path(struct sock *sk, int with_user_data)
{
	unsigned char user_data[16];
	struct iucv_sock *iucv = iucv_sk(sk);
	struct iucv_path *path = iucv->path;

	if (iucv->path) {
		iucv->path = NULL;
		if (with_user_data) {
			low_nmcpy(user_data, iucv->src_name);
			high_nmcpy(user_data, iucv->dst_name);
			ASCEBC(user_data, sizeof(user_data));
			pr_iucv->path_sever(path, user_data);
		} else
			pr_iucv->path_sever(path, NULL);
		iucv_path_free(path);
	}
}

/* Close an IUCV socket */
static void iucv_sock_close(struct sock *sk)
{
	unsigned char user_data[16];
	struct iucv_sock *iucv = iucv_sk(sk);
	unsigned long timeo;
	int err, blen;
@@ -494,25 +512,14 @@ static void iucv_sock_close(struct sock *sk)
		sk->sk_state = IUCV_CLOSED;
		sk->sk_state_change(sk);

		if (iucv->path) {
			low_nmcpy(user_data, iucv->src_name);
			high_nmcpy(user_data, iucv->dst_name);
			ASCEBC(user_data, sizeof(user_data));
			pr_iucv->path_sever(iucv->path, user_data);
			iucv_path_free(iucv->path);
			iucv->path = NULL;
		}

		sk->sk_err = ECONNRESET;
		sk->sk_state_change(sk);

		iucv_skb_queue_purge(&iucv->send_skb_q);
		skb_queue_purge(&iucv->backlog_skb_q);
		break;

	default:
		/* nothing to do here */
		break;
	default:   /* fall through */
		iucv_sever_path(sk, 1);
	}

	/* mark socket for deletion by iucv_sock_kill() */
@@ -894,11 +901,8 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
	if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED)
		err = -ECONNREFUSED;

	if (err && iucv->transport == AF_IUCV_TRANS_IUCV) {
		pr_iucv->path_sever(iucv->path, NULL);
		iucv_path_free(iucv->path);
		iucv->path = NULL;
	}
	if (err && iucv->transport == AF_IUCV_TRANS_IUCV)
		iucv_sever_path(sk, 0);

done:
	release_sock(sk);
@@ -1565,13 +1569,6 @@ static int iucv_sock_release(struct socket *sock)

	iucv_sock_close(sk);

	/* Unregister with IUCV base support */
	if (iucv_sk(sk)->path) {
		pr_iucv->path_sever(iucv_sk(sk)->path, NULL);
		iucv_path_free(iucv_sk(sk)->path);
		iucv_sk(sk)->path = NULL;
	}

	sock_orphan(sk);
	iucv_sock_kill(sk);
	return err;
@@ -1750,8 +1747,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
	path->msglim = iucv->msglimit;
	err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk);
	if (err) {
		err = pr_iucv->path_sever(path, user_data);
		iucv_path_free(path);
		iucv_sever_path(nsk, 1);
		iucv_sock_kill(nsk);
		goto fail;
	}
@@ -1828,6 +1824,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
	struct sk_buff *list_skb = list->next;
	unsigned long flags;

	bh_lock_sock(sk);
	if (!skb_queue_empty(list)) {
		spin_lock_irqsave(&list->lock, flags);

@@ -1849,7 +1846,6 @@ static void iucv_callback_txdone(struct iucv_path *path,
			iucv_sock_wake_msglim(sk);
		}
	}
	BUG_ON(!this);

	if (sk->sk_state == IUCV_CLOSING) {
		if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
@@ -1857,6 +1853,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
			sk->sk_state_change(sk);
		}
	}
	bh_unlock_sock(sk);

}

@@ -1864,9 +1861,15 @@ static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
{
	struct sock *sk = path->private;

	if (sk->sk_state == IUCV_CLOSED)
		return;

	bh_lock_sock(sk);
	iucv_sever_path(sk, 1);
	sk->sk_state = IUCV_DISCONN;

	sk->sk_state_change(sk);
	bh_unlock_sock(sk);
}

/* called if the other communication side shuts down its RECV direction;