summaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c76
1 files changed, 35 insertions, 41 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 2b02a3a8031..29d94d53198 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2,7 +2,7 @@
* net/tipc/socket.c: TIPC socket API
*
* Copyright (c) 2001-2007, Ericsson AB
- * Copyright (c) 2004-2008, Wind River Systems
+ * Copyright (c) 2004-2008, 2010-2011, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,6 +58,9 @@ struct tipc_sock {
#define tipc_sk(sk) ((struct tipc_sock *)(sk))
#define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p))
+#define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \
+ (sock->state == SS_DISCONNECTING))
+
static int backlog_rcv(struct sock *sk, struct sk_buff *skb);
static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
static void wakeupdispatch(struct tipc_port *tport);
@@ -241,7 +244,6 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
tipc_set_portunreliable(tp_ptr->ref, 1);
}
- atomic_inc(&tipc_user_count);
return 0;
}
@@ -290,7 +292,7 @@ static int release(struct socket *sock)
if (buf == NULL)
break;
atomic_dec(&tipc_queue_size);
- if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf)))
+ if (TIPC_SKB_CB(buf)->handle != 0)
buf_discard(buf);
else {
if ((sock->state == SS_CONNECTING) ||
@@ -321,7 +323,6 @@ static int release(struct socket *sock)
sock_put(sk);
sock->sk = NULL;
- atomic_dec(&tipc_user_count);
return res;
}
@@ -495,6 +496,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
if (likely(dest->addr.name.name.type != TIPC_CFG_SRV))
return -EACCES;
+ if (!m->msg_iovlen || (m->msg_iov[0].iov_len < sizeof(hdr)))
+ return -EMSGSIZE;
if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
return -EFAULT;
if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN)))
@@ -911,15 +914,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
struct tipc_port *tport = tipc_sk_port(sk);
struct sk_buff *buf;
struct tipc_msg *msg;
+ long timeout;
unsigned int sz;
u32 err;
int res;
/* Catch invalid receive requests */
- if (m->msg_iovlen != 1)
- return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */
-
if (unlikely(!buf_len))
return -EINVAL;
@@ -930,6 +931,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
restart:
/* Look for a message in receive queue; wait if necessary */
@@ -939,17 +941,15 @@ restart:
res = -ENOTCONN;
goto exit;
}
- if (flags & MSG_DONTWAIT) {
- res = -EWOULDBLOCK;
+ if (timeout <= 0L) {
+ res = timeout ? timeout : -EWOULDBLOCK;
goto exit;
}
release_sock(sk);
- res = wait_event_interruptible(*sk_sleep(sk),
- (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sock->state == SS_DISCONNECTING)));
+ timeout = wait_event_interruptible_timeout(*sk_sleep(sk),
+ tipc_rx_ready(sock),
+ timeout);
lock_sock(sk);
- if (res)
- goto exit;
}
/* Look at first message in receive queue */
@@ -991,11 +991,10 @@ restart:
sz = buf_len;
m->msg_flags |= MSG_TRUNC;
}
- if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg),
- sz))) {
- res = -EFAULT;
+ res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg),
+ m->msg_iov, sz);
+ if (res)
goto exit;
- }
res = sz;
} else {
if ((sock->state == SS_READY) ||
@@ -1038,19 +1037,15 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
struct tipc_port *tport = tipc_sk_port(sk);
struct sk_buff *buf;
struct tipc_msg *msg;
+ long timeout;
unsigned int sz;
int sz_to_copy, target, needed;
int sz_copied = 0;
- char __user *crs = m->msg_iov->iov_base;
- unsigned char *buf_crs;
u32 err;
int res = 0;
/* Catch invalid receive attempts */
- if (m->msg_iovlen != 1)
- return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */
-
if (unlikely(!buf_len))
return -EINVAL;
@@ -1063,7 +1058,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
}
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
-
+ timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
restart:
/* Look for a message in receive queue; wait if necessary */
@@ -1073,17 +1068,15 @@ restart:
res = -ENOTCONN;
goto exit;
}
- if (flags & MSG_DONTWAIT) {
- res = -EWOULDBLOCK;
+ if (timeout <= 0L) {
+ res = timeout ? timeout : -EWOULDBLOCK;
goto exit;
}
release_sock(sk);
- res = wait_event_interruptible(*sk_sleep(sk),
- (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sock->state == SS_DISCONNECTING)));
+ timeout = wait_event_interruptible_timeout(*sk_sleep(sk),
+ tipc_rx_ready(sock),
+ timeout);
lock_sock(sk);
- if (res)
- goto exit;
}
/* Look at first message in receive queue */
@@ -1112,24 +1105,25 @@ restart:
/* Capture message data (if valid) & compute return value (always) */
if (!err) {
- buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);
- sz = (unsigned char *)msg + msg_size(msg) - buf_crs;
+ u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle);
+ sz -= offset;
needed = (buf_len - sz_copied);
sz_to_copy = (sz <= needed) ? sz : needed;
- if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {
- res = -EFAULT;
+
+ res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset,
+ m->msg_iov, sz_to_copy);
+ if (res)
goto exit;
- }
+
sz_copied += sz_to_copy;
if (sz_to_copy < sz) {
if (!(flags & MSG_PEEK))
- TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy;
+ TIPC_SKB_CB(buf)->handle =
+ (void *)(unsigned long)(offset + sz_to_copy);
goto exit;
}
-
- crs += sz_to_copy;
} else {
if (sz_copied != 0)
goto exit; /* can't add error msg to valid data */
@@ -1256,7 +1250,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
/* Enqueue message (finally!) */
- TIPC_SKB_CB(buf)->handle = msg_data(msg);
+ TIPC_SKB_CB(buf)->handle = 0;
atomic_inc(&tipc_queue_size);
__skb_queue_tail(&sk->sk_receive_queue, buf);
@@ -1608,7 +1602,7 @@ restart:
buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf) {
atomic_dec(&tipc_queue_size);
- if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) {
+ if (TIPC_SKB_CB(buf)->handle != 0) {
buf_discard(buf);
goto restart;
}