Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 149817
b: refs/heads/master
c: b8942e3
h: refs/heads/master
i:
  149815: 6cb5084
v: v3
  • Loading branch information
Hendrik Brueckner authored and David S. Miller committed Apr 23, 2009
1 parent f903692 commit 1965c53
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9d5c5d8f4105dc56ec10864b195dd1714f282c22
refs/heads/master: b8942e3b6c4b35dda5e8ca75aec5e2f027fe39a9
121 changes: 101 additions & 20 deletions trunk/net/iucv/af_iucv.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
#include <net/iucv/iucv.h>
#include <net/iucv/af_iucv.h>

#define CONFIG_IUCV_SOCK_DEBUG 1

#define IPRMDATA 0x80
#define VERSION "1.1"

static char iucv_userid[80];
Expand All @@ -44,6 +41,10 @@ static struct proto iucv_proto = {
.obj_size = sizeof(struct iucv_sock),
};

/* special AF_IUCV IPRM messages */
static const u8 iprm_shutdown[8] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};

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

Expand Down Expand Up @@ -80,6 +81,37 @@ static inline void low_nmcpy(unsigned char *dst, char *src)
memcpy(&dst[8], src, 8);
}

/**
* iucv_msg_length() - Returns the length of an iucv message.
* @msg: Pointer to struct iucv_message, MUST NOT be NULL
*
* The function returns the length of the specified iucv message @msg of data
* stored in a buffer and of data stored in the parameter list (PRMDATA).
*
* For IUCV_IPRMDATA, AF_IUCV uses the following convention to transport socket
* data:
* PRMDATA[0..6] socket data (max 7 bytes);
* PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7])
*
* The socket data length is computed by substracting the socket data length
* value from 0xFF.
* If the socket data len is greater 7, then PRMDATA can be used for special
* notifications (see iucv_sock_shutdown); and further,
* if the socket data len is > 7, the function returns 8.
*
* Use this function to allocate socket buffers to store iucv message data.
*/
static inline size_t iucv_msg_length(struct iucv_message *msg)
{
size_t datalen;

if (msg->flags & IUCV_IPRMDATA) {
datalen = 0xff - msg->rmmsg[7];
return (datalen < 8) ? datalen : 8;
}
return msg->length;
}

/* Timers */
static void iucv_sock_timeout(unsigned long arg)
{
Expand Down Expand Up @@ -487,7 +519,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
iucv = iucv_sk(sk);
/* Create path. */
iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT,
IPRMDATA, GFP_KERNEL);
IUCV_IPRMDATA, GFP_KERNEL);
if (!iucv->path) {
err = -ENOMEM;
goto done;
Expand Down Expand Up @@ -521,8 +553,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
}

if (sk->sk_state == IUCV_DISCONN) {
release_sock(sk);
return -ECONNREFUSED;
err = -ECONNREFUSED;
}

if (err) {
Expand Down Expand Up @@ -636,6 +667,30 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
return 0;
}

/**
* iucv_send_iprm() - Send socket data in parameter list of an iucv message.
* @path: IUCV path
* @msg: Pointer to a struct iucv_message
* @skb: The socket data to send, skb->len MUST BE <= 7
*
* Send the socket data in the parameter list in the iucv message
* (IUCV_IPRMDATA). The socket data is stored at index 0 to 6 in the parameter
* list and the socket data len at index 7 (last byte).
* See also iucv_msg_length().
*
* Returns the error code from the iucv_message_send() call.
*/
static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg,
struct sk_buff *skb)
{
u8 prmdata[8];

memcpy(prmdata, (void *) skb->data, skb->len);
prmdata[7] = 0xff - (u8) skb->len;
return iucv_message_send(path, msg, IUCV_IPRMDATA, 0,
(void *) prmdata, 8);
}

static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len)
{
Expand Down Expand Up @@ -677,8 +732,29 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
txmsg.tag = iucv->send_tag++;
memcpy(skb->cb, &txmsg.tag, 4);
skb_queue_tail(&iucv->send_skb_q, skb);
err = iucv_message_send(iucv->path, &txmsg, 0, 0,
(void *) skb->data, skb->len);

if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
&& skb->len <= 7) {
err = iucv_send_iprm(iucv->path, &txmsg, 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);
}

/* 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;
Expand Down Expand Up @@ -744,19 +820,25 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
struct iucv_message *msg)
{
int rc;
unsigned int len;

len = iucv_msg_length(msg);

if (msg->flags & IPRMDATA) {
skb->data = NULL;
skb->len = 0;
/* check for special IPRM messages (e.g. iucv_sock_shutdown) */
if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) {
skb->data = NULL;
skb->len = 0;
}
} else {
rc = iucv_message_receive(path, msg, 0, skb->data,
msg->length, NULL);
rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA,
skb->data, len, NULL);
if (rc) {
kfree_skb(skb);
return;
}
if (skb->truesize >= sk->sk_rcvbuf / 4) {
rc = iucv_fragment_skb(sk, skb, msg->length);
rc = iucv_fragment_skb(sk, skb, len);
kfree_skb(skb);
skb = NULL;
if (rc) {
Expand All @@ -767,7 +849,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
} else {
skb_reset_transport_header(skb);
skb_reset_network_header(skb);
skb->len = msg->length;
skb->len = len;
}
}

Expand All @@ -782,7 +864,7 @@ static void iucv_process_message_q(struct sock *sk)
struct sock_msg_q *p, *n;

list_for_each_entry_safe(p, n, &iucv->message_q.list, list) {
skb = alloc_skb(p->msg.length, GFP_ATOMIC | GFP_DMA);
skb = alloc_skb(iucv_msg_length(&p->msg), GFP_ATOMIC | GFP_DMA);
if (!skb)
break;
iucv_process_message(sk, skb, p->path, &p->msg);
Expand Down Expand Up @@ -928,7 +1010,6 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
struct iucv_sock *iucv = iucv_sk(sk);
struct iucv_message txmsg;
int err = 0;
u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};

how++;

Expand All @@ -950,7 +1031,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
txmsg.class = 0;
txmsg.tag = 0;
err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
(void *) prmmsg, 8);
(void *) iprm_shutdown, 8);
if (err) {
switch (err) {
case 1:
Expand Down Expand Up @@ -1196,11 +1277,11 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
goto save_message;

len = atomic_read(&sk->sk_rmem_alloc);
len += msg->length + sizeof(struct sk_buff);
len += iucv_msg_length(msg) + sizeof(struct sk_buff);
if (len > sk->sk_rcvbuf)
goto save_message;

skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA);
skb = alloc_skb(iucv_msg_length(msg), GFP_ATOMIC | GFP_DMA);
if (!skb)
goto save_message;

Expand Down
2 changes: 2 additions & 0 deletions trunk/net/iucv/iucv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,8 @@ static void iucv_path_complete(struct iucv_irq_data *data)
struct iucv_path_complete *ipc = (void *) data;
struct iucv_path *path = iucv_path_table[ipc->ippathid];

if (path)
path->flags = ipc->ipflags1;
if (path && path->handler && path->handler->path_complete)
path->handler->path_complete(path, ipc->ipuser);
}
Expand Down

0 comments on commit 1965c53

Please sign in to comment.