aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/iucv/af_iucv.c121
-rw-r--r--net/iucv/iucv.c2
2 files changed, 103 insertions, 20 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index b7c40c979921..5fc077ee5831 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -29,9 +29,6 @@
29#include <net/iucv/iucv.h> 29#include <net/iucv/iucv.h>
30#include <net/iucv/af_iucv.h> 30#include <net/iucv/af_iucv.h>
31 31
32#define CONFIG_IUCV_SOCK_DEBUG 1
33
34#define IPRMDATA 0x80
35#define VERSION "1.1" 32#define VERSION "1.1"
36 33
37static char iucv_userid[80]; 34static char iucv_userid[80];
@@ -44,6 +41,10 @@ static struct proto iucv_proto = {
44 .obj_size = sizeof(struct iucv_sock), 41 .obj_size = sizeof(struct iucv_sock),
45}; 42};
46 43
44/* special AF_IUCV IPRM messages */
45static const u8 iprm_shutdown[8] =
46 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
47
47static void iucv_sock_kill(struct sock *sk); 48static void iucv_sock_kill(struct sock *sk);
48static void iucv_sock_close(struct sock *sk); 49static void iucv_sock_close(struct sock *sk);
49 50
@@ -80,6 +81,37 @@ static inline void low_nmcpy(unsigned char *dst, char *src)
80 memcpy(&dst[8], src, 8); 81 memcpy(&dst[8], src, 8);
81} 82}
82 83
84/**
85 * iucv_msg_length() - Returns the length of an iucv message.
86 * @msg: Pointer to struct iucv_message, MUST NOT be NULL
87 *
88 * The function returns the length of the specified iucv message @msg of data
89 * stored in a buffer and of data stored in the parameter list (PRMDATA).
90 *
91 * For IUCV_IPRMDATA, AF_IUCV uses the following convention to transport socket
92 * data:
93 * PRMDATA[0..6] socket data (max 7 bytes);
94 * PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7])
95 *
96 * The socket data length is computed by substracting the socket data length
97 * value from 0xFF.
98 * If the socket data len is greater 7, then PRMDATA can be used for special
99 * notifications (see iucv_sock_shutdown); and further,
100 * if the socket data len is > 7, the function returns 8.
101 *
102 * Use this function to allocate socket buffers to store iucv message data.
103 */
104static inline size_t iucv_msg_length(struct iucv_message *msg)
105{
106 size_t datalen;
107
108 if (msg->flags & IUCV_IPRMDATA) {
109 datalen = 0xff - msg->rmmsg[7];
110 return (datalen < 8) ? datalen : 8;
111 }
112 return msg->length;
113}
114
83/* Timers */ 115/* Timers */
84static void iucv_sock_timeout(unsigned long arg) 116static void iucv_sock_timeout(unsigned long arg)
85{ 117{
@@ -487,7 +519,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
487 iucv = iucv_sk(sk); 519 iucv = iucv_sk(sk);
488 /* Create path. */ 520 /* Create path. */
489 iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, 521 iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT,
490 IPRMDATA, GFP_KERNEL); 522 IUCV_IPRMDATA, GFP_KERNEL);
491 if (!iucv->path) { 523 if (!iucv->path) {
492 err = -ENOMEM; 524 err = -ENOMEM;
493 goto done; 525 goto done;
@@ -521,8 +553,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
521 } 553 }
522 554
523 if (sk->sk_state == IUCV_DISCONN) { 555 if (sk->sk_state == IUCV_DISCONN) {
524 release_sock(sk); 556 err = -ECONNREFUSED;
525 return -ECONNREFUSED;
526 } 557 }
527 558
528 if (err) { 559 if (err) {
@@ -636,6 +667,30 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
636 return 0; 667 return 0;
637} 668}
638 669
670/**
671 * iucv_send_iprm() - Send socket data in parameter list of an iucv message.
672 * @path: IUCV path
673 * @msg: Pointer to a struct iucv_message
674 * @skb: The socket data to send, skb->len MUST BE <= 7
675 *
676 * Send the socket data in the parameter list in the iucv message
677 * (IUCV_IPRMDATA). The socket data is stored at index 0 to 6 in the parameter
678 * list and the socket data len at index 7 (last byte).
679 * See also iucv_msg_length().
680 *
681 * Returns the error code from the iucv_message_send() call.
682 */
683static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg,
684 struct sk_buff *skb)
685{
686 u8 prmdata[8];
687
688 memcpy(prmdata, (void *) skb->data, skb->len);
689 prmdata[7] = 0xff - (u8) skb->len;
690 return iucv_message_send(path, msg, IUCV_IPRMDATA, 0,
691 (void *) prmdata, 8);
692}
693
639static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, 694static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
640 struct msghdr *msg, size_t len) 695 struct msghdr *msg, size_t len)
641{ 696{
@@ -677,8 +732,29 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
677 txmsg.tag = iucv->send_tag++; 732 txmsg.tag = iucv->send_tag++;
678 memcpy(skb->cb, &txmsg.tag, 4); 733 memcpy(skb->cb, &txmsg.tag, 4);
679 skb_queue_tail(&iucv->send_skb_q, skb); 734 skb_queue_tail(&iucv->send_skb_q, skb);
680 err = iucv_message_send(iucv->path, &txmsg, 0, 0, 735
681 (void *) skb->data, skb->len); 736 if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
737 && skb->len <= 7) {
738 err = iucv_send_iprm(iucv->path, &txmsg, skb);
739
740 /* on success: there is no message_complete callback
741 * for an IPRMDATA msg; remove skb from send queue */
742 if (err == 0) {
743 skb_unlink(skb, &iucv->send_skb_q);
744 kfree_skb(skb);
745 }
746
747 /* this error should never happen since the
748 * IUCV_IPRMDATA path flag is set... sever path */
749 if (err == 0x15) {
750 iucv_path_sever(iucv->path, NULL);
751 skb_unlink(skb, &iucv->send_skb_q);
752 err = -EPIPE;
753 goto fail;
754 }
755 } else
756 err = iucv_message_send(iucv->path, &txmsg, 0, 0,
757 (void *) skb->data, skb->len);
682 if (err) { 758 if (err) {
683 if (err == 3) { 759 if (err == 3) {
684 user_id[8] = 0; 760 user_id[8] = 0;
@@ -744,19 +820,25 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
744 struct iucv_message *msg) 820 struct iucv_message *msg)
745{ 821{
746 int rc; 822 int rc;
823 unsigned int len;
824
825 len = iucv_msg_length(msg);
747 826
748 if (msg->flags & IPRMDATA) { 827 /* check for special IPRM messages (e.g. iucv_sock_shutdown) */
749 skb->data = NULL; 828 if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
750 skb->len = 0; 829 if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) {
830 skb->data = NULL;
831 skb->len = 0;
832 }
751 } else { 833 } else {
752 rc = iucv_message_receive(path, msg, 0, skb->data, 834 rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA,
753 msg->length, NULL); 835 skb->data, len, NULL);
754 if (rc) { 836 if (rc) {
755 kfree_skb(skb); 837 kfree_skb(skb);
756 return; 838 return;
757 } 839 }
758 if (skb->truesize >= sk->sk_rcvbuf / 4) { 840 if (skb->truesize >= sk->sk_rcvbuf / 4) {
759 rc = iucv_fragment_skb(sk, skb, msg->length); 841 rc = iucv_fragment_skb(sk, skb, len);
760 kfree_skb(skb); 842 kfree_skb(skb);
761 skb = NULL; 843 skb = NULL;
762 if (rc) { 844 if (rc) {
@@ -767,7 +849,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
767 } else { 849 } else {
768 skb_reset_transport_header(skb); 850 skb_reset_transport_header(skb);
769 skb_reset_network_header(skb); 851 skb_reset_network_header(skb);
770 skb->len = msg->length; 852 skb->len = len;
771 } 853 }
772 } 854 }
773 855
@@ -782,7 +864,7 @@ static void iucv_process_message_q(struct sock *sk)
782 struct sock_msg_q *p, *n; 864 struct sock_msg_q *p, *n;
783 865
784 list_for_each_entry_safe(p, n, &iucv->message_q.list, list) { 866 list_for_each_entry_safe(p, n, &iucv->message_q.list, list) {
785 skb = alloc_skb(p->msg.length, GFP_ATOMIC | GFP_DMA); 867 skb = alloc_skb(iucv_msg_length(&p->msg), GFP_ATOMIC | GFP_DMA);
786 if (!skb) 868 if (!skb)
787 break; 869 break;
788 iucv_process_message(sk, skb, p->path, &p->msg); 870 iucv_process_message(sk, skb, p->path, &p->msg);
@@ -928,7 +1010,6 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
928 struct iucv_sock *iucv = iucv_sk(sk); 1010 struct iucv_sock *iucv = iucv_sk(sk);
929 struct iucv_message txmsg; 1011 struct iucv_message txmsg;
930 int err = 0; 1012 int err = 0;
931 u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
932 1013
933 how++; 1014 how++;
934 1015
@@ -950,7 +1031,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
950 txmsg.class = 0; 1031 txmsg.class = 0;
951 txmsg.tag = 0; 1032 txmsg.tag = 0;
952 err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0, 1033 err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
953 (void *) prmmsg, 8); 1034 (void *) iprm_shutdown, 8);
954 if (err) { 1035 if (err) {
955 switch (err) { 1036 switch (err) {
956 case 1: 1037 case 1:
@@ -1196,11 +1277,11 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
1196 goto save_message; 1277 goto save_message;
1197 1278
1198 len = atomic_read(&sk->sk_rmem_alloc); 1279 len = atomic_read(&sk->sk_rmem_alloc);
1199 len += msg->length + sizeof(struct sk_buff); 1280 len += iucv_msg_length(msg) + sizeof(struct sk_buff);
1200 if (len > sk->sk_rcvbuf) 1281 if (len > sk->sk_rcvbuf)
1201 goto save_message; 1282 goto save_message;
1202 1283
1203 skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA); 1284 skb = alloc_skb(iucv_msg_length(msg), GFP_ATOMIC | GFP_DMA);
1204 if (!skb) 1285 if (!skb)
1205 goto save_message; 1286 goto save_message;
1206 1287
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index fcf404065f12..61e8038a55ee 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1388,6 +1388,8 @@ static void iucv_path_complete(struct iucv_irq_data *data)
1388 struct iucv_path_complete *ipc = (void *) data; 1388 struct iucv_path_complete *ipc = (void *) data;
1389 struct iucv_path *path = iucv_path_table[ipc->ippathid]; 1389 struct iucv_path *path = iucv_path_table[ipc->ippathid];
1390 1390
1391 if (path)
1392 path->flags = ipc->ipflags1;
1391 if (path && path->handler && path->handler->path_complete) 1393 if (path && path->handler && path->handler->path_complete)
1392 path->handler->path_complete(path, ipc->ipuser); 1394 path->handler->path_complete(path, ipc->ipuser);
1393} 1395}