|
@@ -747,108 +747,107 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- 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;
|
|
|
- }
|
|
|
+ /* Return if the socket is not in connected state */
|
|
|
+ if (sk->sk_state != IUCV_CONNECTED) {
|
|
|
+ err = -ENOTCONN;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- if (cmsg->cmsg_level != SOL_IUCV)
|
|
|
- continue;
|
|
|
+ /* initialize defaults */
|
|
|
+ cmsg_done = 0; /* check for duplicate headers */
|
|
|
+ txmsg.class = 0;
|
|
|
|
|
|
- if (cmsg->cmsg_type & cmsg_done) {
|
|
|
- err = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- cmsg_done |= cmsg->cmsg_type;
|
|
|
+ /* iterate over control messages */
|
|
|
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
|
|
|
+ cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
|
|
|
|
|
- switch (cmsg->cmsg_type) {
|
|
|
- case SCM_IUCV_TRGCLS:
|
|
|
- if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
|
|
|
- err = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ if (!CMSG_OK(msg, cmsg)) {
|
|
|
+ err = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- /* set iucv message target class */
|
|
|
- memcpy(&txmsg.class,
|
|
|
- (void *) CMSG_DATA(cmsg), TRGCLS_SIZE);
|
|
|
+ if (cmsg->cmsg_level != SOL_IUCV)
|
|
|
+ continue;
|
|
|
|
|
|
- break;
|
|
|
+ if (cmsg->cmsg_type & cmsg_done) {
|
|
|
+ err = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ cmsg_done |= cmsg->cmsg_type;
|
|
|
|
|
|
- default:
|
|
|
+ switch (cmsg->cmsg_type) {
|
|
|
+ case SCM_IUCV_TRGCLS:
|
|
|
+ if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
|
|
|
err = -EINVAL;
|
|
|
goto out;
|
|
|
- break;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /* allocate one skb for each iucv message:
|
|
|
- * this is fine for SOCK_SEQPACKET (unless we want to support
|
|
|
- * segmented records using the MSG_EOR flag), but
|
|
|
- * for SOCK_STREAM we might want to improve it in future */
|
|
|
- if (!(skb = sock_alloc_send_skb(sk, len,
|
|
|
- msg->msg_flags & MSG_DONTWAIT,
|
|
|
- &err)))
|
|
|
- goto out;
|
|
|
+ /* set iucv message target class */
|
|
|
+ memcpy(&txmsg.class,
|
|
|
+ (void *) CMSG_DATA(cmsg), TRGCLS_SIZE);
|
|
|
|
|
|
- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
|
|
|
- err = -EFAULT;
|
|
|
- goto fail;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ err = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /* increment and save iucv message tag for msg_completion cbk */
|
|
|
- txmsg.tag = iucv->send_tag++;
|
|
|
- memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
|
|
|
- skb_queue_tail(&iucv->send_skb_q, skb);
|
|
|
+ /* allocate one skb for each iucv message:
|
|
|
+ * this is fine for SOCK_SEQPACKET (unless we want to support
|
|
|
+ * segmented records using the MSG_EOR flag), but
|
|
|
+ * for SOCK_STREAM we might want to improve it in future */
|
|
|
+ skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT,
|
|
|
+ &err);
|
|
|
+ if (!skb)
|
|
|
+ goto out;
|
|
|
+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
|
|
|
+ err = -EFAULT;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
|
|
|
- if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
|
|
|
- && skb->len <= 7) {
|
|
|
- err = iucv_send_iprm(iucv->path, &txmsg, skb);
|
|
|
+ /* increment and save iucv message tag for msg_completion cbk */
|
|
|
+ txmsg.tag = iucv->send_tag++;
|
|
|
+ memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
|
|
|
+ skb_queue_tail(&iucv->send_skb_q, skb);
|
|
|
|
|
|
- /* on success: there is no message_complete callback
|
|
|
- * for an IPRMDATA msg; remove skb from send queue */
|
|
|
- if (err == 0) {
|
|
|
- skb_unlink(skb, &iucv->send_skb_q);
|
|
|
- kfree_skb(skb);
|
|
|
- }
|
|
|
+ if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
|
|
|
+ && skb->len <= 7) {
|
|
|
+ err = iucv_send_iprm(iucv->path, &txmsg, skb);
|
|
|
|
|
|
- /* this error should never happen since the
|
|
|
- * IUCV_IPRMDATA path flag is set... sever path */
|
|
|
- if (err == 0x15) {
|
|
|
- iucv_path_sever(iucv->path, NULL);
|
|
|
- skb_unlink(skb, &iucv->send_skb_q);
|
|
|
- err = -EPIPE;
|
|
|
- goto fail;
|
|
|
- }
|
|
|
- } else
|
|
|
- err = iucv_message_send(iucv->path, &txmsg, 0, 0,
|
|
|
- (void *) skb->data, skb->len);
|
|
|
- if (err) {
|
|
|
- if (err == 3) {
|
|
|
- user_id[8] = 0;
|
|
|
- memcpy(user_id, iucv->dst_user_id, 8);
|
|
|
- appl_id[8] = 0;
|
|
|
- memcpy(appl_id, iucv->dst_name, 8);
|
|
|
- pr_err("Application %s on z/VM guest %s"
|
|
|
- " exceeds message limit\n",
|
|
|
- user_id, appl_id);
|
|
|
- }
|
|
|
+ /* on success: there is no message_complete callback
|
|
|
+ * for an IPRMDATA msg; remove skb from send queue */
|
|
|
+ if (err == 0) {
|
|
|
+ skb_unlink(skb, &iucv->send_skb_q);
|
|
|
+ kfree_skb(skb);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* this error should never happen since the
|
|
|
+ * IUCV_IPRMDATA path flag is set... sever path */
|
|
|
+ if (err == 0x15) {
|
|
|
+ iucv_path_sever(iucv->path, NULL);
|
|
|
skb_unlink(skb, &iucv->send_skb_q);
|
|
|
err = -EPIPE;
|
|
|
goto fail;
|
|
|
}
|
|
|
-
|
|
|
- } else {
|
|
|
- err = -ENOTCONN;
|
|
|
- goto out;
|
|
|
+ } else
|
|
|
+ err = iucv_message_send(iucv->path, &txmsg, 0, 0,
|
|
|
+ (void *) skb->data, skb->len);
|
|
|
+ if (err) {
|
|
|
+ if (err == 3) {
|
|
|
+ user_id[8] = 0;
|
|
|
+ memcpy(user_id, iucv->dst_user_id, 8);
|
|
|
+ appl_id[8] = 0;
|
|
|
+ memcpy(appl_id, iucv->dst_name, 8);
|
|
|
+ pr_err("Application %s on z/VM guest %s"
|
|
|
+ " exceeds message limit\n",
|
|
|
+ appl_id, user_id);
|
|
|
+ }
|
|
|
+ skb_unlink(skb, &iucv->send_skb_q);
|
|
|
+ err = -EPIPE;
|
|
|
+ goto fail;
|
|
|
}
|
|
|
|
|
|
release_sock(sk);
|