VSOCK: Introduce vsock_find_unbound_socket and vsock_bind_dgram_generic
authorAsias He <asias@redhat.com>
Wed, 2 Dec 2015 06:43:59 +0000 (14:43 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Dec 2015 20:05:54 +0000 (15:05 -0500)
Signed-off-by: Asias He <asias@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/af_vsock.h
net/vmw_vsock/af_vsock.c

index e9eb2d6791b3bf8ac70644346e720c89b7f0d1af..a0c8fa2ababfd83db88859dd277338b654f4e633 100644 (file)
@@ -175,8 +175,10 @@ void vsock_insert_connected(struct vsock_sock *vsk);
 void vsock_remove_bound(struct vsock_sock *vsk);
 void vsock_remove_connected(struct vsock_sock *vsk);
 struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr);
+struct sock *vsock_find_unbound_socket(struct sockaddr_vm *addr);
 struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
                                         struct sockaddr_vm *dst);
 void vsock_for_each_connected_socket(void (*fn)(struct sock *sk));
+int vsock_bind_dgram_generic(struct vsock_sock *vsk, struct sockaddr_vm *addr);
 
 #endif /* __AF_VSOCK_H__ */
index 7fd1220fbfa0bb2477e2b7e6edcf714a5ae6a097..77247a2b670bce9a2b12afec8c82efef460ddc4e 100644 (file)
@@ -223,6 +223,17 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr)
        return NULL;
 }
 
+static struct sock *__vsock_find_unbound_socket(struct sockaddr_vm *addr)
+{
+       struct vsock_sock *vsk;
+
+       list_for_each_entry(vsk, vsock_unbound_sockets, bound_table)
+               if (addr->svm_port == vsk->local_addr.svm_port)
+                       return sk_vsock(vsk);
+
+       return NULL;
+}
+
 static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src,
                                                  struct sockaddr_vm *dst)
 {
@@ -298,6 +309,21 @@ struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr)
 }
 EXPORT_SYMBOL_GPL(vsock_find_bound_socket);
 
+struct sock *vsock_find_unbound_socket(struct sockaddr_vm *addr)
+{
+       struct sock *sk;
+
+       spin_lock_bh(&vsock_table_lock);
+       sk = __vsock_find_unbound_socket(addr);
+       if (sk)
+               sock_hold(sk);
+
+       spin_unlock_bh(&vsock_table_lock);
+
+       return sk;
+}
+EXPORT_SYMBOL_GPL(vsock_find_unbound_socket);
+
 struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
                                         struct sockaddr_vm *dst)
 {
@@ -532,6 +558,50 @@ static int __vsock_bind_stream(struct vsock_sock *vsk,
        return 0;
 }
 
+int vsock_bind_dgram_generic(struct vsock_sock *vsk, struct sockaddr_vm *addr)
+{
+       static u32 port = LAST_RESERVED_PORT + 1;
+       struct sockaddr_vm new_addr;
+
+       vsock_addr_init(&new_addr, addr->svm_cid, addr->svm_port);
+
+       if (addr->svm_port == VMADDR_PORT_ANY) {
+               bool found = false;
+               unsigned int i;
+
+               for (i = 0; i < MAX_PORT_RETRIES; i++) {
+                       if (port <= LAST_RESERVED_PORT)
+                               port = LAST_RESERVED_PORT + 1;
+
+                       new_addr.svm_port = port++;
+
+                       if (!__vsock_find_unbound_socket(&new_addr)) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return -EADDRNOTAVAIL;
+       } else {
+               /* If port is in reserved range, ensure caller
+                * has necessary privileges.
+                */
+               if (addr->svm_port <= LAST_RESERVED_PORT &&
+                   !capable(CAP_NET_BIND_SERVICE)) {
+                       return -EACCES;
+               }
+
+               if (__vsock_find_unbound_socket(&new_addr))
+                       return -EADDRINUSE;
+       }
+
+       vsock_addr_init(&vsk->local_addr, new_addr.svm_cid, new_addr.svm_port);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vsock_bind_dgram_generic);
+
 static int __vsock_bind_dgram(struct vsock_sock *vsk,
                              struct sockaddr_vm *addr)
 {