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

Commit 44b1e6b5 authored by Hendrik Brueckner's avatar Hendrik Brueckner Committed by David S. Miller
Browse files

af_iucv: Modify iucv msg target class using control msghdr



Allow 'classification' of socket data that is sent or received over
an af_iucv socket. For classification of data, the target class of an
(native) iucv message is used.

This patch provides the cmsg interface for iucv_sock_recvmsg() and
iucv_sock_sendmsg().  Applications can use the msg_control field of
struct msghdr to set or get the target class as a
"socket control message" (SCM/CMSG).

Signed-off-by: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b8942e3b
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -79,6 +79,9 @@ struct iucv_sock {
/* iucv socket options (SOL_IUCV) */
/* iucv socket options (SOL_IUCV) */
#define SO_IPRMDATA_MSG	0x0080		/* send/recv IPRM_DATA msgs */
#define SO_IPRMDATA_MSG	0x0080		/* send/recv IPRM_DATA msgs */


/* iucv related control messages (scm) */
#define SCM_IUCV_TRGCLS	0x0001		/* target class control message */

struct iucv_sock_list {
struct iucv_sock_list {
	struct hlist_head head;
	struct hlist_head head;
	rwlock_t	  lock;
	rwlock_t	  lock;
+75 −4
Original line number Original line Diff line number Diff line
@@ -45,6 +45,15 @@ static struct proto iucv_proto = {
static const u8 iprm_shutdown[8] =
static const u8 iprm_shutdown[8] =
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};


#define TRGCLS_SIZE	(sizeof(((struct iucv_message *)0)->class))

/* macros to set/get socket control buffer at correct offset */
#define CB_TAG(skb)	((skb)->cb)		/* iucv message tag */
#define CB_TAG_LEN	(sizeof(((struct iucv_message *) 0)->tag))
#define CB_TRGCLS(skb)	((skb)->cb + CB_TAG_LEN) /* iucv msg target class */
#define CB_TRGCLS_LEN	(TRGCLS_SIZE)


static void iucv_sock_kill(struct sock *sk);
static void iucv_sock_kill(struct sock *sk);
static void iucv_sock_close(struct sock *sk);
static void iucv_sock_close(struct sock *sk);


@@ -698,6 +707,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
	struct iucv_sock *iucv = iucv_sk(sk);
	struct iucv_sock *iucv = iucv_sk(sk);
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct iucv_message txmsg;
	struct iucv_message txmsg;
	struct cmsghdr *cmsg;
	int cmsg_done;
	char user_id[9];
	char user_id[9];
	char appl_id[9];
	char appl_id[9];
	int err;
	int err;
@@ -717,6 +728,48 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
	}
	}


	if (sk->sk_state == IUCV_CONNECTED) {
	if (sk->sk_state == IUCV_CONNECTED) {
		/* initialize defaults */
		cmsg_done   = 0;	/* check for duplicate headers */
		txmsg.class = 0;

		/* iterate over control messages */
		for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
		     cmsg = CMSG_NXTHDR(msg, cmsg)) {

			if (!CMSG_OK(msg, cmsg)) {
				err = -EINVAL;
				goto out;
			}

			if (cmsg->cmsg_level != SOL_IUCV)
				continue;

			if (cmsg->cmsg_type & cmsg_done) {
				err = -EINVAL;
				goto out;
			}
			cmsg_done |= cmsg->cmsg_type;

			switch (cmsg->cmsg_type) {
			case SCM_IUCV_TRGCLS:
				if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
					err = -EINVAL;
					goto out;
				}

				/* set iucv message target class */
				memcpy(&txmsg.class,
					(void *) CMSG_DATA(cmsg), TRGCLS_SIZE);

				break;

			default:
				err = -EINVAL;
				goto out;
				break;
			}
		}

		if (!(skb = sock_alloc_send_skb(sk, len,
		if (!(skb = sock_alloc_send_skb(sk, len,
						msg->msg_flags & MSG_DONTWAIT,
						msg->msg_flags & MSG_DONTWAIT,
						&err)))
						&err)))
@@ -727,10 +780,9 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
			goto fail;
			goto fail;
		}
		}


		txmsg.class = 0;
		/* increment and save iucv message tag for msg_completion cbk */
		memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len);
		txmsg.tag = iucv->send_tag++;
		txmsg.tag = iucv->send_tag++;
		memcpy(skb->cb, &txmsg.tag, 4);
		memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
		skb_queue_tail(&iucv->send_skb_q, skb);
		skb_queue_tail(&iucv->send_skb_q, skb);


		if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
		if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
@@ -801,6 +853,10 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len)
		if (!nskb)
		if (!nskb)
			return -ENOMEM;
			return -ENOMEM;


		/* copy target class to control buffer of new skb */
		memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN);

		/* copy data fragment */
		memcpy(nskb->data, skb->data + copied, size);
		memcpy(nskb->data, skb->data + copied, size);
		copied += size;
		copied += size;
		dataleft -= size;
		dataleft -= size;
@@ -824,6 +880,10 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,


	len = iucv_msg_length(msg);
	len = iucv_msg_length(msg);


	/* store msg target class in the second 4 bytes of skb ctrl buffer */
	/* Note: the first 4 bytes are reserved for msg tag */
	memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN);

	/* check for special IPRM messages (e.g. iucv_sock_shutdown) */
	/* check for special IPRM messages (e.g. iucv_sock_shutdown) */
	if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
	if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
		if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) {
		if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) {
@@ -915,6 +975,17 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,


	len -= copied;
	len -= copied;


	/* create control message to store iucv msg target class:
	 * get the trgcls from the control buffer of the skb due to
	 * fragmentation of original iucv message. */
	err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS,
			CB_TRGCLS_LEN, CB_TRGCLS(skb));
	if (err) {
		if (!(flags & MSG_PEEK))
			skb_queue_head(&sk->sk_receive_queue, skb);
		return err;
	}

	/* Mark read part of skb as used */
	/* Mark read part of skb as used */
	if (!(flags & MSG_PEEK)) {
	if (!(flags & MSG_PEEK)) {
		skb_pull(skb, copied);
		skb_pull(skb, copied);
@@ -1316,7 +1387,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
		spin_lock_irqsave(&list->lock, flags);
		spin_lock_irqsave(&list->lock, flags);


		while (list_skb != (struct sk_buff *)list) {
		while (list_skb != (struct sk_buff *)list) {
			if (!memcmp(&msg->tag, list_skb->cb, 4)) {
			if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) {
				this = list_skb;
				this = list_skb;
				break;
				break;
			}
			}