diff options
Diffstat (limited to 'net/iucv')
-rw-r--r-- | net/iucv/af_iucv.c | 121 | ||||
-rw-r--r-- | net/iucv/iucv.c | 2 |
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 | ||
37 | static char iucv_userid[80]; | 34 | static 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 */ | ||
45 | static const u8 iprm_shutdown[8] = | ||
46 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; | ||
47 | |||
47 | static void iucv_sock_kill(struct sock *sk); | 48 | static void iucv_sock_kill(struct sock *sk); |
48 | static void iucv_sock_close(struct sock *sk); | 49 | static 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 | */ | ||
104 | static 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 */ |
84 | static void iucv_sock_timeout(unsigned long arg) | 116 | static 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 | */ | ||
683 | static 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 | |||
639 | static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | 694 | static 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 | } |