#include <linux/list.h>
#include <linux/wait.h>
#include <linux/init.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
-# include <net/tcp_states.h>
-#else
-# include <linux/tcp.h>
-#endif
#include <asm/io.h>
#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
# include <linux/ioctl32.h>
Bool oldPktProto);
static int VSockVmciGetAFValue(void);
static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg);
-static int VSockVmciRecvSeqCB(void *data, VMCIDatagram *dg);
static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg);
static void VSockVmciPeerAttachCB(VMCIId subId,
VMCI_EventData *ed, void *clientData);
struct sockaddr *addr, int addrLen);
static int VSockVmciDgramConnect(struct socket *sock,
struct sockaddr *addr, int addrLen, int flags);
-static int VSockVmciSeqConnect(struct socket *sock,
- struct sockaddr *addr, int addrLen, int flags);
static int VSockVmciStreamConnect(struct socket *sock,
struct sockaddr *addr, int addrLen, int flags);
static int VSockVmciAccept(struct socket *sock, struct socket *newsock, int flags);
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags);
-static int VSockVmciSeqSendmsg(struct kiocb *kiocb,
- struct socket *sock, struct msghdr *msg, size_t len);
-static int VSockVmciSeqRecvmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags);
static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
.owner = THIS_MODULE,
};
-/* Socket operations, split for DGRAM, STREAM and SEQPACKET sockets. */
+/* Socket operations, split for DGRAM and STREAM sockets. */
static struct proto_ops vsockVmciDgramOps = {
.family = VSOCK_INVALID_FAMILY,
.owner = THIS_MODULE,
.sendpage = sock_no_sendpage,
};
-static struct proto_ops vsockVmciSeqOps = {
- .family = VSOCK_INVALID_FAMILY,
- .owner = THIS_MODULE,
- .release = VSockVmciRelease,
- .bind = VSockVmciBind,
- .connect = VSockVmciSeqConnect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = VSockVmciGetname,
- .poll = VSockVmciPoll,
- .ioctl = sock_no_ioctl,
- .listen = sock_no_listen,
- .shutdown = VSockVmciShutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .sendmsg = VSockVmciSeqSendmsg,
- .recvmsg = VSockVmciSeqRecvmsg,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-
static struct proto_ops vsockVmciStreamOps = {
.family = VSOCK_INVALID_FAMILY,
.owner = THIS_MODULE,
*/
#define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ)
-#define VSOCK_SEND_SEQ_CLOSE(_vsk, _err) \
- VSockVmciSendSeqPacket((_vsk), VSOCK_SEQ_PACKET_TYPE_CLOSE, (_err))
-#define VSOCK_SEND_SEQ_SHUTDOWN(_vsk, _mode) \
- VSockVmciSendSeqPacket((_vsk), VSOCK_SEQ_PACKET_TYPE_SHUTDOWN, (_mode))
-
#ifdef VMX86_DEVEL
# define LOG_PACKET(_pkt) VSockVmciLogPkt(__FUNCTION__, __LINE__, _pkt)
#else
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciSendSeqPacket --
- *
- * Send a sequential packet. This uses a stack-allocated packet, i.e.,
- * it isn't meant for DATA packets, but it works fine for the other packet
- * types.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VSockVmciSendSeqPacket(VSockVmciSock *vsk, // IN
- VSockSeqPacketType type, // IN
- uint32 mode) // IN
-{
- int err;
- VSockSeqPacket pkt;
-
- ASSERT(vsk);
-
- VSockSeqPacket_Init(&pkt, &vsk->localAddr, &vsk->remoteAddr, type, mode);
-
- err = VMCIDatagram_Send(&pkt.hdr.dg);
- if (err < 0) {
- err = VSockVmci_ErrorToVSockError(err);
- }
-
- return err;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciRecvSeqCB --
- *
- * VMCI Datagram receive callback. This function is used specifically for
- * SOCK_SEQPACKET sockets.
- *
- * This is invoked as part of a tasklet that's scheduled when the VMCI
- * interrupt fires. This is run in bottom-half context and if it ever needs
- * to sleep it should defer that work to a work queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * An sk_buff is created and queued with this socket.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VSockVmciRecvSeqCB(void *data, // IN
- VMCIDatagram *dg) // IN
-{
- struct sock *sk;
- size_t size;
- VSockVmciSock *vsk;
- VSockSeqPacket *pkt;
-
- ASSERT(dg);
- ASSERT(dg->payloadSize <= VMCI_MAX_DG_PAYLOAD_SIZE);
-
- sk = (struct sock *)data;
-
- ASSERT(sk);
-
- /* XXX, figure out why sk->sk_socket can be NULL. */
- if (!sk->sk_socket) {
- return EINVAL;
- }
-
- ASSERT(sk->sk_socket->type == SOCK_SEQPACKET);
-
- if (VMCI_HYPERVISOR_CONTEXT_ID != dg->src.context) {
- return VMCI_ERROR_NO_ACCESS;
- }
-
- if (VMCI_RPC_PRIVILEGED != dg->src.resource &&
- VMCI_RPC_UNPRIVILEGED != dg->src.resource) {
- return VMCI_ERROR_NO_ACCESS;
- }
-
- size = VMCI_DG_SIZE(dg);
- if (size < sizeof *pkt) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- vsk = vsock_sk(sk);
- pkt = (VSockSeqPacket *)dg;
-
- /*
- * After this point, if we fail to handle the packet, we need to send a
- * close to the peer with an error. Otherwise it might hang, waiting for a
- * response to a packet that we discarded.
- */
-
- if (VSOCK_SEQ_PACKET_VERSION_1 != pkt->hdr.version) {
- VSOCK_SEND_SEQ_CLOSE(vsk, EINVAL);
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (SS_CONNECTED != sk->sk_socket->state) {
- VSOCK_SEND_SEQ_CLOSE(vsk, ENOTCONN);
- return VMCI_ERROR_DST_UNREACHABLE;
- }
-
- switch (pkt->hdr.type) {
- case VSOCK_SEQ_PACKET_TYPE_DATA: {
- struct sk_buff *skb;
- /*
- * Attach the packet to the socket's receive queue as an sk_buff.
- */
-
- size -= sizeof *pkt;
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb) {
- VSOCK_SEND_SEQ_CLOSE(vsk, ENOMEM);
- return VMCI_ERROR_NO_MEM;
- }
-
- /* compat_sk_receive_skb() will do a sock_put(), so hold here. */
- sock_hold(sk);
- skb_put(skb, size);
- memcpy(skb->data, VSOCK_SEQ_PACKET_PAYLOAD(pkt), size);
-
- /*
- * XXX, this can drop the skb. We need to find an alternative that
- * will return an error if that happens, so that we can send a reset
- * to the peer, i.e.,
- *
- * if (!receive_skb(sk, skb)) {
- * VSOCK_SEND_SEQ_CLOSE(vsk, ENOMEM);
- * return VMCI_ERROR_NO_MEM;
- * }
- */
-
- compat_sk_receive_skb(sk, skb, 0);
- break;
- }
- case VSOCK_SEQ_PACKET_TYPE_CLOSE:
- bh_lock_sock(sk);
-
- sock_set_flag(sk, SOCK_DONE);
- vsk->peerShutdown = SHUTDOWN_MASK;
- sk->sk_state = TCP_CLOSE;
-
- /*
- * A close packet with an error code means a forceful reset, whereas
- * no error means a graceful close.
- */
- if (pkt->hdr.val) {
- sk->sk_socket->state = SS_UNCONNECTED;
- sk->sk_err = pkt->hdr.val;
- sk->sk_error_report(sk);
- } else {
- if (skb_queue_empty(&sk->sk_receive_queue)) {
- sk->sk_socket->state = SS_DISCONNECTING;
- }
- sk->sk_state_change(sk);
- }
-
- bh_unlock_sock(sk);
- break;
- /*
- * There's no reason for us to receive a shutdown packet in this direction,
- * or any other packet for that matter. Inform the peer that the packet
- * is invalid.
- */
- default:
- VSOCK_SEND_SEQ_CLOSE(vsk, EINVAL);
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- return VMCI_SUCCESS;
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciContextUpdatedCB --
- *
- * Invoked when a VM is resumed (technically when the context ID changes,
- * but the event is actually sent even when it does not, so this works
- * well for catching resumes). We must mark all connected sequential
- * sockets as detached.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May modify socket state and signal socket.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-VSockVmciContextUpdatedCB(VMCIId subId, // IN
- VMCI_EventData *eData, // IN
- void *clientData) // IN
-{
- uint32 i;
-
- spin_lock_bh(&vsockSeqTableLock);
-
- for (i = 0; i < ARRAYSIZE(vsockSeqTable); i++) {
- VSockVmciSock *vsk;
-
- list_for_each_entry(vsk, &vsockSeqTable[i], seqTable) {
- struct sock *sk = sk_vsock(vsk);
-
- sock_set_flag(sk, SOCK_DONE);
- vsk->peerShutdown = SHUTDOWN_MASK;
- sk->sk_state = TCP_CLOSE;
-
- if (skb_queue_empty(&sk->sk_receive_queue)) {
- sk->sk_socket->state = SS_DISCONNECTING;
- }
- sk->sk_state_change(sk);
- }
- }
-
- spin_unlock_bh(&vsockSeqTableLock);
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
break;
}
- case SOCK_DGRAM:
- case SOCK_SEQPACKET: {
+ case SOCK_DGRAM: {
uint32 flags = 0;
/* VMCI will select a resource ID for us if we provide VMCI_INVALID_ID. */
}
err = VSockVmciDatagramCreateHnd(newAddr.svm_port, flags,
- sk->sk_socket->type == SOCK_DGRAM ?
- VSockVmciRecvDgramCB :
- VSockVmciRecvSeqCB,
+ VSockVmciRecvDgramCB,
sk, &vsk->dgHandle);
if (err < VMCI_SUCCESS) {
err = VSockVmci_ErrorToVSockError(err);
INIT_LIST_HEAD(&vsk->boundTable);
INIT_LIST_HEAD(&vsk->connectedTable);
- INIT_LIST_HEAD(&vsk->seqTable);
vsk->dgHandle = VMCI_INVALID_HANDLE;
vsk->qpHandle = VMCI_INVALID_HANDLE;
vsk->qpair = NULL;
VSockVmciRemoveConnected(sk);
}
- if (VSockVmciInSeqTable(sk)) {
- VSockVmciRemoveSeq(sk);
- }
-
if (!VMCI_HANDLE_INVALID(vsk->dgHandle)) {
- if (SOCK_SEQPACKET == sk->sk_type && TCP_ESTABLISHED == sk->sk_state) {
- VSOCK_SEND_SEQ_CLOSE(vsk, 0);
- }
VMCIDatagram_DestroyHnd(vsk->dgHandle);
vsk->dgHandle = VMCI_INVALID_HANDLE;
}
} else {
vsockVmciDgramOps.family = i;
vsockVmciStreamOps.family = i;
- vsockVmciSeqOps.family = i;
err = i;
break;
}
vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
vsockVmciStreamOps.family = vsockVmciFamilyOps.family;
- vsockVmciSeqOps.family = vsockVmciFamilyOps.family;
}
goto out;
}
- err = VMCIEvent_Subscribe(VMCI_EVENT_CTX_ID_UPDATE,
- VMCI_FLAG_EVENT_NONE,
- VSockVmciContextUpdatedCB,
- NULL,
- &ctxUpdatedSubId);
- if (err < VMCI_SUCCESS) {
- Warning("Unable to subscribe to context updated event. (%d)\n", err);
- err = VSockVmci_ErrorToVSockError(err);
- ctxUpdatedSubId = VMCI_INVALID_ID;
- goto out;
- }
-
out:
if (err != 0) {
VSockVmciUnregisterWithVmci();
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciSeqConnect --
- *
- * Connects a sequential socket.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VSockVmciSeqConnect(struct socket *sock, // IN
- struct sockaddr *addr, // IN
- int addrLen, // IN
- int flags) // IN
-{
- int err;
- struct sock *sk;
- VSockVmciSock *vsk;
- VSockSeqPacket pkt;
- struct sockaddr_vm *remoteAddr;
-
- sk = sock->sk;
- vsk = vsock_sk(sk);
-
- lock_sock(sk);
-
- if (SS_CONNECTED == sock->state) {
- err = -EISCONN;
- goto out;
- } else if (SS_CONNECTING == sock->state ||
- SS_DISCONNECTING == sock->state) {
- err = -EINVAL;
- goto out;
- }
-
- if (VSockAddr_Cast(addr, addrLen, &remoteAddr) != 0) {
- err = -EINVAL;
- goto out;
- }
-
- if (!VSockAddr_Bound(&vsk->localAddr)) {
- struct sockaddr_vm localAddr;
-
- VSockAddr_Init(&localAddr, VMADDR_CID_ANY, VMADDR_PORT_ANY);
- if ((err = __VSockVmciBind(sk, &localAddr))) {
- goto out;
- }
- }
-
- if (VMCI_HYPERVISOR_CONTEXT_ID != remoteAddr->svm_cid) {
- err = -EINVAL;
- goto out;
- }
-
- if (VMCI_RPC_PRIVILEGED != remoteAddr->svm_port &&
- VMCI_RPC_UNPRIVILEGED != remoteAddr->svm_port) {
- err = -EINVAL;
- goto out;
- }
-
- /*
- * No need to call SocketContextDgram() here, we already do specific checks
- * on the context and port above. All we have to do here is ensure that
- * only the superuser gets access to the privileged RPC handler.
- */
-
- if (VMCI_RPC_PRIVILEGED == remoteAddr->svm_port &&
- !capable(CAP_SYS_ADMIN)) {
- err = -EACCES;
- goto out;
- }
-
- VSockSeqPacket_Init(&pkt, &vsk->localAddr, remoteAddr,
- VSOCK_SEQ_PACKET_TYPE_CONNECT, 0);
-
- err = VMCIDatagram_Send(&pkt.hdr.dg);
- if (err < 0) {
- err = VSockVmci_ErrorToVSockError(err);
- goto out;
- }
-
- /*
- * It's not necessary to get an acknowledgement. We're sending to the
- * hypervisor, which means the result of the call tells us whether the
- * endpoint accepted it or not. So as long as it returns success,
- * we are connected.
- */
-
- memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr);
-
- /*
- * The skb routines actually check if this is a sequential socket, and if
- * so, they require that the socket be in the TCP established state. So
- * we need to use the TCP states for sk_state rather than the SS states
- * (our STREAM sockets cheat and get away with it, we should fix that).
- */
-
- sock->state = SS_CONNECTED;
- sk->sk_state = TCP_ESTABLISHED;
- VSockVmciInsertSeq(vsockSeqSocketsVsk(vsk), sk);
- sk->sk_state_change(sk);
-
- err = 0;
-
-out:
- release_sock(sk);
- return err;
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
}
- release_sock(sk);
- } else if (sock->type == SOCK_SEQPACKET) {
- lock_sock(sk);
-
- /*
- * If there is something in the queue then we can read.
- */
- if (!skb_queue_empty(&sk->sk_receive_queue) &&
- !(sk->sk_shutdown & RCV_SHUTDOWN)) {
- mask |= POLLIN | POLLRDNORM;
- }
-
- /*
- * Sockets whose connections have beed closed, reset or terminated
- * should also be considered readable, and we check the shutdown flag
- * for that.
- */
- if (sk->sk_shutdown & RCV_SHUTDOWN ||
- vsk->peerShutdown & SEND_SHUTDOWN) {
- mask |= POLLIN | POLLRDNORM;
- }
-
- /*
- * Connected sockets that can produce data can be written.
- */
- if (sk->sk_state == TCP_ESTABLISHED &&
- !(sk->sk_shutdown & SEND_SHUTDOWN)) {
- mask |= POLLOUT | POLLWRNORM;
- }
-
release_sock(sk);
}
}
/*
- * If this is a STREAM/SEQPACKET socket and it is not connected then bail
- * out immediately. If it is a DGRAM socket then we must first kick the
- * socket so that it wakes up from any sleeping calls, for example recv(),
- * and then afterwards return the error.
+ * If this is a STREAM socket and it is not connected then bail out
+ * immediately. If it is a DGRAM socket then we must first kick the socket
+ * so that it wakes up from any sleeping calls, for example recv(), and then
+ * afterwards return the error.
*/
sk = sock->sk;
if (sock->state == SS_UNCONNECTED) {
err = -ENOTCONN;
- if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
+ if (sk->sk_type == SOCK_STREAM) {
return err;
}
} else {
err = 0;
}
- /*
- * It doesn't make any sense to try and shutdown a sequential socket to
- * the hypervisor in the recv direction, only for send or for both.
- */
-
- if (sk->sk_type == SOCK_SEQPACKET && mode == RCV_SHUTDOWN) {
- err = -EINVAL;
- return err;
- }
-
/* Receive and send shutdowns are treated alike. */
mode = mode & (RCV_SHUTDOWN | SEND_SHUTDOWN);
if (mode) {
lock_sock(sk);
sk->sk_shutdown |= mode;
- if (sk->sk_type == SOCK_SEQPACKET) {
- sk->sk_state = TCP_CLOSE;
- }
sk->sk_state_change(sk);
release_sock(sk);
if (sk->sk_type == SOCK_STREAM) {
sock_reset_flag(sk, SOCK_DONE);
VSOCK_SEND_SHUTDOWN(sk, mode);
- } else if (sk->sk_type == SOCK_SEQPACKET) {
- sock_reset_flag(sk, SOCK_DONE);
- err = VSOCK_SEND_SEQ_SHUTDOWN(vsock_sk(sk), mode);
}
}
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciSeqSendmsg --
- *
- * Sends a datagram.
- *
- * Results:
- * Number of bytes sent on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VSockVmciSeqSendmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to send on
- struct msghdr *msg, // IN: message to send
- size_t len) // IN: length of message
-{
- int err;
- struct sock *sk;
- VSockVmciSock *vsk;
- VSockSeqPacket *pkt;
-
- sk = sock->sk;
- vsk = vsock_sk(sk);
-
- if (msg->msg_flags & MSG_OOB) {
- return -EOPNOTSUPP;
- }
-
- if (len > VMCI_MAX_DG_PAYLOAD_SIZE) {
- return -EMSGSIZE;
- }
-
- lock_sock(sk);
-
- /* Callers should not provide a destination with sequential sockets. */
- if (msg->msg_namelen) {
- err = sock->state == SS_CONNECTED ? -EISCONN : -EOPNOTSUPP;
- goto out;
- }
-
- /* Send data only if we're not shutdown in that direction. */
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- err = -EPIPE;
- goto out;
- }
-
- if (sock->state != SS_CONNECTED) {
- err = -ENOTCONN;
- goto out;
- }
-
- /*
- * We already managed to connect, which means we must already have the
- * right privs to send to our peer. So no need for the usual datagram
- * checks here, they were done by connect().
- */
-
- /*
- * Allocate a buffer for the user's message and our packet header.
- */
- pkt = kmalloc(len + sizeof *pkt, GFP_KERNEL);
- if (!pkt) {
- err = -ENOMEM;
- goto out;
- }
-
- VSockSeqPacket_Init(pkt, &vsk->localAddr, &vsk->remoteAddr,
- VSOCK_SEQ_PACKET_TYPE_DATA, 0);
- pkt->hdr.dg.payloadSize += len;
-
- err = memcpy_fromiovec(VSOCK_SEQ_PACKET_PAYLOAD(pkt), msg->msg_iov, len);
- if (0 != err) {
- kfree(pkt);
- goto out;
- }
-
- err = VMCIDatagram_Send(&pkt->hdr.dg);
- kfree(pkt);
- if (err < 0) {
- err = VSockVmci_ErrorToVSockError(err);
- goto out;
- }
-
- err = len;
-
-out:
- release_sock(sk);
- return err;
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciSeqRecvmsg --
- *
- * Receives a datagram and places it in the caller's msg.
- *
- * Results:
- * The size of the payload on success, negative value on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VSockVmciSeqRecvmsg(struct kiocb *kiocb, // UNUSED
- struct socket *sock, // IN: socket to receive from
- struct msghdr *msg, // IN/OUT: message to receive into
- size_t len, // IN: length of receive buffer
- int flags) // IN: receive flags
-{
- int err;
- int noblock;
- size_t payloadLen;
- struct sock *sk;
- struct sk_buff *skb;
-
- if (flags & MSG_OOB || flags & MSG_ERRQUEUE) {
- return -EOPNOTSUPP;
- }
-
- sk = sock->sk;
- noblock = flags & MSG_DONTWAIT;
-
- /* Retrieve the head sk_buff from the socket's receive queue. */
- err = 0;
- skb = skb_recv_datagram(sk, flags, noblock, &err);
- if (err) {
- return err;
- }
-
- if (!skb) {
- return -EAGAIN;
- }
-
- if (!skb->data) {
- /* err is 0, meaning we read zero bytes. */
- goto out;
- }
-
- payloadLen = skb->len;
- if (payloadLen > len) {
- payloadLen = len;
- msg->msg_flags |= MSG_TRUNC;
- /*
- * XXX, we're supposed to be a reliable protocol, so while it's fine to
- * return a partial packet here, we shouldn't drop the remainder. We
- * should keep it around so that a subsequent recv() can read it and
- * then get the end of record marker (see below).
- */
- } else {
- /* We managed to read the whole payload, so mark the end of record. */
- msg->msg_flags |= MSG_EOR;
- }
-
- /* Place the datagram payload in the user's iovec. */
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, payloadLen);
- if (err) {
- goto out;
- }
-
- msg->msg_namelen = 0;
- if (msg->msg_name) {
- VSockVmciSock *vsk;
- struct sockaddr_vm *vmciAddr;
-
- /* Provide the address of the sender. */
- vsk = vsock_sk(sk);
- vmciAddr = (struct sockaddr_vm *)msg->msg_name;
- VSockAddr_Init(vmciAddr,
- vsk->remoteAddr.svm_cid, vsk->remoteAddr.svm_port);
- msg->msg_namelen = sizeof *vmciAddr;
- }
- err = payloadLen;
-
-out:
- skb_free_datagram(sk, skb);
- return err;
-}
-
-
/*
*----------------------------------------------------------------------------
*
case SOCK_STREAM:
sock->ops = &vsockVmciStreamOps;
break;
- case SOCK_SEQPACKET:
- sock->ops = &vsockVmciSeqOps;
- break;
default:
return -ESOCKTNOSUPPORT;
}
* vsockBindTable[VSOCK_HASH_SIZE - 1] are for bound sockets and
* vsockBindTable[VSOCK_HASH_SIZE] is for unbound sockets. The hash function
* mods with VSOCK_HASH_SIZE - 1 to ensure this.
- *
- * Connected sequential sockets are put in the seq table.
*/
#define VSOCK_HASH_SIZE 251
#define LAST_RESERVED_PORT 1023
extern struct list_head vsockBindTable[VSOCK_HASH_SIZE + 1];
extern struct list_head vsockConnectedTable[VSOCK_HASH_SIZE];
-extern struct list_head vsockSeqTable[VSOCK_HASH_SIZE];
extern spinlock_t vsockTableLock;
-extern spinlock_t vsockSeqTableLock;
#define VSOCK_HASH(addr) ((addr)->svm_port % (VSOCK_HASH_SIZE - 1))
#define vsockBoundSockets(addr) (&vsockBindTable[VSOCK_HASH(addr)])
(&vsockConnectedTable[VSOCK_CONN_HASH(src, dst)])
#define vsockConnectedSocketsVsk(vsk) \
vsockConnectedSockets(&(vsk)->remoteAddr, &(vsk)->localAddr)
-#define VSOCK_SEQ_HASH(src, dst) VSOCK_CONN_HASH(src, dst)
-#define vsockSeqSockets(src, dst) \
- (&vsockSeqTable[VSOCK_SEQ_HASH(src, dst)])
-#define vsockSeqSocketsVsk(vsk) \
- vsockSeqSockets(&(vsk)->remoteAddr, &(vsk)->localAddr)
/*
* Prototypes.
void VSockVmciInitTables(void);
void __VSockVmciInsertBound(struct list_head *list, struct sock *sk);
void __VSockVmciInsertConnected(struct list_head *list, struct sock *sk);
-void __VSockVmciInsertSeq(struct list_head *list, struct sock *sk);
void __VSockVmciRemoveBound(struct sock *sk);
void __VSockVmciRemoveConnected(struct sock *sk);
-void __VSockVmciRemoveSeq(struct sock *sk);
struct sock *__VSockVmciFindBoundSocket(struct sockaddr_vm *addr);
struct sock *__VSockVmciFindConnectedSocket(struct sockaddr_vm *src,
struct sockaddr_vm *dst);
Bool __VSockVmciInBoundTable(struct sock *sk);
Bool __VSockVmciInConnectedTable(struct sock *sk);
-Bool __VSockVmciInSeqTable(struct sock *sk);
struct sock *VSockVmciGetPending(struct sock *listener, VSockPacket *pkt);
void VSockVmciReleasePending(struct sock *pending);
static INLINE void VSockVmciInsertBound(struct list_head *list, struct sock *sk);
static INLINE void VSockVmciInsertConnected(struct list_head *list, struct sock *sk);
-static INLINE void VSockVmciInsertSeq(struct list_head *list, struct sock *sk);
static INLINE void VSockVmciRemoveBound(struct sock *sk);
static INLINE void VSockVmciRemoveConnected(struct sock *sk);
-static INLINE void VSockVmciRemoveSeq(struct sock *sk);
static INLINE struct sock *VSockVmciFindBoundSocket(struct sockaddr_vm *addr);
static INLINE struct sock *VSockVmciFindConnectedSocket(struct sockaddr_vm *src,
struct sockaddr_vm *dst);
static INLINE Bool VSockVmciInBoundTable(struct sock *sk);
static INLINE Bool VSockVmciInConnectedTable(struct sock *sk);
-static INLINE Bool VSockVmciInSeqTable(struct sock *sk);
/*
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciInsertSeq --
- *
- * Inserts socket into the sequential table.
- *
- * Note that it is important to invoke the bottom-half versions of the
- * spinlock functions since these may be called from tasklets.
- *
- * Results:
- * None.
- *
- * Side effects:
- * vsockSeqTableLock is acquired and released.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-VSockVmciInsertSeq(struct list_head *list, // IN
- struct sock *sk) // IN
-{
- ASSERT(list);
- ASSERT(sk);
-
- spin_lock_bh(&vsockSeqTableLock);
- __VSockVmciInsertSeq(list, sk);
- spin_unlock_bh(&vsockSeqTableLock);
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciRemoveSeq --
- *
- * Removes socket from the sequential list.
- *
- * Note that it is important to invoke the bottom-half versions of the
- * spinlock functions since these may be called from tasklets.
- *
- * Results:
- * None.
- *
- * Side effects:
- * vsockSeqTableLock is acquired and released.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-VSockVmciRemoveSeq(struct sock *sk) // IN
-{
- ASSERT(sk);
-
- spin_lock_bh(&vsockSeqTableLock);
- __VSockVmciRemoveSeq(sk);
- spin_unlock_bh(&vsockSeqTableLock);
-}
-
-
/*
*----------------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciInSeqTable --
- *
- * Determines whether the provided socket is in the sequential table.
- *
- * Note that it is important to invoke the bottom-half versions of the
- * spinlock functions since these may be called from tasklets.
- *
- * Results:
- * TRUE is socket is in sequential table, FALSE otherwise.
- *
- * Side effects:
- * vsockSeqTableLock is acquired and released.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-VSockVmciInSeqTable(struct sock *sk) // IN
-{
- Bool ret;
-
- ASSERT(sk);
-
- spin_lock_bh(&vsockSeqTableLock);
- ret = __VSockVmciInSeqTable(sk);
- spin_unlock_bh(&vsockSeqTableLock);
-
- return ret;
-}
-
-
#endif /* __UTIL_H__ */