Commit 990454b5 authored by Reilly Grant's avatar Reilly Grant Committed by David S. Miller

VSOCK: Handle changes to the VMCI context ID.

The VMCI context ID of a virtual machine may change at any time. There
is a VMCI event which signals this but datagrams may be processed before
this is handled. It is therefore necessary to be flexible about the
destination context ID of any datagrams received. (It can be assumed to
be correct because it is provided by the hypervisor.) The context ID on
existing sockets should be updated to reflect how the hypervisor is
currently referring to the system.
Signed-off-by: default avatarReilly Grant <grantr@vmware.com>
Acked-by: default avatarAndy King <acking@vmware.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 25fb6ca4
...@@ -207,7 +207,7 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr) ...@@ -207,7 +207,7 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr)
struct vsock_sock *vsk; struct vsock_sock *vsk;
list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table)
if (vsock_addr_equals_addr_any(addr, &vsk->local_addr)) if (addr->svm_port == vsk->local_addr.svm_port)
return sk_vsock(vsk); return sk_vsock(vsk);
return NULL; return NULL;
...@@ -220,8 +220,8 @@ static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src, ...@@ -220,8 +220,8 @@ static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src,
list_for_each_entry(vsk, vsock_connected_sockets(src, dst), list_for_each_entry(vsk, vsock_connected_sockets(src, dst),
connected_table) { connected_table) {
if (vsock_addr_equals_addr(src, &vsk->remote_addr) if (vsock_addr_equals_addr(src, &vsk->remote_addr) &&
&& vsock_addr_equals_addr(dst, &vsk->local_addr)) { dst->svm_port == vsk->local_addr.svm_port) {
return sk_vsock(vsk); return sk_vsock(vsk);
} }
} }
......
...@@ -464,19 +464,16 @@ static struct sock *vmci_transport_get_pending( ...@@ -464,19 +464,16 @@ static struct sock *vmci_transport_get_pending(
struct vsock_sock *vlistener; struct vsock_sock *vlistener;
struct vsock_sock *vpending; struct vsock_sock *vpending;
struct sock *pending; struct sock *pending;
struct sockaddr_vm src;
vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
vlistener = vsock_sk(listener); vlistener = vsock_sk(listener);
list_for_each_entry(vpending, &vlistener->pending_links, list_for_each_entry(vpending, &vlistener->pending_links,
pending_links) { pending_links) {
struct sockaddr_vm src;
struct sockaddr_vm dst;
vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port);
if (vsock_addr_equals_addr(&src, &vpending->remote_addr) && if (vsock_addr_equals_addr(&src, &vpending->remote_addr) &&
vsock_addr_equals_addr(&dst, &vpending->local_addr)) { pkt->dst_port == vpending->local_addr.svm_port) {
pending = sk_vsock(vpending); pending = sk_vsock(vpending);
sock_hold(pending); sock_hold(pending);
goto found; goto found;
...@@ -739,10 +736,15 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) ...@@ -739,10 +736,15 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg)
*/ */
bh_lock_sock(sk); bh_lock_sock(sk);
if (!sock_owned_by_user(sk) && sk->sk_state == SS_CONNECTED) if (!sock_owned_by_user(sk)) {
/* The local context ID may be out of date, update it. */
vsk->local_addr.svm_cid = dst.svm_cid;
if (sk->sk_state == SS_CONNECTED)
vmci_trans(vsk)->notify_ops->handle_notify_pkt( vmci_trans(vsk)->notify_ops->handle_notify_pkt(
sk, pkt, true, &dst, &src, sk, pkt, true, &dst, &src,
&bh_process_pkt); &bh_process_pkt);
}
bh_unlock_sock(sk); bh_unlock_sock(sk);
...@@ -902,6 +904,9 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) ...@@ -902,6 +904,9 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work)
lock_sock(sk); lock_sock(sk);
/* The local context ID may be out of date. */
vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context;
switch (sk->sk_state) { switch (sk->sk_state) {
case SS_LISTEN: case SS_LISTEN:
vmci_transport_recv_listen(sk, pkt); vmci_transport_recv_listen(sk, pkt);
...@@ -958,6 +963,10 @@ static int vmci_transport_recv_listen(struct sock *sk, ...@@ -958,6 +963,10 @@ static int vmci_transport_recv_listen(struct sock *sk,
pending = vmci_transport_get_pending(sk, pkt); pending = vmci_transport_get_pending(sk, pkt);
if (pending) { if (pending) {
lock_sock(pending); lock_sock(pending);
/* The local context ID may be out of date. */
vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context;
switch (pending->sk_state) { switch (pending->sk_state) {
case SS_CONNECTING: case SS_CONNECTING:
err = vmci_transport_recv_connecting_server(sk, err = vmci_transport_recv_connecting_server(sk,
......
...@@ -64,16 +64,6 @@ bool vsock_addr_equals_addr(const struct sockaddr_vm *addr, ...@@ -64,16 +64,6 @@ bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
} }
EXPORT_SYMBOL_GPL(vsock_addr_equals_addr); EXPORT_SYMBOL_GPL(vsock_addr_equals_addr);
bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
const struct sockaddr_vm *other)
{
return (addr->svm_cid == VMADDR_CID_ANY ||
other->svm_cid == VMADDR_CID_ANY ||
addr->svm_cid == other->svm_cid) &&
addr->svm_port == other->svm_port;
}
EXPORT_SYMBOL_GPL(vsock_addr_equals_addr_any);
int vsock_addr_cast(const struct sockaddr *addr, int vsock_addr_cast(const struct sockaddr *addr,
size_t len, struct sockaddr_vm **out_addr) size_t len, struct sockaddr_vm **out_addr)
{ {
......
...@@ -24,8 +24,6 @@ bool vsock_addr_bound(const struct sockaddr_vm *addr); ...@@ -24,8 +24,6 @@ bool vsock_addr_bound(const struct sockaddr_vm *addr);
void vsock_addr_unbind(struct sockaddr_vm *addr); void vsock_addr_unbind(struct sockaddr_vm *addr);
bool vsock_addr_equals_addr(const struct sockaddr_vm *addr, bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
const struct sockaddr_vm *other); const struct sockaddr_vm *other);
bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
const struct sockaddr_vm *other);
int vsock_addr_cast(const struct sockaddr *addr, size_t len, int vsock_addr_cast(const struct sockaddr *addr, size_t len,
struct sockaddr_vm **out_addr); struct sockaddr_vm **out_addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment