Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[sfrench/cifs-2.6.git] / net / tipc / socket.c
index 9c834fc30112c148ca02348d113e2015a3a48dd8..2a6a5a6b4c125bac4f9e2e59241091b71a6d1c99 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/socket.c: TIPC socket API
  * 
  * Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -169,12 +169,6 @@ static int tipc_create(struct socket *sock, int protocol)
        struct sock *sk;
         u32 ref;
 
-       if ((sock->type != SOCK_STREAM) && 
-           (sock->type != SOCK_SEQPACKET) &&
-           (sock->type != SOCK_DGRAM) &&
-           (sock->type != SOCK_RDM))
-               return -EPROTOTYPE;
-
        if (unlikely(protocol != 0))
                return -EPROTONOSUPPORT;
 
@@ -199,6 +193,9 @@ static int tipc_create(struct socket *sock, int protocol)
                sock->ops = &msg_ops;
                sock->state = SS_READY;
                break;
+       default:
+               tipc_deleteport(ref);
+               return -EPROTOTYPE;
        }
 
        sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
@@ -458,7 +455,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
 
        if (unlikely(!dest))
                return -EDESTADDRREQ;
-       if (unlikely(dest->family != AF_TIPC))
+       if (unlikely((m->msg_namelen < sizeof(*dest)) ||
+                    (dest->family != AF_TIPC)))
                return -EINVAL;
 
        needs_conn = (sock->state != SS_READY);
@@ -601,7 +599,8 @@ exit:
  * 
  * Used for SOCK_STREAM data.
  * 
- * Returns the number of bytes sent on success, or errno otherwise
+ * Returns the number of bytes sent on success (or partial success), 
+ * or errno if no data sent
  */
 
 
@@ -615,6 +614,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
        char __user *curr_start;
        int curr_left;
        int bytes_to_send;
+       int bytes_sent;
        int res;
        
        if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
@@ -629,6 +629,9 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
                         return -ENOTCONN;
         }
 
+       if (unlikely(m->msg_name))
+               return -EISCONN;
+
        /* 
         * Send each iovec entry using one or more messages
         *
@@ -637,11 +640,13 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
         * of small iovec entries into send_packet().
         */
 
-       my_msg = *m;
-       curr_iov = my_msg.msg_iov;
-       curr_iovlen = my_msg.msg_iovlen;
+       curr_iov = m->msg_iov;
+       curr_iovlen = m->msg_iovlen;
        my_msg.msg_iov = &my_iov;
        my_msg.msg_iovlen = 1;
+       my_msg.msg_flags = m->msg_flags;
+       my_msg.msg_name = NULL;
+       bytes_sent = 0;
 
        while (curr_iovlen--) {
                curr_start = curr_iov->iov_base;
@@ -652,16 +657,18 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
                                ? curr_left : TIPC_MAX_USER_MSG_SIZE;
                        my_iov.iov_base = curr_start;
                        my_iov.iov_len = bytes_to_send;
-                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0)
-                                return res;
+                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {
+                               return bytes_sent ? bytes_sent : res;
+                       }
                        curr_left -= bytes_to_send;
                        curr_start += bytes_to_send;
+                       bytes_sent += bytes_to_send;
                }
 
                curr_iov++;
        }
 
-       return total_len;
+       return bytes_sent;
 }
 
 /**
@@ -743,10 +750,10 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
        if (unlikely(err)) {
                anc_data[0] = err;
                anc_data[1] = msg_data_sz(msg);
-               if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data)))
+               if ((res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data)))
                        return res;
                if (anc_data[1] &&
-                   (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], 
+                   (res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], 
                                    msg_data(msg))))
                        return res;
        }
@@ -777,7 +784,7 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
                has_name = 0;
        }
        if (has_name &&
-           (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data)))
+           (res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data)))
                return res;
 
        return 0;
@@ -939,7 +946,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
        int sz_to_copy;
        int sz_copied = 0;
        int needed;
-       char *crs = m->msg_iov->iov_base;
+       char __user *crs = m->msg_iov->iov_base;
        unsigned char *buf_crs;
        u32 err;
        int res;
@@ -968,7 +975,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
 restart:
        if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
                     (flags & MSG_DONTWAIT))) {
-               res = (sz_copied == 0) ? -EWOULDBLOCK : 0;
+               res = -EWOULDBLOCK;
                goto exit;
        }
 
@@ -1059,7 +1066,7 @@ restart:
 
 exit:
        up(&tsock->sem);
-       return res ? res : sz_copied;
+       return sz_copied ? sz_copied : res;
 }
 
 /**
@@ -1201,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
        atomic_inc(&tipc_queue_size);
        skb_queue_tail(&sock->sk->sk_receive_queue, buf);
 
-        wake_up_interruptible(sock->sk->sk_sleep);
+       if (waitqueue_active(sock->sk->sk_sleep))
+               wake_up_interruptible(sock->sk->sk_sleep);
        return TIPC_OK;
 }
 
@@ -1216,7 +1224,8 @@ static void wakeupdispatch(struct tipc_port *tport)
 {
        struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
 
-        wake_up_interruptible(tsock->sk.sk_sleep);
+       if (waitqueue_active(tsock->sk.sk_sleep))
+               wake_up_interruptible(tsock->sk.sk_sleep);
 }
 
 /**
@@ -1244,7 +1253,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
    if (sock->state == SS_READY)
           return -EOPNOTSUPP;
 
-   /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */
+   /* Issue Posix-compliant error code if socket is in the wrong state */
+
    if (sock->state == SS_LISTENING)
           return -EOPNOTSUPP;
    if (sock->state == SS_CONNECTING)
@@ -1252,13 +1262,20 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
    if (sock->state != SS_UNCONNECTED)
            return -EISCONN;
 
-   if ((destlen < sizeof(*dst)) || (dst->family != AF_TIPC) ||
-       ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID)))
+   /*
+    * Reject connection attempt using multicast address
+    *
+    * Note: send_msg() validates the rest of the address fields,
+    *       so there's no need to do it here
+    */
+
+   if (dst->addrtype == TIPC_ADDR_MCAST)
            return -EINVAL;
 
    /* Send a 'SYN-' to destination */
 
    m.msg_name = dest;
+   m.msg_namelen = destlen;
    if ((res = send_msg(NULL, sock, &m, 0)) < 0) {
           sock->state = SS_DISCONNECTING;
           return res;
@@ -1486,7 +1503,7 @@ static int setsockopt(struct socket *sock,
                return -ENOPROTOOPT;
        if (ol < sizeof(value))
                return -EINVAL;
-        if ((res = get_user(value, (u32 *)ov)))
+        if ((res = get_user(value, (u32 __user *)ov)))
                return res;
 
        if (down_interruptible(&tsock->sem)) 
@@ -1531,7 +1548,7 @@ static int setsockopt(struct socket *sock,
  */
 
 static int getsockopt(struct socket *sock, 
-                     int lvl, int opt, char __user *ov, int *ol)
+                     int lvl, int opt, char __user *ov, int __user *ol)
 {
        struct tipc_sock *tsock = tipc_sk(sock->sk);
         int len;