aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2009-04-21 19:26:23 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-23 07:04:33 -0400
commitb8942e3b6c4b35dda5e8ca75aec5e2f027fe39a9 (patch)
tree1d89b4fc4aa5d327c0c43feb4281b1a3aa6e0a23 /net
parent9d5c5d8f4105dc56ec10864b195dd1714f282c22 (diff)
af_iucv: Support data in IUCV msg parameter lists (IPRMDATA)
The patch allows to send and receive data in the parameter list of an iucv message. The parameter list is an arry of 8 bytes that are used by af_iucv as follows: 0..6 7 bytes for socket data and 7 1 byte to store the data length. Instead of storing the data length directly, the difference between 0xFF and the data length is used. This convention does not interfere with the existing use of PRM messages for shutting down the send direction of an AF_IUCV socket (shutdown() operation). Data lenghts greater than 7 (or PRM message byte 8 is less than 0xF8) denotes to special messages. Currently, the special SEND_SHUTDOWN message is supported only. To use IPRM messages, both communicators must set the IUCV_IPRMDATA flag during path negotiation, i.e. in iucv_connect() and path_pending(). To be compatible to older af_iucv implementations, sending PRM messages is controlled by the socket option SO_IPRMDATA_MSG. Receiving PRM messages does not depend on the socket option (but requires the IUCV_IPRMDATA path flag to be set). Sending/Receiving data in the parameter list improves performance for small amounts of data by reducing message_completion() interrupts and memory copy operations. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-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}