This change consist of 2 part.
Part-1: Hgfs VMCI Interface for linux Guest.
Guest VMCI Interface: Every request will pass meta Packet as contiguous buffer and data packet
as set of struct pages. This is linux guest only. Note that even contiguous buffer will be sliced
down into many pages when passed to the host.
Use req->bufferSize instead of HGFS_PACKET_MAX so that each transport can allocate packet
of variable size.
Part-2: Hgfs VMCI Interface for linux host.
Implement new interfaces for communication between hgfsServer
and transport layer. Earlier hgfsUtil.c was implemented which
was thought to be too complicated. Now a less(?) complicated
version hgfsServerPacketUtil.c has been added.
Removed memcpy from backdoor, tools code. Write reply directly
into guest memory.
I thought about reference counting but realized that it is not
required. It would have been useful if the system could hold onto
memory for long time but we are guaranteed to release all the
memory at packet Send, so I am not too worried about it.
Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
libHgfsServer_la_SOURCES =
libHgfsServer_la_SOURCES += hgfsServer.c
libHgfsServer_la_SOURCES += hgfsServerLinux.c
+libHgfsServer_la_SOURCES += hgfsServerPacketUtil.c
libHgfsServer_la_SOURCES += hgfsDirNotifyStub.c
AM_CFLAGS =
#include "util.h"
#include "wiper.h"
#include "hgfsDirNotify.h"
+#include "hgfsTransport.h"
#if defined(_WIN32)
#include <io.h>
#endif
/* Session related callbacks. */
-static void HgfsServerSessionReceive(char const *packetIn,
- size_t packetSize,
+static void HgfsServerSessionReceive(HgfsPacket *packet,
void *clientData,
HgfsReceiveFlags flags);
static Bool HgfsServerSessionConnect(void *transportData,
- HgfsSessionSendFunc *send,
+ HgfsServerChannelCallbacks *channelCbTable,
void **clientData);
static void HgfsServerSessionDisconnect(void *clientData);
static void HgfsServerSessionClose(void *clientData);
static void HgfsServerSessionInvalidateObjects(void *clientData,
DblLnkLst_Links *shares);
-static void HgfsServerSessionSendComplete(void *clientData, char *buffer);
+static void HgfsServerSessionSendComplete(HgfsPacket *packet, void *clientData);
/*
* Callback table passed to transport and any channels.
*/
static HgfsInternalStatus
-HgfsServerClose(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerClose(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsHandle file;
char *packetOut = NULL;
size_t replySize;
HgfsFreeFileNode(file, session);
}
- if (!HgfsPackCloseReply(packetIn, status, op, &packetOut, &replySize) ||
- !HgfsPacketSend(packetOut, replySize, session, 0)) {
+ if (!HgfsPackCloseReply(input->packet, packetIn, status, op,
+ &packetOut, &replySize, session) ||
+ !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
status = HGFS_INTERNAL_STATUS_ERROR;
goto error;
}
return 0;
error:
- free(packetOut);
-
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
static HgfsInternalStatus
-HgfsServerSearchClose(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerSearchClose(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsHandle search;
char *packetOut = NULL;
size_t replySize;
goto error;
}
- if (!HgfsPackSearchCloseReply(packetIn, status, op, &packetOut, &replySize) ||
- !HgfsPacketSend(packetOut, replySize, session, 0)) {
+ if (!HgfsPackSearchCloseReply(input->packet, packetIn, status, op,
+ &packetOut, &replySize, session) ||
+ !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
status = HGFS_INTERNAL_STATUS_ERROR;
goto error;
}
return 0;
error:
- free(packetOut);
-
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
/* Opcode handlers, indexed by opcode */
static struct {
HgfsInternalStatus
- (*handler)(const char *packetIn,
- size_t packetSize,
- HgfsSessionInfo *session);
+ (*handler)(HgfsInputParam *input);
/* Minimal size of the request packet */
unsigned int minReqSize;
{ HgfsServerSymlinkCreate, HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3) },
{ HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange) },
{ HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) },
-
+ { HgfsServerRead, HGFS_SIZEOF_OP(HgfsRequestReadV3) },
+ { HgfsServerWrite, HGFS_SIZEOF_OP(HgfsRequestWriteV3) },
};
* make a copy of it. The validity of packetIn for the HGFS server is only
* within the scope of this function.
*
+ * Definitions of Meta Packet, Data packet can be looked up in hgfsChannelVmci.c
+ *
* Results:
* None
*
*/
static void
-HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- void *clientData, // IN: session info
- HgfsReceiveFlags flags) // IN: flags to indicate processing
+HgfsServerSessionReceive(HgfsPacket *packet, // IN: Hgfs Packet
+ void *clientData, // IN: session info
+ HgfsReceiveFlags flags) // IN: flags to indicate processing
{
HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
- HgfsRequest *request = (HgfsRequest *)packetIn;
+ HgfsRequest *request;
HgfsHandle id;
HgfsOp op;
HgfsStatus status;
Bool v4header = FALSE;
+ HgfsInputParam input;
+ size_t metaPacketSize;
+ char *metaPacket;
ASSERT(session);
- ASSERT(request);
if (session->state == HGFS_SESSION_STATE_CLOSED) {
LOG(4, ("%s: %d: Received packet after disconnected.\n", __FUNCTION__,
return;
}
- /* Error out if less than HgfsRequest size. */
- if (packetSize < sizeof *request) {
- if (packetSize >= sizeof id) {
+ metaPacket = HSPU_GetMetaPacket(packet, &metaPacketSize, session);
+ request = (HgfsRequest *)metaPacket;
+ ASSERT_DEVEL(request);
+ if (!request) {
+ /*
+ * How can I return error back to the client, clearly the client is either broken or
+ * malicious ? We cannot continue from here.
+ */
+ return;
+ }
+
+ /*
+ * Error out if less than HgfsRequest size.
+ */
+ if (metaPacketSize < sizeof *request) {
+ if (metaPacketSize >= sizeof id) {
id = request->id;
} else {
id = 0;
}
status = HGFS_STATUS_PROTOCOL_ERROR;
+ ASSERT_DEVEL(0);
goto err;
}
id = request->id;
op = request->op;
+
/* If it is a V4 packet then handle it appropriately. */
- if (HGFS_V4_LEGACY_OPCODE == op) {
- HgfsHeader *header = (HgfsHeader *)packetIn;
- if (packetSize < sizeof *header) {
+ if (HGFS_V4_LEGACY_OPCODE == op) {
+ HgfsHeader *header = (HgfsHeader *)metaPacket;
+ if (metaPacketSize < sizeof *header) {
status = HGFS_STATUS_PROTOCOL_ERROR;
+ ASSERT_DEVEL(0);
goto err;
}
op = header->op;
v4header = TRUE;
}
- if (!HgfsValidatePacket(packetIn, packetSize)) {
+ if (!HgfsValidatePacket(metaPacket, metaPacketSize)) {
status = HGFS_STATUS_PROTOCOL_ERROR;
LOG(4, ("%s: %d: Possible BUG! malformed packet.\n", __FUNCTION__,
__LINE__));
HGFS_ASSERT_MINIMUM_OP(op);
if (op < sizeof handlers / sizeof handlers[0]) {
- if (packetSize >= handlers[op].minReqSize) {
+ if (metaPacketSize >= handlers[op].minReqSize) {
HgfsInternalStatus internalStatus;
- internalStatus = (*handlers[op].handler)(packetIn, packetSize,
- session);
+ input.metaPacket = metaPacket;
+ input.metaPacketSize = metaPacketSize;
+ input.session = session;
+ input.packet = packet;
+ internalStatus = (*handlers[op].handler)(&input);
status = HgfsConvertFromInternalStatus(internalStatus);
} else {
/*
if (status != HGFS_STATUS_SUCCESS) {
char *packetOut;
uint32 replySize;
+ size_t replyPacketSize;
if (v4header) {
HgfsHeader *header;
-
- header = Util_SafeMalloc(sizeof *header);
- HgfsPackReplyHeaderV4(status, 0, (HgfsHeader *)packetIn, header);
+ replyPacketSize = sizeof *header;
+ header = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+ if (!header || sizeof *header > replyPacketSize) {
+ /*
+ * Transport should probably check for minimum hgfs packet size.
+ * How should we send an error back if there is no meta packet ?
+ */
+ return;
+ }
+ HgfsPackReplyHeaderV4(status, 0, (HgfsHeader *)metaPacket, header);
packetOut = (char *)header;
replySize = sizeof *header;
} else {
HgfsReply *reply;
-
- reply = Util_SafeMalloc(sizeof *reply);
+ replyPacketSize = sizeof *reply;
+ reply = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+ if (!reply || sizeof *reply > replyPacketSize) {
+ /*
+ * Transport should probably check for minimum hgfs packet size.
+ * How should we send an error back if there is no meta packet ?
+ */
+ return;
+ }
reply->id = id;
reply->status = status;
packetOut = (char *)reply;
replySize = sizeof *reply;
}
-
- if (!HgfsPacketSend(packetOut, replySize, session, 0)) {
+ LOG(4, ("Error occured for id = %u\n", (uint32)id));
+ if (!HgfsPacketSend(packet, packetOut, replySize, session, 0)) {
/* Send failed. Drop the reply. */
- free(packetOut);
+ HSPU_PutReplyPacket(packet, session);
}
}
}
*/
static Bool
-HgfsServerSessionConnect(void *transportData, // IN: transport session context
- HgfsSessionSendFunc *send, // IN: send reply callback
- void **sessionData) // OUT: server session context
+HgfsServerSessionConnect(void *transportData, // IN: transport session context
+ HgfsServerChannelCallbacks *channelCbTable, // IN: Channel callbacks
+ void **sessionData) // OUT: server session context
{
int i;
HgfsSessionInfo *session = Util_SafeMalloc(sizeof *session);
session->type = HGFS_SESSION_TYPE_REGULAR;
session->state = HGFS_SESSION_STATE_OPEN;
session->transportData = transportData;
- session->send = send;
+ session->channelCbTable = channelCbTable;
Atomic_Write(&session->refCount, 0);
/* Give our session a reference to hold while we are open. */
size_t *packetLen, // IN/OUT: packet length
HgfsReceiveFlags flags) // IN: flags
{
+ HgfsPacket packet;
ASSERT(packetIn);
ASSERT(packetOut);
ASSERT(packetLen);
hgfsStaticSession.session->type = HGFS_SESSION_TYPE_INTERNAL;
}
- HgfsServerSessionReceive(packetIn, *packetLen, hgfsStaticSession.session, 0);
+ memset(&packet, 0, sizeof packet);
+ packet.iov[0].va = (void *)packetIn;
+ packet.iov[0].len = *packetLen;
+ packet.iovCount = 1;
+ packet.metaPacket = (void *)packetIn;
+ packet.metaPacketSize = *packetLen;
+ packet.replyPacket = packetOut;
+ packet.replyPacketSize = HGFS_LARGE_PACKET_MAX;
+
+ HgfsServerSessionReceive(&packet,
+ hgfsStaticSession.session,
+ 0);
/*
* At this point, all the HGFS ops send reply synchronously. So
ASSERT(hgfsStaticSession.bufferOut);
- memcpy(packetOut, hgfsStaticSession.bufferOut,
- hgfsStaticSession.bufferOutLen);
*packetLen = hgfsStaticSession.bufferOutLen;
- HgfsServerSessionSendComplete(hgfsStaticSession.session,
- hgfsStaticSession.bufferOut);
+ HgfsServerSessionSendComplete(&packet,
+ hgfsStaticSession.session);
hgfsStaticSession.bufferOut = NULL;
}
#endif
*/
void
-HgfsServerSessionSendComplete(void *clientData, // IN: session currently unused
- char *buffer) // IN: sent buffer
+HgfsServerSessionSendComplete(HgfsPacket *packet, // IN/OUT: Hgfs packet
+ void *clientData) // IN: session info
{
- free(buffer);
+ HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
+ HSPU_PutMetaPacket(packet, session);
+ HSPU_PutReplyPacket(packet, session);
}
*/
Bool
-HgfsPacketSend(char *packet, // IN: packet buffer
- size_t packetSize, // IN: packet size
- HgfsSessionInfo *session, // IN: session info
- HgfsSendFlags flags) // IN: flags for how to process
+HgfsPacketSend(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char *packetOut, // IN: output buffer
+ size_t packetOutLen, // IN: packet size
+ HgfsSessionInfo *session, // IN: session info
+ HgfsSendFlags flags) // IN: flags for how to process
{
Bool result = FALSE;
ASSERT(packet);
+ ASSERT(packetOut);
ASSERT(session);
if (session->state == HGFS_SESSION_STATE_OPEN) {
#ifndef VMX86_TOOLS
ASSERT(session->type == HGFS_SESSION_TYPE_REGULAR);
- result = session->send(session->transportData, packet, packetSize, flags);
+ result = session->channelCbTable->send(session->transportData,
+ packet, packetOut,
+ packetOutLen, flags);
#else
/* This is internal session. */
ASSERT(session->type == HGFS_SESSION_TYPE_INTERNAL);
- hgfsStaticSession.bufferOut = packet;
- hgfsStaticSession.bufferOutLen = packetSize;
+ hgfsStaticSession.bufferOut = packetOut;
+ hgfsStaticSession.bufferOutLen = packetOutLen;
result = TRUE;
#endif
}
*/
Bool
-HgfsPackAndSendPacket(char *packet, // IN: packet to send
- size_t packetSize, // IN: packet size
+HgfsPackAndSendPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char *packetOut, // IN: Output packet to send
+ size_t packetOutLen, // IN: Output packet size
HgfsInternalStatus status, // IN: status
HgfsHandle id, // IN: id of the request packet
HgfsSessionInfo *session, // IN: session info
HgfsSendFlags flags) // IN: flags how to send
{
- HgfsReply *reply = (HgfsReply *)packet;
+ HgfsReply *reply = (HgfsReply *)packetOut;
ASSERT(packet);
+ ASSERT(packetOut);
ASSERT(session);
- ASSERT(packetSize <= HGFS_LARGE_PACKET_MAX);
+ ASSERT(packetOutLen <= HGFS_LARGE_PACKET_MAX);
reply->id = id;
reply->status = HgfsConvertFromInternalStatus(status);
- return HgfsPacketSend(packet, packetSize, session, flags);
+ return HgfsPacketSend(packet, packetOut, packetOutLen, session, flags);
}
* Allocates hgfs reply packet and initializes its header.
*
* Results:
- * Size of the allocated packet.
+ * TRUE on success, FALSE on failure.
*
* Side effects:
* None
*-----------------------------------------------------------------------------
*/
-void
-HgfsAllocInitReply(char const *packetIn, // IN: incoming packet
+Bool
+HgfsAllocInitReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
size_t payloadSize, // IN: payload size
HgfsInternalStatus status, // IN: reply status
char **packetOut, // OUT: allocated reply
void **payload, // OUT: pointer to the reply payload
- size_t *packetSize) // OUT: size of the allocated packet
+ size_t *packetSize, // OUT: size of the allocated packet
+ HgfsSessionInfo *session) // IN: Session Info
{
HgfsRequest *request = (HgfsRequest *)packetIn;
+ size_t replyPacketSize;
size_t headerSize = 0; /* Replies prior to V3 do not have a header. */
+ HgfsInternalStatus dummyStatus;
+
if (HGFS_V4_LEGACY_OPCODE == request->op) {
headerSize = sizeof(HgfsHeader);
} else if (request->op < HGFS_OP_CREATE_SESSION_V4 &&
request->op > HGFS_OP_RENAME_V2) {
headerSize = sizeof(HgfsReply);
}
- *packetSize = headerSize + payloadSize;
- *packetOut = Util_SafeCalloc(1, *packetSize);
+ replyPacketSize = *packetSize = headerSize + payloadSize;
+ *packetOut = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, *packetSize, replyPacketSize, dummyStatus, exit);
+
*payload = *packetOut + headerSize;
if (HGFS_V4_LEGACY_OPCODE == request->op) {
HgfsPackReplyHeaderV4(status,
HgfsRequest const *request = (HgfsRequest const *)packetIn;
HgfsPackLegacyReplyHeader(status, request->id, (HgfsReply *)*packetOut);
}
+
+ return TRUE;
+exit:
+ return FALSE;
}
*/
Bool
-HgfsPackOpenReply(char const *packetIn, // IN: incoming packet
+HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsFileOpenInfo *openInfo, // IN: open info struct
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session info
{
+ Bool result;
ASSERT(packetIn);
ASSERT(openInfo);
ASSERT(packetSize);
case HGFS_OP_OPEN_V3: {
HgfsReplyOpenV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
HgfsPackOpenReplyV3(openInfo, reply);
break;
}
case HGFS_OP_OPEN_V2: {
HgfsReplyOpenV2 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
HgfsPackOpenV2Reply(openInfo, reply);
break;
}
case HGFS_OP_OPEN: {
HgfsReplyOpen *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
HgfsPackOpenV1Reply(openInfo, reply);
break;
}
default:
- return FALSE;
+ goto error;
}
return TRUE;
+error:
+ return FALSE;
}
* Pack hgfs close reply to the HgfsReplyClose(V3) structure.
*
* Results:
- * Always TRUE.
+ * TRUE on success, FALSE on failure
*
* Side effects:
* None
*/
Bool
-HgfsPackCloseReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: request type
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
+ Bool result;
ASSERT(packetIn);
ASSERT(packetSize);
case HGFS_OP_CLOSE_V3: {
HgfsReplyCloseV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_CLOSE: {
HgfsReplyClose *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
+ result = FALSE;
NOT_REACHED();
- return FALSE;
}
- return TRUE;
+ return result;
}
* Pack hgfs SearchClose reply into a HgfsReplySearchClose(V3) structure.
*
* Results:
- * Always TRUE, except when it is called with a
- * wrong op (which is a programming error).
+ * TRUE on success, FALSE on failure.
*
* Side effects:
* None
*/
Bool
-HgfsPackSearchCloseReply(char const *packetIn, // IN: incoming packet
+HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: request type
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
+ Bool result;
ASSERT(packetIn);
ASSERT(packetSize);
case HGFS_OP_SEARCH_CLOSE_V3: {
HgfsReplyCloseV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_SEARCH_CLOSE: {
HgfsReplyClose *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
NOT_REACHED();
- return FALSE;
+ result = FALSE;
}
- return TRUE;
+ return result;
}
*/
Bool
-HgfsPackDeleteReply(char const *packetIn, // IN: incoming packet
+HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: requested operation
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
Bool result = TRUE;
ASSERT(packetIn);
case HGFS_OP_DELETE_DIR_V3: {
HgfsReplyDeleteV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_DELETE_FILE_V2:
case HGFS_OP_DELETE_DIR: {
HgfsReplyDelete *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
*/
Bool
-HgfsPackRenameReply(char const *packetIn, // IN: incoming packet
+HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: requested operation
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
Bool result = TRUE;
ASSERT(packetIn);
case HGFS_OP_RENAME_V3: {
HgfsReplyRenameV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_RENAME_V2:
case HGFS_OP_RENAME: {
HgfsReplyRename *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
*/
Bool
-HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet
+HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsFileAttrInfo *attr, // IN: attr stucture
const char *utf8TargetName, // IN: optional target name
uint32 utf8TargetNameLen, // IN: file name length
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
+ Bool result;
ASSERT(packetIn);
ASSERT(attr);
HgfsReplyGetattrV3 *reply;
uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
- HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
+
if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
free(reply);
- return FALSE;
+ goto error;
}
HgfsPackGetattrReplyPayloadV3(attr, utf8TargetName, utf8TargetNameLen, reply);
break;
HgfsRequest *request = (HgfsRequest *)packetIn;
uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
- HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
+
if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
free(reply);
- return FALSE;
+ goto error;
}
HgfsPackGetattrReplyPayloadV2(request->id,
status,
HgfsReplyGetattr *reply;
HgfsRequest *request = (HgfsRequest *)packetIn;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result == FALSE) {
+ goto error;
+ }
+
HgfsPackGetattrReplyPayloadV1(request->id, status, attr, reply);
break;
}
default:
LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__));
NOT_REACHED();
-
- return FALSE;
+ result = FALSE;
}
- return TRUE;
+error:
+ return result;
}
*/
Bool
-HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet
+HgfsPackSearchReadReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
const char *utf8Name, // IN: file name
size_t utf8NameLen, // IN: file name length
HgfsFileAttrInfo *attr, // IN: file attr struct
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
+ Bool result = TRUE;
ASSERT(packetIn);
*packetOut = NULL;
HgfsReplySearchReadV3 *reply;
uint32 payloadSize = sizeof *reply + utf8NameLen + sizeof(HgfsDirEntry);
- HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize);
+ if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+ (void **)&reply, packetSize, session)) {
+ result = FALSE;
+ goto error;
+ }
+
if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
free(reply);
- return FALSE;
+ result = FALSE;
+ goto error;
}
HgfsPackSearchReadReplyPayloadV3(attr, utf8Name, utf8NameLen, reply);
break;
HgfsReplySearchReadV2 *reply;
uint32 payloadSize = sizeof *reply + utf8NameLen;
- HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize);
+ if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+ (void **)&reply, packetSize, session)) {
+ result = FALSE;
+ goto error;
+ }
+
if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
free(reply);
- return FALSE;
+ result = FALSE;
+ goto error;
}
HgfsPackSearchReadReplyPayloadV2(attr,
utf8Name,
HgfsReplySearchRead *reply;
uint32 payloadSize = sizeof *reply + utf8NameLen;
- HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
- (void **)&reply, packetSize);
+ if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+ (void **)&reply, packetSize, session)) {
+ result = FALSE;
+ goto error;
+ }
+
if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
free(reply);
- return FALSE;
+ result = FALSE;
+ goto error;
}
HgfsPackSearchReadReplyPayloadV1(attr,
utf8Name,
default: {
LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__));
NOT_REACHED();
- return FALSE;
+ result = FALSE;
}
}
- return TRUE;
+error:
+ return result;
}
*/
Bool
-HgfsPackSetattrReply(char const *packetIn, // IN: incoming packet
+HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: request type
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
Bool result = TRUE;
case HGFS_OP_SETATTR_V3: {
HgfsReplySetattrV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_SETATTR_V2:
case HGFS_OP_SETATTR: {
HgfsReplySetattr *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
*/
Bool
-HgfsPackCreateDirReply(char const *packetIn, // IN: create dir operation version
+HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: create dir operation version
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: request type
char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN: Session Info
{
Bool result = TRUE;
case HGFS_OP_CREATE_DIR_V3: {
HgfsReplyCreateDirV3 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_CREATE_DIR_V2: {
HgfsReplyCreateDirV2 *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
case HGFS_OP_CREATE_DIR: {
HgfsReplyCreateDir *reply;
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
break;
}
default:
*/
Bool
-HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
+HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: request type
- uint32 actualSize, // IN: amount written
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize) // OUT: size of packet
+ uint32 actualSize, // IN: amount written
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session) // IN:Session Info
{
HgfsReplyWriteWin32StreamV3 *reply;
+ Bool result;
ASSERT(packetIn);
return FALSE;
}
- HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
- (void **)&reply, packetSize);
- reply->actualSize = actualSize;
+ result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+ (void **)&reply, packetSize, session);
+ if (result != FALSE) {
+ reply->actualSize = actualSize;
+ }
- return TRUE;
+ return result;
}
# define HGFS_LOCK_DESTROY(lock) MXUser_DestroyExclLock(lock)
#endif
+#ifdef _WIN32
+# define HGFS_REPLYPKT_STATUS RPC_S_PROTOCOL_ERROR
+#else
+# define HGFS_REPLYPKT_STATUS EPROTO
+#endif
+
+#define HGFS_REPLYPKT_CHECK(replyPacket, replySize, replyPacketSize, status, label) \
+ do { \
+ LOG(4, ("%s: \n", __FUNCTION__)); \
+ ASSERT_DEVEL(replyPacket); \
+ if (!replyPacket || ((replySize) > (replyPacketSize))) { \
+ status = HGFS_REPLYPKT_STATUS; \
+ goto label; \
+ } \
+ } while(0)
+
/*
* Does this platform have oplock support? We define it here to avoid long
/* Session is dynamic or internal. */
HgfsSessionInfoType type;
- /* Function to send reply for a packet after processing. */
- HgfsSessionSendFunc *send;
+ /* Function callbacks into Hgfs Channels. */
+ HgfsServerChannelCallbacks *channelCbTable;
/* Lock to ensure some fileIO requests are atomic for a handle. */
HgfsLock *fileIOLock;
HgfsServerLock serverLock;
} ServerLockData;
+typedef
+struct HgfsInputParam {
+ const char *metaPacket;
+ size_t metaPacketSize;
+ HgfsSessionInfo *session;
+ HgfsPacket *packet;
+}
+HgfsInputParam;
Bool
HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct
*/
HgfsInternalStatus
-HgfsServerOpen(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerOpen(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerRead(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerRead(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerWrite(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerWrite(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerSearchOpen(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerSearchRead(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerSearchRead(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerGetattr(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerGetattr(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerSetattr(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerSetattr(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerCreateDir(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerCreateDir(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerDeleteFile(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerDeleteDir(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerRename(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerRename(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerQueryVolume(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerSymlinkCreate(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerServerLockChange(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerServerLockChange(HgfsInputParam *input); // IN: Input params
HgfsInternalStatus
-HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session); // IN: opaque transport data
+HgfsServerWriteWin32Stream(HgfsInputParam *input); // IN: Input params
/* Unpack/pack requests/reply helper functions. */
HgfsFileOpenInfo *openInfo); // IN/OUT: open info struct
Bool
-HgfsPackOpenReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsFileOpenInfo *openInfo, // IN: open info struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: outgoing packet size
-
+HgfsPackOpenReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsFileOpenInfo *openInfo, // IN: open info struct
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session info
Bool
HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet
size_t packetSize, // IN: request packet size
uint32 *caseFlags); // OUT: case-sensitivity flags
Bool
-HgfsPackDeleteReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackDeleteReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: requested operation
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet
uint32 *newCaseFlags); // OUT: new case-sensitivity flags
Bool
-HgfsPackRenameReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: requested operation
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackRenameReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: requested operation
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
-HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsFileAttrInfo *attr, // IN: attr stucture
- const char *utf8TargetName, // IN: optional target name
- uint32 utf8TargetNameLen, // IN: file name length
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
-
+HgfsPackGetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsFileAttrInfo *attr, // IN: attr stucture
+ const char *utf8TargetName, // IN: optional target name
+ uint32 utf8TargetNameLen, // IN: file name length
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet
size_t packetSize, // IN: packet size
uint32 *offset); // OUT: entry offset
Bool
-HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- const char *utf8Name, // IN: file name
- size_t utf8NameLen, // IN: file name length
- HgfsFileAttrInfo *attr, // IN: file attr struct
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackSearchReadReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ const char *utf8Name, // IN: file name
+ size_t utf8NameLen, // IN: file name length
+ HgfsFileAttrInfo *attr, // IN: file attr struct
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet
uint32 *caseFlags); // OUT: case-sensitivity flags
Bool
-HgfsPackSetattrReply(char const *packetIn, // IN: setattrOp operation version
+HgfsPackSetattrReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
HgfsInternalStatus status, // IN: reply status
HgfsOp op, // IN: request type
char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
-
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet
HgfsCreateDirInfo *info); // IN/OUT: info struct
Bool
-HgfsPackCreateDirReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackCreateDirReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: create dir operation version
+ HgfsInternalStatus status , // IN: reply status
+ HgfsOp op, // IN: request type
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
Bool
HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
Bool *doSecurity); // OUT: restore sec.str.
Bool
-HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- uint32 actualSize, // IN: amount written
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackWriteWin32StreamReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: request type
+ uint32 actualSize, // IN: amount written
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN:Session Info
+
Bool
HgfsUnpackCloseRequest(char const *packetIn, // IN: request packet
size_t packetSize, // IN: request packet size
HgfsOp *op, // OUT: request type
HgfsHandle *file); // OUT: Handle to close
+
Bool
-HgfsPackCloseReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: request type
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
+
Bool
HgfsUnpackSearchCloseRequest(char const *packetIn, // IN: request packet
size_t packetSize, // IN: request packet size
HgfsOp *op, // OUT: request type
HgfsHandle *file); // OUT: Handle to close
+
Bool
-HgfsPackSearchCloseReply(char const *packetIn, // IN: incoming packet
- HgfsInternalStatus status, // IN: reply status
- HgfsOp op, // IN: request type
- char **packetOut, // OUT: outgoing packet
- size_t *packetSize); // OUT: size of packet
+HgfsPackSearchCloseReply(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char const *packetIn, // IN: incoming packet
+ HgfsInternalStatus status, // IN: reply status
+ HgfsOp op, // IN: request type
+ char **packetOut, // OUT: outgoing packet
+ size_t *packetSize, // OUT: size of packet
+ HgfsSessionInfo *session); // IN: Session Info
/* Node cache functions. */
/* Transport related functions. */
Bool
-HgfsPackAndSendPacket(char *packet, // IN: packet to send
- size_t packetSize, // IN: packet size
- HgfsInternalStatus status, // IN: status
- HgfsHandle id, // IN: id of the request packet
- HgfsSessionInfo *session, // IN: session info
- HgfsSendFlags flags); // IN: flags how to send
+HgfsPackAndSendPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char *packetOut, // IN: Output packet to send
+ size_t packetOutLen, // IN: Output packet size
+ HgfsInternalStatus status, // IN: status
+ HgfsHandle id, // IN: id of the request packet
+ HgfsSessionInfo *session, // IN: session info
+ HgfsSendFlags flags); // IN: flags how to send
Bool
-HgfsPacketSend(char *packet, // IN: packet buffer
- size_t packetSize, // IN: packet size
- HgfsSessionInfo *session, // IN: session info
- HgfsSendFlags flags); // IN: flags how to send
+HgfsPacketSend(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ char *packetOut, // IN: Output packet buffer
+ size_t packetOutLen, // IN: Output packet size
+ HgfsSessionInfo *session, // IN: session info
+ HgfsSendFlags flags); // IN: flags how to send
Bool
HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo, // IN: Hgfs file handle
HgfsOpenFlags *flags); // IN/OUT: open mode
+
+void *
+HSPU_GetBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: start index of iov
+ void **buf, // OUT: Contigous buffer
+ size_t bufSize, // IN: Size of buffer
+ Bool *isAllocated, // OUT: Was buffer allocated ?
+ uint32 mappingType, // IN: Readable/ Writeable ?
+ HgfsSessionInfo *session); // IN: Session Info
+
+void *
+HSPU_GetMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ size_t *metaPacketSize, // OUT: Size of metaPacket
+ HgfsSessionInfo *session); // IN: Session Info
+
+void *
+HSPU_GetDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 mappingType, // IN: Readable/ Writeable ?
+ HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: Start of iov
+ void **buf, // IN/OUT: Buffer to be freed
+ size_t *bufSize, // IN: Size of the buffer
+ Bool *isAllocated, // IN: Was buffer allocated ?
+ uint32 mappingType, // IN: Readable/ Writeable ?
+ HgfsSessionInfo *session); // IN: Session info
+
+void
+HSPU_PutDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_CopyBufToDataIovec(HgfsPacket *packet, // IN/OUT: Hgfs packet
+ void *buf, // IN: Buffer to copy from
+ uint32 bufSize, // IN: Size of buffer
+ HgfsSessionInfo *session);// IN: Session Info
+void
+HSPU_CopyBufToIovec(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: start index into iov
+ void *buf, // IN: Buffer
+ size_t bufSize, // IN: Size of buffer
+ HgfsSessionInfo *session); // IN: Session Info
+void *
+HSPU_GetReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ size_t *replyPacketSize, //IN/OUT: Size of reply Packet
+ HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session); // IN: Session Info
#endif /* __HGFS_SERVER_INT_H__ */
*/
HgfsInternalStatus
-HgfsServerOpen(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerOpen(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsNameStatus nameStatus;
HgfsInternalStatus status;
int newFd = -1;
goto exit;
}
- if (HgfsPackOpenReply(packetIn, status, &openInfo, &packetOut,
- &packetOutSize)) {
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (HgfsPackOpenReply(input->packet, packetIn, status, &openInfo, &packetOut,
+ &packetOutSize, session)) {
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
} else {
status = EPROTO;
*/
HgfsInternalStatus
-HgfsServerRead(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerRead(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ HgfsSessionInfo *session = input->session;
HgfsRequest *header = (HgfsRequest *)packetIn;
int fd;
int error;
char *payload;
uint32 *replyActualSize;
size_t replySize;
+ size_t replyPacketSize;
char *packetOut;
ASSERT(packetIn);
ASSERT(session);
- if (header->op == HGFS_OP_READ_V3) {
+ if (header->op == HGFS_OP_READ_FAST_V3) {
+ HgfsRequestReadV3 *request =
+ (HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+ HgfsReplyReadV3 *reply;
+
+ file = request->file;
+ offset = request->offset;
+ requiredSize = request->requiredSize;
+
+ replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply) - 1;
+ /* Get a data packet buffer that is writeable */
+ payload = HSPU_GetDataPacketBuf(input->packet, HGFS_BUF_WRITEABLE, session);
+ if (!payload) {
+ ASSERT_DEVEL(payload);
+ status = EPROTO;
+ goto error;
+ }
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
+ reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+
+ replyActualSize = &reply->actualSize;
+ reply->reserved = 0;
+
+ } else if (header->op == HGFS_OP_READ_V3) {
HgfsRequestReadV3 *request =
(HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
HgfsReplyReadV3 *reply;
extra = HGFS_LARGE_PACKET_MAX - replySize;
/*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
+ * requiredSize is user-provided, so this test must be carefully
+ * written to prevent wraparounds.
+ */
if (requiredSize > extra) {
/*
* The client wants to read more bytes than our payload can handle.
* Truncate the request
*/
- requiredSize = extra;
+ requiredSize = extra;
}
-
- packetOut = Util_SafeMalloc(replySize + requiredSize);
+ replyPacketSize = replySize + requiredSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
payload = reply->payload;
replyActualSize = &reply->actualSize;
requiredSize = extra;
}
- packetOut = Util_SafeMalloc(replySize + requiredSize);
+ replyPacketSize = replySize + requiredSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
reply = (HgfsReplyRead *)packetOut;
payload = reply->payload;
replyActualSize = &reply->actualSize;
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
- free(packetOut);
- return status;
+ goto error;
}
if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__));
- free(packetOut);
- return EBADF;
+ status = EBADF;
+ goto error;
}
#if defined(GLIBC_VERSION_21) || defined(__APPLE__)
LOG(4, ("%s: read %d bytes\n", __FUNCTION__, error));
*replyActualSize = error;
- replySize += error;
+
+ if (header->op == HGFS_OP_READ_FAST_V3) {
+ HSPU_PutDataPacketBuf(input->packet, session);
+ } else {
+ replySize += error;
+ }
/* Send the reply. */
- if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, session, 0)) {
+ if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize, 0,
+ header->id, session, 0)) {
status = 0;
goto error;
}
- return 0;
+ return 0;
error:
- free(packetOut);
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerWrite(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerWrite(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsRequest *header = (HgfsRequest *)packetIn;
- uint32 extra;
HgfsInternalStatus status;
int fd;
int error;
char *payload;
uint32 *actualSize;
size_t replySize;
+ size_t replyPacketSize;
char *packetOut;
ASSERT(packetIn);
ASSERT(session);
- if (header->op == HGFS_OP_WRITE_V3) {
+ if (header->op == HGFS_OP_WRITE_FAST_V3) {
HgfsRequestWriteV3 *request;
HgfsReplyWriteV3 *reply;
replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
- packetOut = Util_SafeMalloc(replySize);
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
/* Enforced by the dispatch function */
ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
- extra = packetSize - (HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
file = request->file;
flags = request->flags;
offset = request->offset;
- payload = request->payload;
requiredSize = request->requiredSize;
+ reply->reserved = 0;
actualSize = &reply->actualSize;
+ /* Get a data packet buffer that is readable */
+ payload = HSPU_GetDataPacketBuf(input->packet, HGFS_BUF_READABLE, session);
+ if (!payload) {
+ ASSERT_DEVEL(payload);
+ status = EPROTO;
+ goto error;
+ }
+
+ } else if (header->op == HGFS_OP_WRITE_V3) {
+ HgfsRequestWriteV3 *request;
+ HgfsReplyWriteV3 *reply;
+ uint32 extra;
+
+ replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
+
+ request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+ reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+
+ /* Enforced by the dispatch function */
+ ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+ extra = packetSize - (HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+
+ file = request->file;
+ flags = request->flags;
+ offset = request->offset;
+ requiredSize = request->requiredSize;
reply->reserved = 0;
+ actualSize = &reply->actualSize;
+
+ payload = request->payload;
+
+ /*
+ * requiredSize is user-provided, so this test must be carefully
+ * written to prevent wraparounds.
+ */
+ if (requiredSize > extra) {
+ requiredSize = extra;
+ }
+
} else {
HgfsRequestWrite *request;
HgfsReplyWrite *reply;
+ uint32 extra;
replySize = sizeof *reply;
- packetOut = Util_SafeMalloc(replySize);
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
request = (HgfsRequestWrite *)packetIn;
reply = (HgfsReplyWrite *)packetOut;
payload = request->payload;
requiredSize = request->requiredSize;
actualSize = &reply->actualSize;
+
+ /*
+ * requiredSize is user-provided, so this test must be carefully
+ * written to prevent wraparounds.
+ */
+ if (requiredSize > extra) {
+ requiredSize = extra;
+ }
}
- LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u, extra %u\n",
- __FUNCTION__, file, offset, requiredSize, extra));
+ LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u\n",
+ __FUNCTION__, file, offset, requiredSize));
/* Get the file desriptor from the cache */
status = HgfsGetFd(file, session, ((flags & HGFS_WRITE_APPEND) ?
if (status != 0) {
LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
- free(packetOut);
- return status;
+ goto error;
}
if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
- free(packetOut);
- return EBADF;
- }
-
- /*
- * requiredSize is user-provided, so this test must be carefully
- * written to prevent wraparounds.
- */
- if (requiredSize > extra) {
- /*
- * The driver wants to write more bytes than there is in its payload.
- * Truncate the request
- */
- requiredSize = extra;
+ status = EBADF;
+ goto error;
}
#if defined(GLIBC_VERSION_21) || defined(__APPLE__)
*actualSize = error;
status = 0;
- if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
- session, 0)) {
+ if (header->op == HGFS_OP_WRITE_FAST_V3) {
+ HSPU_PutDataPacketBuf(input->packet, session);
+ }
+
+ if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
+ 0, header->id, session, 0)) {
goto error;
}
+
return 0;
error:
- free(packetOut);
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerSearchOpen(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsRequest *header;
HgfsHandle *replySearch;
uint32 extra;
uint32 dirNameLength;
HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
size_t replySize;
+ size_t replyPacketSize;
char *packetOut;
HgfsShareInfo shareInfo;
HgfsReplySearchOpenV3 *replyV3;
replySize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- packetOut = Util_SafeMalloc(replySize);
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
requestV3 = (HgfsRequestSearchOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
replyV3 = (HgfsReplySearchOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
HgfsRequestSearchOpen *request = (HgfsRequestSearchOpen *)packetIn;
replySize = sizeof (HgfsReplySearchOpen);
- packetOut = Util_SafeMalloc(replySize);
+ replyPacketSize = replySize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
/* Enforced by the dispatch function */
ASSERT(packetSize >= sizeof *request);
*/
*replySearch = handle;
- if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
- session, 0)) {
+ if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
+ 0, header->id, session, 0)) {
status = 0;
goto exit;
}
return 0;
exit:
- free(packetOut);
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerSearchRead(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerSearchRead(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
uint32 requestedOffset;
HgfsFileAttrInfo attr;
HgfsInternalStatus status;
* since what filesystems allow dent lengths as high as 6144 bytes?
*/
status = 0;
- if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen,
- &attr, &packetOut, &packetOutSize)) {
+ if (!HgfsPackSearchReadReply(input->packet, packetIn, status, entryName, entryNameLen,
+ &attr, &packetOut, &packetOutSize, session)) {
status = EPROTO;
}
free(dent);
if (status == 0 &&
- !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ !HgfsPacketSend(input->packet,
+ packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
return status;
}
free(search.utf8ShareName);
LOG(4, ("%s: no entry\n", __FUNCTION__));
status = 0;
- if (!HgfsPackSearchReadReply(packetIn, status, NULL, 0, &attr,
- &packetOut, &packetOutSize)) {
+ if (!HgfsPackSearchReadReply(input->packet, packetIn, status, NULL, 0, &attr,
+ &packetOut, &packetOutSize, session)) {
status = EPROTO;
}
if (status == 0 &&
- !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
return status;
}
*/
HgfsInternalStatus
-HgfsServerGetattr(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerGetattr(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
char *localName;
HgfsAttrHint hints = 0;
HgfsFileAttrInfo attr;
}
targetNameLen = targetName ? strlen(targetName) : 0;
}
- status = HgfsPackGetattrReply(packetIn, status, &attr, targetName,
- targetNameLen, &packetOut, &packetOutSize) ? 0 : EPROTO;
+ status = HgfsPackGetattrReply(input->packet, packetIn, status, &attr, targetName,
+ targetNameLen, &packetOut, &packetOutSize, session) ? 0 : EPROTO;
free(targetName);
if (status == 0 &&
- !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
exit:
*/
HgfsInternalStatus
-HgfsServerSetattr(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerSetattr(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsInternalStatus status;
HgfsFileAttrInfo attr;
char *cpName;
status = HgfsSetattrFromName(cpName, cpNameSize, &attr, hints,
caseFlags, session);
}
- if (!HgfsPackSetattrReply(packetIn, status, attr.requestType, &packetOut, &packetOutSize)) {
+ if (!HgfsPackSetattrReply(input->packet, packetIn, status, attr.requestType,
+ &packetOut, &packetOutSize, session)) {
status = EPROTO;
goto exit;
}
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
/* We can't send the packet, ignore the error if any. */
}
status = 0;
*/
HgfsInternalStatus
-HgfsServerCreateDir(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerCreateDir(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsNameStatus nameStatus;
HgfsCreateDirInfo info;
char *localName;
LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
return error;
}
- if (!HgfsPackCreateDirReply(packetIn, 0, info.requestType,
- &packetOut, &packetOutSize)) {
+ if (!HgfsPackCreateDirReply(input->packet, packetIn, 0, info.requestType,
+ &packetOut, &packetOutSize, session)) {
return EPROTO;
}
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
return 0;
}
*/
HgfsInternalStatus
-HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerDeleteFile(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsNameStatus nameStatus;
char *localName;
int error;
return error;
}
- if (!HgfsPackDeleteReply(packetIn, 0, op, &packetOut, &packetOutSize)) {
+ if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
+ &packetOutSize, session)) {
return EPROTO;
}
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
return 0;
}
*/
HgfsInternalStatus
-HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerDeleteDir(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsNameStatus nameStatus;
char *localName = NULL;
int error;
return error;
}
- if (!HgfsPackDeleteReply(packetIn, 0, op, &packetOut, &packetOutSize)) {
+ if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
+ &packetOutSize, session)) {
return EPROTO;
}
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
return 0;
}
*/
HgfsInternalStatus
-HgfsServerRename(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerRename(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsNameStatus nameStatus;
char *localOldName = NULL;
size_t localOldNameLen;
*/
status = 0;
HgfsUpdateNodeNames(localOldName, localNewName, session);
- if (!HgfsPackRenameReply(packetIn, status, op, &packetOut, &packetOutSize)) {
+ if (!HgfsPackRenameReply(input->packet, packetIn, status, op, &packetOut,
+ &packetOutSize, session)) {
status = EPROTO;
goto exit;
}
- if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
- free(packetOut);
+ if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+ HSPU_PutReplyPacket(input->packet, session);
}
exit:
*/
HgfsInternalStatus
-HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerQueryVolume(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsRequest *header;
uint32 extra;
char *utf8Name = NULL;
uint64 *totalBytes;
char *packetOut;
size_t packetOutSize;
+ size_t replyPacketSize;
HgfsShareInfo shareInfo;
ASSERT(packetIn);
HgfsReplyQueryVolumeV3 *replyV3;
packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- packetOut = Util_SafeMalloc(packetOutSize);
+ replyPacketSize = packetOutSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
replyV3 = (HgfsReplyQueryVolumeV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
/*
HgfsReplyQueryVolume *reply;
packetOutSize = sizeof *reply;
- packetOut = Util_SafeMalloc(packetOutSize);
+ replyPacketSize = packetOutSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
reply = (HgfsReplyQueryVolume *)packetOut;
freeBytes = &reply->freeBytes;
/* Enforced by the dispatch function. */
ASSERT(packetSize >= sizeof *request);
extra = packetSize - sizeof *request;
-
fileName = request->fileName.name;
fileNameLength = request->fileName.length;
}
*totalBytes = outTotalBytes;
status = 0;
- if (!HgfsPackAndSendPacket(packetOut, packetOutSize, status, header->id,
- session, 0)) {
+ if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
+ status, header->id, session, 0)) {
goto exit;
}
return status;
exit:
- free(packetOut);
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerSymlinkCreate(HgfsInputParam *input) // IN: Input params
{
+ const char *packetIn = input->metaPacket;
+ size_t packetSize = input->metaPacketSize;
+ HgfsSessionInfo *session = input->session;
HgfsRequest *header;
uint32 extra;
char *localSymlinkName = NULL;
HgfsShareOptions configOptions;
char *packetOut = NULL;
size_t packetOutSize;
+ size_t replyPacketSize;
HgfsInternalStatus status = 0;
size_t localSymlinkNameLen;
HgfsShareInfo shareInfo;
*/
if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC ||
targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
- LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
-
- return EPARAMETERNOTSUPPORTED;
- }
-
- packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
- packetOut = Util_SafeMalloc(packetOutSize);
- replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
- replyV3->reserved = 0;
- } else {
- HgfsRequestSymlinkCreate *request;
- HgfsFileName *targetNameP;
- request = (HgfsRequestSymlinkCreate *)packetIn;
-
- /* Enforced by the dispatch function. */
- ASSERT(packetSize >= sizeof *request);
- extra = packetSize - sizeof *request;
-
- symlinkName = request->symlinkName.name;
- symlinkNameLength = request->symlinkName.length;
-
- /*
- * targetName starts after symlinkName + the variable length array
- * in symlinkName.
- */
-
- targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength);
- targetName = targetNameP->name;
- targetNameLength = targetNameP->length;
- packetOutSize = sizeof(struct HgfsReplySymlinkCreate);
- packetOut = Util_SafeMalloc(packetOutSize);
- }
-
- /*
- * request->symlinkName.length is user-provided, so this test must
- * be carefully written to prevent wraparounds.
- */
-
- if (symlinkNameLength > extra) {
- /* The input packet is smaller than the request */
- status = EPROTO;
- goto exit;
- }
-
- /*
- * It is now safe to read the symlink file name and the
- * "targetName" field
- */
+ LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
+ return EPARAMETERNOTSUPPORTED;
+ }
+
+ packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
+ replyPacketSize = packetOutSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
+ replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+ replyV3->reserved = 0;
+
+ } else {
+ HgfsRequestSymlinkCreate *request;
+ HgfsFileName *targetNameP;
+ request = (HgfsRequestSymlinkCreate *)packetIn;
+
+ /* Enforced by the dispatch function. */
+ ASSERT(packetSize >= sizeof *request);
+ extra = packetSize - sizeof *request;
+
+ symlinkName = request->symlinkName.name;
+ symlinkNameLength = request->symlinkName.length;
+
+ /*
+ * targetName starts after symlinkName + the variable length array
+ * in symlinkName.
+ */
+
+ targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength);
+ targetName = targetNameP->name;
+ targetNameLength = targetNameP->length;
+ packetOutSize = sizeof(struct HgfsReplySymlinkCreate);
+ replyPacketSize = packetOutSize;
+ packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+ HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+ }
+
+ /*
+ * request->symlinkName.length is user-provided, so this test must
+ * be carefully written to prevent wraparounds.
+ */
+
+ if (symlinkNameLength > extra) {
+ /* The input packet is smaller than the request */
+ status = EPROTO;
+ goto exit;
+ }
+
+ /*
+ * It is now safe to read the symlink file name and the
+ * "targetName" field
+ */
nameStatus = HgfsServerGetShareInfo(symlinkName,
symlinkNameLength,
}
status = 0;
- if (!HgfsPackAndSendPacket(packetOut, packetOutSize, status, header->id,
+ if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
+ status, header->id,
session, 0)) {
goto exit;
}
exit:
free(localSymlinkName);
- free(packetOut);
+ HSPU_PutReplyPacket(input->packet, session);
return status;
}
*/
HgfsInternalStatus
-HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerWriteWin32Stream(HgfsInputParam *input) // IN: Input params
{
return EOPNOTSUPP;
}
*/
HgfsInternalStatus
-HgfsServerServerLockChange(char const *packetIn, // IN: incoming packet
- size_t packetSize, // IN: size of packet
- HgfsSessionInfo *session) // IN: session info
+HgfsServerServerLockChange(HgfsInputParam *input) // IN: Input params
{
return EOPNOTSUPP;
}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsServerPacketUtil.c --
+ *
+ * Utility functions for manipulating packet used by hgfs server code
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vmware.h"
+#include "hgfsServer.h"
+#include "hgfsServerInt.h"
+#include "util.h"
+
+#define LOGLEVEL_MODULE hgfs
+#include "loglevel_user.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetReplyPacket --
+ *
+ * Get a reply packet given an hgfs packet.
+ * Guest mappings may be established.
+ *
+ * Results:
+ * Pointer to reply packet.
+ *
+ * Side effects:
+ * Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ size_t *replyPacketSize, // IN/OUT: Size of reply Packet
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ ASSERT(session);
+ if (packet->replyPacket) {
+ /*
+ * When we are transferring packets over backdoor, reply packet
+ * is a static buffer. Backdoor should always return from here.
+ */
+ LOG(4, ("Exising reply packet %s %Zu %Zu\n", __FUNCTION__,
+ *replyPacketSize, packet->replyPacketSize));
+ /*
+ * HgfsServer_ProcessPacket does not tell us the real size of packetOut.
+ * It assumes that size of reply packet can never be bigger than size of
+ * the outgoing packet. I changed it to HGFS_LARGE_PACKET_MAX.
+ */
+ ASSERT_DEVEL(*replyPacketSize <= packet->replyPacketSize);
+ goto exit;
+ } else if (session->channelCbTable && session->channelCbTable->getWriteVa) {
+ /* Can we write directly into guest memory ? */
+ if (packet->metaPacket) {
+ LOG(10, ("%s Using meta packet for reply packet\n", __FUNCTION__));
+ ASSERT_DEVEL(*replyPacketSize <= packet->metaPacketSize);
+ packet->replyPacket = packet->metaPacket;
+ packet->replyPacketSize = packet->metaPacketSize;
+ goto exit;
+ }
+
+ /* This should really never happen in existing scenarios */
+ ASSERT_DEVEL(0);
+ LOG(10, ("%s Mapping meta packet for reply packet\n", __FUNCTION__));
+ packet->replyPacket = HSPU_GetBuf(packet, 0, &packet->metaPacket,
+ packet->metaPacketSize,
+ &packet->metaPacketIsAllocated,
+ HGFS_BUF_WRITEABLE,
+ session);
+ /*
+ * Really this can never happen, we would have caught bad physical address
+ * during getMetaPacket.
+ */
+ ASSERT(packet->replyPacket);
+ packet->replyPacketSize = packet->metaPacketSize;
+ } else {
+ /* For sockets channel we always need to allocate buffer */
+ LOG(10, ("%s Allocating reply packet\n", __FUNCTION__));
+ packet->replyPacket = Util_SafeMalloc(*replyPacketSize);
+ packet->replyPacketIsAllocated = TRUE;
+ packet->replyPacketSize = *replyPacketSize;
+ }
+
+exit:
+ *replyPacketSize = packet->replyPacketSize;
+ return packet->replyPacket;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutReplyPacket --
+ *
+ * Free buffer if reply packet was allocated.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutReplyPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ if (packet->replyPacketIsAllocated) {
+ LOG(10, ("%s Freeing reply packet", __FUNCTION__));
+ free(packet->replyPacket);
+ packet->replyPacketIsAllocated = FALSE;
+ packet->replyPacket = NULL;
+ packet->replyPacketSize = 0;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetMetaPacket --
+ *
+ * Get a meta packet given an hgfs packet.
+ * Guest mappings will be established.
+ *
+ * Results:
+ * Pointer to meta packet.
+ *
+ * Side effects:
+ * Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ size_t *metaPacketSize, // OUT: Size of metaPacket
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ *metaPacketSize = packet->metaPacketSize;
+ return HSPU_GetBuf(packet, 0, &packet->metaPacket,
+ packet->metaPacketSize,
+ &packet->metaPacketIsAllocated,
+ HGFS_BUF_WRITEABLE, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetDataPacketIov --
+ *
+ * Get a data packet in an iov form given an hgfs packet.
+ * Guest mappings will be established.
+ *
+ * Results:
+ * Pointer to data packet iov.
+ *
+ * Side effects:
+ * Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetDataPacketIov(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session, // IN: Session Info
+ HgfsVaIov iov) // OUT: I/O vector
+{
+ NOT_IMPLEMENTED();
+ return NULL;
+
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetDataPacketBuf --
+ *
+ * Get a data packet given an hgfs packet.
+ * Guest mappings will be established.
+ *
+ * Results:
+ * Pointer to data packet.
+ *
+ * Side effects:
+ * Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 mappingType, // IN: Writeable/Readable
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ packet->dataMappingType = mappingType;
+ return HSPU_GetBuf(packet, packet->dataPacketIovIndex,
+ &packet->dataPacket, packet->dataPacketSize,
+ &packet->dataPacketIsAllocated, mappingType, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetBuf --
+ *
+ * Get a {meta, data} packet given an hgfs packet.
+ * Guest mappings will be established.
+ *
+ * Results:
+ * Pointer to buffer.
+ *
+ * Side effects:
+ * Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: start index of iov
+ void **buf, // OUT: Contigous buffer
+ size_t bufSize, // IN: Size of buffer
+ Bool *isAllocated, // OUT: Was buffer allocated ?
+ uint32 mappingType, // IN: Readable/Writeable ?
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ uint32 iovCount;
+ uint32 iovMapped = 0;
+ int32 size = bufSize;
+ int i;
+ void* (*func)(uint64, uint32, char **);
+ ASSERT(buf);
+
+ if (*buf) {
+ return *buf;
+ } else if (bufSize == 0) {
+ return NULL;
+ }
+
+ ASSERT_DEVEL(session->channelCbTable);
+ if (!session->channelCbTable) {
+ return NULL;
+ }
+
+ if (mappingType == HGFS_BUF_WRITEABLE) {
+ func = session->channelCbTable->getWriteVa;
+ } else {
+ ASSERT(mappingType == HGFS_BUF_READABLE);
+ func = session->channelCbTable->getReadVa;
+ }
+
+ ASSERT_DEVEL(func);
+ if (func == NULL) {
+ return NULL;
+ }
+
+ /* Establish guest memory mappings */
+ for (iovCount = startIndex; iovCount < packet->iovCount && size > 0;
+ iovCount++) {
+
+ packet->iov[iovCount].token = NULL;
+
+ /* Debugging check: Iov in VMCI should never cross page boundary */
+ ASSERT_DEVEL(packet->iov[iovCount].len <=
+ (4096 - (packet->iov[iovCount].pa & 0xfff)));
+
+ packet->iov[iovCount].va = func(packet->iov[iovCount].pa,
+ packet->iov[iovCount].len,
+ &packet->iov[iovCount].token);
+ ASSERT_DEVEL(packet->iov[iovCount].va);
+ if (packet->iov[iovCount].va == NULL) {
+ /* Guest probably passed us bad physical address */
+ *buf = NULL;
+ goto freeMem;
+ }
+ iovMapped++;
+ size -= packet->iov[iovCount].len;
+ }
+
+ if (iovMapped > 1) {
+ /* Seems like more than one page was requested. */
+ uint32 copiedAmount = 0;
+ uint32 copyAmount;
+ int32 remainingSize;
+ int i;
+ ASSERT_DEVEL(packet->iov[startIndex].len < bufSize);
+ *buf = Util_SafeMalloc(bufSize);
+ *isAllocated = TRUE;
+
+ LOG(10, ("%s: Hgfs Allocating buffer \n", __FUNCTION__));
+
+ /*
+ * Since we are allocating seperate buffer, it does not make sense
+ * to continue to hold on to mappings. Let's release it, we will
+ * reacquire mappings when we need in HSPU_CopyBufToIovec.
+ */
+ remainingSize = bufSize;
+ for (i = startIndex; i < packet->iovCount && remainingSize > 0; i++) {
+ copyAmount = remainingSize < packet->iov[i].len ?
+ remainingSize : packet->iov[i].len;
+ memcpy((char *)*buf + copiedAmount, packet->iov[i].va, copyAmount);
+ copiedAmount += copyAmount;
+ remainingSize -= copyAmount;
+ }
+ ASSERT_DEVEL(copiedAmount == bufSize);
+ } else {
+ /* We will continue to hold on to guest mappings */
+ *buf = packet->iov[startIndex].va;
+ return *buf;
+ }
+
+freeMem:
+ for (i = 0; i < iovCount; i++) {
+ session->channelCbTable->putVa(&packet->iov[i].token);
+ packet->iov[i].va = NULL;
+ }
+
+ return *buf;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutMetaPacket --
+ *
+ * Free meta packet buffer if allocated.
+ * Guest mappings will be released.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutMetaPacket(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ LOG(4, ("%s Hgfs Putting Meta packet\n", __FUNCTION__));
+ HSPU_PutBuf(packet, 0, &packet->metaPacket,
+ &packet->metaPacketSize,
+ &packet->metaPacketIsAllocated,
+ HGFS_BUF_WRITEABLE, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutDataPacketIov --
+ *
+ * Free data packet Iov if allocated.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * Guest mappings will be released.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutDataPacketIov()
+{
+ NOT_IMPLEMENTED();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutDataPacketBuf --
+ *
+ * Free data packet buffer if allocated.
+ * Guest mappings will be released.
+ *
+ * Results:
+ * void.
+ *
+ * Side effects:
+ * None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutDataPacketBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ HgfsSessionInfo *session) // IN: Session Info
+{
+
+ LOG(4, ("%s Hgfs Putting Data packet\n", __FUNCTION__));
+ HSPU_PutBuf(packet, packet->dataPacketIovIndex,
+ &packet->dataPacket, &packet->dataPacketSize,
+ &packet->dataPacketIsAllocated,
+ packet->dataMappingType, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutBuf --
+ *
+ * Free buffer if allocated and release guest mappings.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutBuf(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: Start of iov
+ void **buf, // IN/OUT: Buffer to be freed
+ size_t *bufSize, // IN: Size of the buffer
+ Bool *isAllocated, // IN: Was buffer allocated ?
+ uint32 mappingType, // IN: Readable / Writeable ?
+ HgfsSessionInfo *session) // IN: Session info
+{
+ uint32 iovCount = 0;
+ int size = *bufSize;
+ ASSERT(buf);
+
+ if (!session->channelCbTable) {
+ return;
+ }
+
+ if (!session->channelCbTable->putVa || *buf == NULL) {
+ return;
+ }
+
+ if (*isAllocated) {
+ if (mappingType == HGFS_BUF_WRITEABLE) {
+ HSPU_CopyBufToIovec(packet, startIndex, *buf, *bufSize, session);
+ }
+ LOG(10, ("%s: Hgfs Freeing buffer \n", __FUNCTION__));
+ free(*buf);
+ *isAllocated = FALSE;
+ } else {
+ for (iovCount = startIndex;
+ iovCount < packet->iovCount && size > 0;
+ iovCount++) {
+ ASSERT_DEVEL(packet->iov[iovCount].token);
+ session->channelCbTable->putVa(&packet->iov[iovCount].token);
+ size -= packet->iov[iovCount].len;
+ }
+ LOG(10, ("%s: Hgfs bufSize = %d \n", __FUNCTION__, size));
+ ASSERT(size <= 0);
+ }
+ *buf = NULL;
+ *bufSize = 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToMetaIovec --
+ *
+ * Write out buffer to data Iovec.
+ *
+ * Results:
+ * void
+ *
+ * Side effects:
+ * @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToMetaIovec(HgfsPacket *packet, // IN/OUT: Hgfs packet
+ void *buf, // IN: Buffer to copy from
+ size_t bufSize, // IN: Size of buffer
+ HgfsSessionInfo *session)// IN: Session Info
+{
+ HSPU_CopyBufToIovec(packet, 0, buf, bufSize, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToDataIovec --
+ *
+ * Write out buffer to data Iovec.
+ *
+ * Results:
+ * void
+ *
+ * Side effects:
+ * @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToDataIovec(HgfsPacket *packet, // IN: Hgfs packet
+ void *buf, // IN: Buffer to copy from
+ uint32 bufSize, // IN: Size of buffer
+ HgfsSessionInfo *session)
+{
+ HSPU_CopyBufToIovec(packet, packet->dataPacketIovIndex, buf, bufSize,
+ session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToDataIovec --
+ *
+ * Write out buffer to data Iovec.
+ *
+ * Results:
+ * void
+ *
+ * Side effects:
+ * @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToIovec(HgfsPacket *packet, // IN/OUT: Hgfs Packet
+ uint32 startIndex, // IN: start index into iov
+ void *buf, // IN: Contigous Buffer
+ size_t bufSize, // IN: Size of buffer
+ HgfsSessionInfo *session) // IN: Session Info
+{
+ uint32 iovCount;
+ size_t remainingSize = bufSize;
+ size_t copyAmount;
+ size_t copiedAmount = 0;
+ int i;
+
+ ASSERT(packet);
+ ASSERT(buf);
+
+ if (!session->channelCbTable) {
+ return;
+ }
+
+ ASSERT_DEVEL(session->channelCbTable->getWriteVa);
+ if (!session->channelCbTable->getWriteVa) {
+ return;
+ }
+
+ for (iovCount = startIndex; iovCount < packet->iovCount
+ && remainingSize > 0; iovCount++) {
+ copyAmount = remainingSize < packet->iov[iovCount].len ?
+ remainingSize: packet->iov[iovCount].len;
+
+ packet->iov[iovCount].token = NULL;
+
+ /* Debugging check: Iov in VMCI should never cross page boundary */
+ ASSERT_DEVEL(packet->iov[iovCount].len <=
+ (4096 - (packet->iov[iovCount].pa & 0xfff)));
+
+ packet->iov[iovCount].va = session->channelCbTable->getWriteVa(packet->iov[iovCount].pa,
+ packet->iov[iovCount].len,
+ &packet->iov[iovCount].token);
+ ASSERT_DEVEL(packet->iov[iovCount].va);
+ if (packet->iov[iovCount].va == NULL) {
+ goto freeMem;
+ }
+
+ memcpy(packet->iov[iovCount].va, (char *)buf + copiedAmount, copyAmount);
+ remainingSize -= copyAmount;
+ copiedAmount += copyAmount;
+ }
+
+ ASSERT(remainingSize == 0);
+ return;
+
+freeMem:
+ for (i = startIndex; i < iovCount; i++) {
+ session->channelCbTable->putVa(&packet->iov[i].token);
+ }
+}
+
+
Bool HgfsChannel_Init(void *data); /* Optional data, used in guest. */
void HgfsChannel_Exit(void *data); /* Optional data, used in guest. */
void HgfsChannel_InvalidateObjects(DblLnkLst_Links *shares);
-
#endif
HGFS_OP_CREATE_SYMLINK_V3, /* Create a symlink */
HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */
HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */
-
+ HGFS_OP_READ_FAST_V3, /* Read */
+ HGFS_OP_WRITE_FAST_V3, /* Write */
/*
* Operations for version 4, deprecating version 3 operations.
*/
#define HGFS_REQ_GET_PAYLOAD_V3(hgfsReq) ((char *)(hgfsReq) + sizeof(HgfsRequest))
#define HGFS_REP_GET_PAYLOAD_V3(hgfsRep) ((char *)(hgfsRep) + sizeof(HgfsReply))
-/* Some fudged values for TCP over sockets. */
-#define HGFS_HOST_PORT 2000
-
-/* Socket packet magic. */
-#define HGFS_SOCKET_VERSION1 1
-
-/*
- * Socket status codes.
- */
-
-typedef enum {
- HGFS_SOCKET_STATUS_SUCCESS, /* Socket header is good. */
- HGFS_SOCKET_STATUS_SIZE_MISMATCH, /* Size and version are incompatible. */
- HGFS_SOCKET_STATUS_VERSION_NOT_SUPPORTED, /* Version not handled by remote. */
- HGFS_SOCKET_STATUS_INVALID_PACKETLEN, /* Message len exceeds maximum. */
-} HgfsSocketStatus;
-
-/*
- * Socket flags.
- */
-
-typedef uint32 HgfsSocketFlags;
-
-/* Used by backdoor proxy socket client to Hgfs server (out of VMX process). */
-#define HGFS_SOCKET_SYNC (1 << 0)
-
-/* Socket packet header. */
-typedef
-#include "vmware_pack_begin.h"
-struct HgfsSocketHeader {
- uint32 version; /* Header version. */
- uint32 size; /* Header size, should match for the specified version. */
- HgfsSocketStatus status; /* Status: always success when sending (ignored) valid on replies. */
- uint32 packetLen; /* The length of the packet to follow. */
- HgfsSocketFlags flags; /* The flags to indicate how to deal with the packet. */
-}
-#include "vmware_pack_end.h"
-HgfsSocketHeader;
-
-#define HgfsSocketHeaderInit(hdr, _version, _size, _status, _pktLen, _flags) \
- do { \
- (hdr)->version = (_version); \
- (hdr)->size = (_size); \
- (hdr)->status = (_status); \
- (hdr)->packetLen = (_pktLen); \
- (hdr)->flags = (_flags); \
- } while (0)
-
-
/*
* File types, used in HgfsAttr. We support regular files,
* directories, and symlinks.
void *loggerData; // logger callback private data
} HgfsServerStateLogger;
+
+#define HGFS_MAX_IOV 3
+#define HGFS_BUF_READABLE 0x0000cafe
+#define HGFS_BUF_WRITEABLE 0x0000babe
+
+typedef
+struct HgfsVmxIov {
+ void *va; /* Virtual addr */
+ uint64 pa; /* Physical address passed by the guest */
+ uint32 len; /* length of data; should be <= PAGE_SIZE for VMCI; arbitrary for backdoor */
+ char *token; /* Token for physMem_ APIs */
+} HgfsVmxIov;
+
+typedef
+struct HgfsVaIov {
+ void *va;
+ uint32 len;
+} HgfsVaIov;
+
+typedef
+struct HgfsPacket {
+ /* For metapacket we always establish writeable mappings */
+ void *metaPacket;
+ size_t metaPacketSize;
+ Bool metaPacketIsAllocated;
+
+ void *dataPacket;
+ size_t dataPacketSize;
+ uint32 dataPacketIovIndex;
+ Bool dataPacketIsAllocated;
+ /* What type of mapping was established - readable/ writeable ? */
+ uint32 dataMappingType;
+
+ void *replyPacket;
+ size_t replyPacketSize;
+ Bool replyPacketIsAllocated;
+
+ uint32 iovCount;
+ HgfsVmxIov iov[1];
+
+} HgfsPacket;
+
+
/*
* Function used for sending replies to the client for a session.
* Passed by the caller at session connect time.
size_t bufferLen, // IN
HgfsSendFlags flags); // IN
+typedef struct HgfsServerChannelCallbacks {
+ void* (*getReadVa)(uint64 pa, uint32 size, char **token);
+ void* (*getWriteVa)(uint64 pa, uint32 size, char **token);
+ void (*putVa)(char **token);
+ Bool (*send)(void *opaqueSession, HgfsPacket *packet, char *buffer,
+ size_t bufferLen, HgfsSendFlags flags);
+}HgfsServerChannelCallbacks;
+
typedef struct HgfsServerSessionCallbacks {
- Bool (*connect)(void *, HgfsSessionSendFunc *, void **);
+ Bool (*connect)(void *, HgfsServerChannelCallbacks *, void **);
void (*disconnect)(void *);
void (*close)(void *);
- void (*receive)(char const *,size_t, void *, HgfsReceiveFlags);
+ void (*receive)(HgfsPacket *packet, void *, HgfsReceiveFlags);
void (*invalidateObjects)(void *, DblLnkLst_Links *);
- void (*sendComplete)(void *, char *);
+ void (*sendComplete)(HgfsPacket *, void *);
} HgfsServerSessionCallbacks;
Bool HgfsServer_InitState(HgfsServerSessionCallbacks **, HgfsServerStateLogger *);
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsTransport.h --
+ *
+ * Transport file shared between guest drivers and host.
+ */
+
+#ifndef _HGFS_TRANSPORT_H_
+# define _HGFS_TRANSPORT_H_
+
+#include "vmci_defs.h"
+#include "hgfsServer.h" /* For HGFS_MAX_IOV */
+
+/****************************************
+ * Vsock, Tcp specific data structures *
+ ****************************************/
+
+/* Some fudged values for TCP over sockets. */
+#define HGFS_HOST_PORT 2000
+
+/* Socket packet magic. */
+#define HGFS_SOCKET_VERSION1 1
+
+/*
+ * Socket status codes.
+ */
+
+typedef enum {
+ HGFS_SOCKET_STATUS_SUCCESS, /* Socket header is good. */
+ HGFS_SOCKET_STATUS_SIZE_MISMATCH, /* Size and version are incompatible. */
+ HGFS_SOCKET_STATUS_VERSION_NOT_SUPPORTED, /* Version not handled by remote. */
+ HGFS_SOCKET_STATUS_INVALID_PACKETLEN, /* Message len exceeds maximum. */
+} HgfsSocketStatus;
+
+/*
+ * Socket flags.
+ */
+
+typedef uint32 HgfsSocketFlags;
+
+/* Used by backdoor proxy socket client to Hgfs server (out of VMX process). */
+#define HGFS_SOCKET_SYNC (1 << 0)
+
+/* Socket packet header. */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsSocketHeader {
+ uint32 version; /* Header version. */
+ uint32 size; /* Header size, should match for the specified version. */
+ HgfsSocketStatus status; /* Status: always success when sending (ignored) valid on replies. */
+ uint32 packetLen; /* The length of the packet to follow. */
+ HgfsSocketFlags flags; /* The flags to indicate how to deal with the packet. */
+}
+#include "vmware_pack_end.h"
+HgfsSocketHeader;
+
+#define HgfsSocketHeaderInit(hdr, _version, _size, _status, _pktLen, _flags) \
+ do { \
+ (hdr)->version = (_version); \
+ (hdr)->size = (_size); \
+ (hdr)->status = (_status); \
+ (hdr)->packetLen = (_pktLen); \
+ (hdr)->flags = (_flags); \
+ } while (0)
+
+
+/************************************************
+ * VMCI specific data structures, macros *
+ ************************************************/
+
+#define HGFS_VMCI_VERSION_1 0xabcdabcd
+
+/* Helpful for debugging purposes */
+#define HGFS_VMCI_IO_PENDING 0xdeadbeef
+#define HGFS_VMCI_IO_COMPLETE 0xfaceb00c
+#define HGFS_VMCI_MORE_SPACE_NEEDED 0xc00becaf
+#define HGFS_VMCI_IO_FAILED 0xbeef0000
+
+#define HGFS_VMCI_TRANSPORT_ERROR (VMCI_ERROR_CLIENT_MIN - 1)
+
+/*
+ * Used By : Guest and Host
+ * Lives in : Inside HgfsVmciTransportHeader
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsIov {
+ uint64 pa; /* Physical addr */
+ uint32 len; /* length of data; should be <= PAGE_SIZE */
+}
+#include "vmware_pack_end.h"
+HgfsIov;
+
+/*
+ * Every VMCI request will have this transport Header sent over
+ * in the datagram by the Guest OS.
+ *
+ * Used By : Guest and Host
+ * Lives in : Sent by Guest inside VMCI datagram
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsVmciTransportHeader {
+ uint32 version; /* Version number */
+ uint32 iovCount; /* Number of iovs */
+ HgfsIov iov[1]; /* (PA, len) */
+}
+#include "vmware_pack_end.h"
+HgfsVmciTransportHeader;
+
+/*
+ * Indicates status of VMCI requests. If the requests are processed sync
+ * by the hgfsServer then guest should see IO_COMPLETE otherwise IO_PENDING.
+ *
+ * Used By: Guest and Host
+ * Lives in: Guest Memory
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsVmciTransportStatus {
+ uint32 status; /* IO_PENDING, COMPLETE, MORE SPACE NEEDED, FAILED etc */
+ uint32 flags; /* ASYNC_PEND, VALID_ASYNC_PEND_REPLY */
+ uint32 size; /* G->H: Size of the packet,H->G: How much more space is needed */
+}
+#include "vmware_pack_end.h"
+HgfsVmciTransportStatus;
+
+#endif /* _HGFS_TRANSPORT_H_ */
+
#define EPROTO (ELAST + 1)
#endif
-#define HGFS_NAME_BUFFER_SIZE(request) (HGFS_PACKET_MAX - (sizeof *request - 1))
-#define HGFS_NAME_BUFFER_SIZET(sizet) (HGFS_PACKET_MAX - ((sizet) - 1))
+#define HGFS_NAME_BUFFER_SIZE(packetSize, request) (packetSize - (sizeof *request - 1))
+#define HGFS_NAME_BUFFER_SIZET(packetSize, sizet) (packetSize - ((sizet) - 1))
#ifndef _WIN32
/*
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005-2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VMCI_DEF_H_
+#define _VMCI_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+#include "vm_atomic.h"
+#include "vm_assert.h"
+
+/* Register offsets. */
+#define VMCI_STATUS_ADDR 0x00
+#define VMCI_CONTROL_ADDR 0x04
+#define VMCI_ICR_ADDR 0x08
+#define VMCI_IMR_ADDR 0x0c
+#define VMCI_DATA_OUT_ADDR 0x10
+#define VMCI_DATA_IN_ADDR 0x14
+#define VMCI_CAPS_ADDR 0x18
+#define VMCI_RESULT_LOW_ADDR 0x1c
+#define VMCI_RESULT_HIGH_ADDR 0x20
+
+/* Max number of devices. */
+#define VMCI_MAX_DEVICES 1
+
+/* Status register bits. */
+#define VMCI_STATUS_INT_ON 0x1
+
+/* Control register bits. */
+#define VMCI_CONTROL_RESET 0x1
+#define VMCI_CONTROL_INT_ENABLE 0x2
+#define VMCI_CONTROL_INT_DISABLE 0x4
+
+/* Capabilities register bits. */
+#define VMCI_CAPS_HYPERCALL 0x1
+#define VMCI_CAPS_GUESTCALL 0x2
+#define VMCI_CAPS_DATAGRAM 0x4
+#define VMCI_CAPS_NOTIFICATIONS 0x8
+
+/* Interrupt Cause register bits. */
+#define VMCI_ICR_DATAGRAM 0x1
+#define VMCI_ICR_NOTIFICATION 0x2
+
+/* Interrupt Mask register bits. */
+#define VMCI_IMR_DATAGRAM 0x1
+#define VMCI_IMR_NOTIFICATION 0x2
+
+/*
+ * We have a fixed set of resource IDs available in the VMX.
+ * This allows us to have a very simple implementation since we statically
+ * know how many will create datagram handles. If a new caller arrives and
+ * we have run out of slots we can manually increment the maximum size of
+ * available resource IDs.
+ */
+
+typedef uint32 VMCI_Resource;
+
+/* VMCI reserved hypervisor datagram resource IDs. */
+#define VMCI_RESOURCES_QUERY 0
+#define VMCI_GET_CONTEXT_ID 1
+#define VMCI_SET_NOTIFY_BITMAP 2
+#define VMCI_DOORBELL_LINK 3
+#define VMCI_DOORBELL_UNLINK 4
+#define VMCI_DOORBELL_NOTIFY 5
+#define VMCI_DATAGRAM_REQUEST_MAP 6
+#define VMCI_DATAGRAM_REMOVE_MAP 7
+#define VMCI_EVENT_SUBSCRIBE 8
+#define VMCI_EVENT_UNSUBSCRIBE 9
+#define VMCI_QUEUEPAIR_ALLOC 10
+#define VMCI_QUEUEPAIR_DETACH 11
+#define VMCI_VSOCK_VMX_LOOKUP 12
+#define VMCI_HGFS_TRANSPORT 13
+#define VMCI_RESOURCE_MAX 14
+
+/* VMCI Ids. */
+typedef uint32 VMCIId;
+
+typedef struct VMCIHandle {
+ VMCIId context;
+ VMCIId resource;
+} VMCIHandle;
+
+static INLINE
+VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid,
+ VMCIId rid)
+{
+ VMCIHandle h;
+ h.context = cid;
+ h.resource = rid;
+ return h;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_HANDLE_TO_UINT64 --
+ *
+ * Helper for VMCI handle to uint64 conversion.
+ *
+ * Results:
+ * The uint64 value.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCI_HANDLE_TO_UINT64(VMCIHandle handle) // IN:
+{
+ uint64 handle64;
+
+ handle64 = handle.context;
+ handle64 <<= 32;
+ handle64 |= handle.resource;
+ return handle64;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_UINT64_TO_HANDLE --
+ *
+ * Helper for uint64 to VMCI handle conversion.
+ *
+ * Results:
+ * The VMCI handle value.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE VMCIHandle
+VMCI_UINT64_TO_HANDLE(uint64 handle64) // IN:
+{
+ VMCIId context = (VMCIId)(handle64 >> 32);
+ VMCIId resource = (VMCIId)handle64;
+
+ return VMCI_MAKE_HANDLE(context, resource);
+}
+
+#define VMCI_HANDLE_TO_CONTEXT_ID(_handle) ((_handle).context)
+#define VMCI_HANDLE_TO_RESOURCE_ID(_handle) ((_handle).resource)
+#define VMCI_HANDLE_EQUAL(_h1, _h2) ((_h1).context == (_h2).context && \
+ (_h1).resource == (_h2).resource)
+
+#define VMCI_INVALID_ID 0xFFFFFFFF
+static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID,
+ VMCI_INVALID_ID};
+
+#define VMCI_HANDLE_INVALID(_handle) \
+ VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE)
+
+/*
+ * The below defines can be used to send anonymous requests.
+ * This also indicates that no response is expected.
+ */
+#define VMCI_ANON_SRC_CONTEXT_ID VMCI_INVALID_ID
+#define VMCI_ANON_SRC_RESOURCE_ID VMCI_INVALID_ID
+#define VMCI_ANON_SRC_HANDLE VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID, \
+ VMCI_ANON_SRC_RESOURCE_ID)
+
+/* The lowest 16 context ids are reserved for internal use. */
+#define VMCI_RESERVED_CID_LIMIT 16
+
+/*
+ * Hypervisor context id, used for calling into hypervisor
+ * supplied services from the VM.
+ */
+#define VMCI_HYPERVISOR_CONTEXT_ID 0
+
+/*
+ * Well-known context id, a logical context that contains
+ * a set of well-known services.
+ */
+#define VMCI_WELL_KNOWN_CONTEXT_ID 1
+
+/* Todo: Change host context id to dynamic/random id. */
+#define VMCI_HOST_CONTEXT_ID 2
+
+/*
+ * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make
+ * handles that refer to a specific context.
+ */
+#define VMCI_CONTEXT_RESOURCE_ID 0
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCI error codes.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#define VMCI_SUCCESS_QUEUEPAIR_ATTACH 5
+#define VMCI_SUCCESS_QUEUEPAIR_CREATE 4
+#define VMCI_SUCCESS_LAST_DETACH 3
+#define VMCI_SUCCESS_ACCESS_GRANTED 2
+#define VMCI_SUCCESS_ENTRY_DEAD 1
+#define VMCI_SUCCESS 0
+#define VMCI_ERROR_INVALID_RESOURCE (-1)
+#define VMCI_ERROR_INVALID_ARGS (-2)
+#define VMCI_ERROR_NO_MEM (-3)
+#define VMCI_ERROR_DATAGRAM_FAILED (-4)
+#define VMCI_ERROR_MORE_DATA (-5)
+#define VMCI_ERROR_NO_MORE_DATAGRAMS (-6)
+#define VMCI_ERROR_NO_ACCESS (-7)
+#define VMCI_ERROR_NO_HANDLE (-8)
+#define VMCI_ERROR_DUPLICATE_ENTRY (-9)
+#define VMCI_ERROR_DST_UNREACHABLE (-10)
+#define VMCI_ERROR_PAYLOAD_TOO_LARGE (-11)
+#define VMCI_ERROR_INVALID_PRIV (-12)
+#define VMCI_ERROR_GENERIC (-13)
+#define VMCI_ERROR_PAGE_ALREADY_SHARED (-14)
+#define VMCI_ERROR_CANNOT_SHARE_PAGE (-15)
+#define VMCI_ERROR_CANNOT_UNSHARE_PAGE (-16)
+#define VMCI_ERROR_NO_PROCESS (-17)
+#define VMCI_ERROR_NO_DATAGRAM (-18)
+#define VMCI_ERROR_NO_RESOURCES (-19)
+#define VMCI_ERROR_UNAVAILABLE (-20)
+#define VMCI_ERROR_NOT_FOUND (-21)
+#define VMCI_ERROR_ALREADY_EXISTS (-22)
+#define VMCI_ERROR_NOT_PAGE_ALIGNED (-23)
+#define VMCI_ERROR_INVALID_SIZE (-24)
+#define VMCI_ERROR_REGION_ALREADY_SHARED (-25)
+#define VMCI_ERROR_TIMEOUT (-26)
+#define VMCI_ERROR_DATAGRAM_INCOMPLETE (-27)
+#define VMCI_ERROR_INCORRECT_IRQL (-28)
+#define VMCI_ERROR_EVENT_UNKNOWN (-29)
+#define VMCI_ERROR_OBSOLETE (-30)
+#define VMCI_ERROR_QUEUEPAIR_MISMATCH (-31)
+#define VMCI_ERROR_QUEUEPAIR_NOTSET (-32)
+#define VMCI_ERROR_QUEUEPAIR_NOTOWNER (-33)
+#define VMCI_ERROR_QUEUEPAIR_NOTATTACHED (-34)
+#define VMCI_ERROR_QUEUEPAIR_NOSPACE (-35)
+#define VMCI_ERROR_QUEUEPAIR_NODATA (-36)
+#define VMCI_ERROR_BUSMEM_INVALIDATION (-37)
+#define VMCI_ERROR_MODULE_NOT_LOADED (-38)
+
+/* VMCI clients should return error code withing this range */
+#define VMCI_ERROR_CLIENT_MIN (-500)
+#define VMCI_ERROR_CLIENT_MAX (-550)
+
+/* Internal error codes. */
+#define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000)
+
+#define VMCI_PATH_MAX 256
+
+/* VMCI reserved events. */
+typedef uint32 VMCI_Event;
+
+#define VMCI_EVENT_CTX_ID_UPDATE 0
+#define VMCI_EVENT_CTX_REMOVED 1
+#define VMCI_EVENT_QP_RESUMED 2
+#define VMCI_EVENT_QP_PEER_ATTACH 3
+#define VMCI_EVENT_QP_PEER_DETACH 4
+#define VMCI_EVENT_MAX 5
+
+/* Reserved guest datagram resource ids. */
+#define VMCI_EVENT_HANDLER 0
+
+/* VMCI privileges. */
+typedef enum VMCIResourcePrivilegeType {
+ VMCI_PRIV_CH_PRIV,
+ VMCI_PRIV_DESTROY_RESOURCE,
+ VMCI_PRIV_ASSIGN_CLIENT,
+ VMCI_PRIV_DG_CREATE,
+ VMCI_PRIV_DG_SEND,
+ VMCI_PRIV_SM_CREATE,
+ VMCI_PRIV_SM_ATTACH,
+ VMCI_NUM_PRIVILEGES,
+} VMCIResourcePrivilegeType;
+
+/*
+ * VMCI coarse-grained privileges (per context or host
+ * process/endpoint. An entity with the restricted flag is only
+ * allowed to interact with the hypervisor and trusted entities.
+ */
+typedef uint32 VMCIPrivilegeFlags;
+
+#define VMCI_PRIVILEGE_FLAG_RESTRICTED 0x01
+#define VMCI_PRIVILEGE_FLAG_TRUSTED 0x02
+#define VMCI_PRIVILEGE_ALL_FLAGS (VMCI_PRIVILEGE_FLAG_RESTRICTED | \
+ VMCI_PRIVILEGE_FLAG_TRUSTED)
+#define VMCI_NO_PRIVILEGE_FLAGS 0x00
+#define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS VMCI_NO_PRIVILEGE_FLAGS
+#define VMCI_LEAST_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_RESTRICTED
+#define VMCI_MAX_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_TRUSTED
+
+/* VMCI Discovery Service. */
+
+/* Well-known handle to the discovery service. */
+#define VMCI_DS_RESOURCE_ID 1 /* Reserved resource ID for discovery service. */
+#define VMCI_DS_HANDLE VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \
+ VMCI_DS_RESOURCE_ID)
+#define VMCI_DS_CONTEXT VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \
+ VMCI_CONTEXT_RESOURCE_ID)
+
+/* Maximum length of a DS message. */
+#define VMCI_DS_MAX_MSG_SIZE 300
+
+/* Command actions. */
+#define VMCI_DS_ACTION_LOOKUP 0
+#define VMCI_DS_ACTION_REGISTER 1
+#define VMCI_DS_ACTION_UNREGISTER 2
+
+/* Defines wire-protocol format for a request send to the DS from a context. */
+typedef struct VMCIDsRequestHeader {
+ int32 action;
+ int32 msgid;
+ VMCIHandle handle;
+ int32 nameLen;
+ char name[1];
+} VMCIDsRequestHeader;
+
+
+/* Defines the wire-protocol format for a request send from the DS to a context. */
+typedef struct VMCIDsReplyHeader {
+ int32 msgid;
+ int32 code;
+ VMCIHandle handle;
+ int32 msgLen;
+ int8 msg[1];
+} VMCIDsReplyHeader;
+
+#define VMCI_PUBLIC_GROUP_NAME "vmci public group"
+/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
+#define VMCI_RESERVED_RESOURCE_ID_MAX 1023
+
+#define VMCI_DOMAIN_NAME_MAXLEN 32
+
+#define VMCI_LGPFX "VMCI: "
+
+
+/*
+ * VMCIQueueHeader
+ *
+ * A Queue cannot stand by itself as designed. Each Queue's header
+ * contains a pointer into itself (the producerTail) and into its peer
+ * (consumerHead). The reason for the separation is one of
+ * accessibility: Each end-point can modify two things: where the next
+ * location to enqueue is within its produceQ (producerTail); and
+ * where the next dequeue location is in its consumeQ (consumerHead).
+ *
+ * An end-point cannot modify the pointers of its peer (guest to
+ * guest; NOTE that in the host both queue headers are mapped r/w).
+ * But, each end-point needs read access to both Queue header
+ * structures in order to determine how much space is used (or left)
+ * in the Queue. This is because for an end-point to know how full
+ * its produceQ is, it needs to use the consumerHead that points into
+ * the produceQ but -that- consumerHead is in the Queue header for
+ * that end-points consumeQ.
+ *
+ * Thoroughly confused? Sorry.
+ *
+ * producerTail: the point to enqueue new entrants. When you approach
+ * a line in a store, for example, you walk up to the tail.
+ *
+ * consumerHead: the point in the queue from which the next element is
+ * dequeued. In other words, who is next in line is he who is at the
+ * head of the line.
+ *
+ * Also, producerTail points to an empty byte in the Queue, whereas
+ * consumerHead points to a valid byte of data (unless producerTail ==
+ * consumerHead in which case consumerHead does not point to a valid
+ * byte of data).
+ *
+ * For a queue of buffer 'size' bytes, the tail and head pointers will be in
+ * the range [0, size-1].
+ *
+ * If produceQHeader->producerTail == consumeQHeader->consumerHead
+ * then the produceQ is empty.
+ */
+
+typedef struct VMCIQueueHeader {
+ /* All fields are 64bit and aligned. */
+ VMCIHandle handle; /* Identifier. */
+ Atomic_uint64 producerTail; /* Offset in this queue. */
+ Atomic_uint64 consumerHead; /* Offset in peer queue. */
+} VMCIQueueHeader;
+
+
+/*
+ * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
+ * size to be less than 4GB, and use 32bit atomic operations on the head and
+ * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
+ * is an atomic read-modify-write. This will cause traces to fire when a 32bit
+ * consumer tries to read the producer's tail pointer, for example, because the
+ * consumer has read-only access to the producer's tail pointer.
+ *
+ * We provide the following macros to invoke 32bit or 64bit atomic operations
+ * based on the architecture the code is being compiled on.
+ */
+
+/* Architecture independent maximum queue size. */
+#define QP_MAX_QUEUE_SIZE_ARCH_ANY CONST64U(0xffffffff)
+
+#ifdef __x86_64__
+# define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffffffffffff)
+# define QPAtomic_ReadOffset(x) Atomic_Read64(x)
+# define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
+#else
+ /*
+ * Wrappers below are being used to call Atomic_Read32 because of the
+ * 'type punned' compilation warning received when Atomic_Read32 is
+ * called with a Atomic_uint64 pointer typecasted to Atomic_uint32
+ * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset.
+ */
+
+ static INLINE uint32
+ TypeSafe_Atomic_Read32(void *var) // IN:
+ {
+ return Atomic_Read32((Atomic_uint32 *)(var));
+ }
+
+ static INLINE void
+ TypeSafe_Atomic_Write32(void *var, uint32 val) // IN:
+ {
+ Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val));
+ }
+
+# define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffff)
+# define QPAtomic_ReadOffset(x) TypeSafe_Atomic_Read32((void *)(x))
+# define QPAtomic_WriteOffset(x, y) \
+ TypeSafe_Atomic_Write32((void *)(x), (uint32)(y))
+#endif /* __x86_64__ */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QPAddPointer --
+ *
+ * Helper to add a given offset to a head or tail pointer. Wraps the value
+ * of the pointer around the max size of the queue.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+QPAddPointer(Atomic_uint64 *var, // IN:
+ size_t add, // IN:
+ uint64 size) // IN:
+{
+ uint64 newVal = QPAtomic_ReadOffset(var);
+
+ if (newVal >= size - add) {
+ newVal -= size;
+ }
+ newVal += add;
+
+ QPAtomic_WriteOffset(var, newVal);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ProducerTail() --
+ *
+ * Helper routine to get the Producer Tail from the supplied queue.
+ *
+ * Results:
+ * The contents of the queue's producer tail.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueueHeader_ProducerTail(const VMCIQueueHeader *qHeader) // IN:
+{
+ VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader;
+ return QPAtomic_ReadOffset(&qh->producerTail);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ConsumerHead() --
+ *
+ * Helper routine to get the Consumer Head from the supplied queue.
+ *
+ * Results:
+ * The contents of the queue's consumer tail.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueueHeader_ConsumerHead(const VMCIQueueHeader *qHeader) // IN:
+{
+ VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader;
+ return QPAtomic_ReadOffset(&qh->consumerHead);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_AddProducerTail() --
+ *
+ * Helper routine to increment the Producer Tail. Fundamentally,
+ * QPAddPointer() is used to manipulate the tail itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_AddProducerTail(VMCIQueueHeader *qHeader, // IN/OUT:
+ size_t add, // IN:
+ uint64 queueSize) // IN:
+{
+ QPAddPointer(&qHeader->producerTail, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_AddConsumerHead() --
+ *
+ * Helper routine to increment the Consumer Head. Fundamentally,
+ * QPAddPointer() is used to manipulate the head itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_AddConsumerHead(VMCIQueueHeader *qHeader, // IN/OUT:
+ size_t add, // IN:
+ uint64 queueSize) // IN:
+{
+ QPAddPointer(&qHeader->consumerHead, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_CheckAlignment --
+ *
+ * Checks if the given queue is aligned to page boundary. Returns TRUE if
+ * the alignment is good.
+ *
+ * Results:
+ * TRUE or FALSE.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+VMCIQueueHeader_CheckAlignment(const VMCIQueueHeader *qHeader) // IN:
+{
+ uintptr_t hdr, offset;
+
+ hdr = (uintptr_t) qHeader;
+ offset = hdr & (PAGE_SIZE -1);
+
+ return offset == 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_GetPointers --
+ *
+ * Helper routine for getting the head and the tail pointer for a queue.
+ * Both the VMCIQueues are needed to get both the pointers for one queue.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_GetPointers(const VMCIQueueHeader *produceQHeader, // IN:
+ const VMCIQueueHeader *consumeQHeader, // IN:
+ uint64 *producerTail, // OUT:
+ uint64 *consumerHead) // OUT:
+{
+ if (producerTail) {
+ *producerTail = VMCIQueueHeader_ProducerTail(produceQHeader);
+ }
+
+ if (consumerHead) {
+ *consumerHead = VMCIQueueHeader_ConsumerHead(consumeQHeader);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ResetPointers --
+ *
+ * Reset the tail pointer (of "this" queue) and the head pointer (of
+ * "peer" queue).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_ResetPointers(VMCIQueueHeader *qHeader) // IN/OUT:
+{
+ QPAtomic_WriteOffset(&qHeader->producerTail, CONST64U(0));
+ QPAtomic_WriteOffset(&qHeader->consumerHead, CONST64U(0));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_Init --
+ *
+ * Initializes a queue's state (head & tail pointers).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_Init(VMCIQueueHeader *qHeader, // IN/OUT:
+ const VMCIHandle handle) // IN:
+{
+ qHeader->handle = handle;
+ VMCIQueueHeader_ResetPointers(qHeader);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_FreeSpace --
+ *
+ * Finds available free space in a produce queue to enqueue more
+ * data or reports an error if queue pair corruption is detected.
+ *
+ * Results:
+ * Free space size in bytes or an error code.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE int64
+VMCIQueueHeader_FreeSpace(const VMCIQueueHeader *produceQHeader, // IN:
+ const VMCIQueueHeader *consumeQHeader, // IN:
+ const uint64 produceQSize) // IN:
+{
+ uint64 tail;
+ uint64 head;
+ uint64 freeSpace;
+
+ tail = VMCIQueueHeader_ProducerTail(produceQHeader);
+ head = VMCIQueueHeader_ConsumerHead(consumeQHeader);
+
+ if (tail >= produceQSize || head >= produceQSize) {
+ return VMCI_ERROR_INVALID_SIZE;
+ }
+
+ /*
+ * Deduct 1 to avoid tail becoming equal to head which causes ambiguity. If
+ * head and tail are equal it means that the queue is empty.
+ */
+
+ if (tail >= head) {
+ freeSpace = produceQSize - (tail - head) - 1;
+ } else {
+ freeSpace = head - tail - 1;
+ }
+
+ return freeSpace;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_BufReady --
+ *
+ * VMCIQueueHeader_FreeSpace() does all the heavy lifting of
+ * determing the number of free bytes in a Queue. This routine,
+ * then subtracts that size from the full size of the Queue so
+ * the caller knows how many bytes are ready to be dequeued.
+ *
+ * Results:
+ * On success, available data size in bytes (up to MAX_INT64).
+ * On failure, appropriate error code.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE int64
+VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN:
+ const VMCIQueueHeader *produceQHeader, // IN:
+ const uint64 consumeQSize) // IN:
+{
+ int64 freeSpace;
+
+ freeSpace = VMCIQueueHeader_FreeSpace(consumeQHeader,
+ produceQHeader,
+ consumeQSize);
+ if (freeSpace < VMCI_SUCCESS) {
+ return freeSpace;
+ } else {
+ return consumeQSize - freeSpace - 1;
+ }
+}
+
+
+#endif
+
request->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Convert an input string to utf8 precomposed form, convert it to
request->reserved2 = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
request->mode = openMode;
request->flags = openFlags;
DEBUG(VM_DEBUG_COMM, "open flags are %x\n", request->flags);
request->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
fullPath = HGFS_VP_TO_FILENAME(vp);
fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Convert an input string to utf8 precomposed form, convert it to
request->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Convert an input string to utf8 precomposed form, convert it to
request->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Convert an input string to utf8 precomposed form, convert it to
request->symlinkName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Convert an input string to utf8 precomposed form, convert it to
request->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
/*
* Per the calling conventions of this function, if the path is NULL then
#define VMCI_QUEUEPAIR_ALLOC 10
#define VMCI_QUEUEPAIR_DETACH 11
#define VMCI_VSOCK_VMX_LOOKUP 12
-#define VMCI_RESOURCE_MAX 13
+#define VMCI_HGFS_TRANSPORT 13
+#define VMCI_RESOURCE_MAX 14
/* VMCI Ids. */
typedef uint32 VMCIId;
VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid,
VMCIId rid)
{
- VMCIHandle h = {cid, rid};
+ VMCIHandle h;
+ h.context = cid;
+ h.resource = rid;
return h;
}
#define VMCI_ERROR_BUSMEM_INVALIDATION (-37)
#define VMCI_ERROR_MODULE_NOT_LOADED (-38)
+/* VMCI clients should return error code withing this range */
+#define VMCI_ERROR_CLIENT_MIN (-500)
+#define VMCI_ERROR_CLIENT_MAX (-550)
+
/* Internal error codes. */
#define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000)
#include <linux/errno.h>
-#include "bdhandler.h"
+#include "transport.h"
#include "hgfsBd.h"
#include "hgfsDevLinux.h"
#include "hgfsProto.h"
#include "module.h"
#include "request.h"
#include "rpcout.h"
-#include "transport.h"
#include "vm_assert.h"
+static Bool HgfsBdChannelOpen(HgfsTransportChannel *channel);
+static void HgfsBdChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsBdChannelAllocate(size_t payloadSize);
+void HgfsBdChannelFree(HgfsReq *req);
+static int HgfsBdChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+
+static HgfsTransportChannel channel = {
+ .name = "backdoor",
+ .ops.open = HgfsBdChannelOpen,
+ .ops.close = HgfsBdChannelClose,
+ .ops.allocate = HgfsBdChannelAllocate,
+ .ops.free = HgfsBdChannelFree,
+ .ops.send = HgfsBdChannelSend,
+ .priv = NULL,
+ .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
/*
*-----------------------------------------------------------------------------
*
*
* HgfsBdChannelAllocate --
*
- * Allocate request uin the way that is suitable for sending through
+ * Allocate request in a way that is suitable for sending through
* backdoor.
*
* Results:
HGFS_SYNC_REQREP_CLIENT_CMD_LEN);
req->payload = req->buffer + HGFS_SYNC_REQREP_CLIENT_CMD_LEN;
+ req->bufferSize = payloadSize;
}
return req;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBdChannelFree --
+ *
+ * Free previously allocated request.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsBdChannelFree(HgfsReq *req)
+{
+ ASSERT(req);
+ kfree(req);
+}
+
+
/*
*----------------------------------------------------------------------
*
ASSERT(req);
ASSERT(req->state == HGFS_REQ_STATE_UNSENT);
- ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
+ ASSERT(req->payloadSize <= req->bufferSize);
LOG(8, ("VMware hgfs: %s: backdoor sending.\n", __func__));
payloadSize = req->payloadSize;
HgfsTransportChannel*
HgfsGetBdChannel(void)
{
- static HgfsTransportChannel channel;
-
- channel.name = "backdoor";
- channel.ops.open = HgfsBdChannelOpen;
- channel.ops.close = HgfsBdChannelClose;
- channel.ops.allocate = HgfsBdChannelAllocate;
- channel.ops.send = HgfsBdChannelSend;
- channel.priv = NULL;
- channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
return &channel;
}
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2006 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *********************************************************/
-
-/*
- * bdhandler.h --
- *
- * Backdoor channel implementation.
- */
-
-#ifndef _HGFS_DRIVER_BDHANDLER_H_
-#define _HGFS_DRIVER_BDHANDLER_H_
-
-#include "transport.h"
-
-HgfsTransportChannel *HgfsGetBdChannel(void);
-
-#endif // _HGFS_DRIVER_BDHANDLER_H_
* Make sure name length is legal.
*/
if (fileNameLength > NAME_MAX ||
- fileNameLength > HGFS_PACKET_MAX - replySize) {
+ fileNameLength > req->bufferSize - replySize) {
return -ENAMETOOLONG;
}
}
/* Build full name to send to server. */
- if (HgfsBuildPath(name, HGFS_PACKET_MAX - (requestSize - 1),
+ if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1),
file->f_dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: build path failed\n"));
return -EINVAL;
/* Convert to CP name. */
result = CPName_ConvertTo(name,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
name);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: CP conversion failed\n"));
/* Build full name to send to server. */
if (HgfsBuildPath(name,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
file->f_dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: build path "
"failed\n"));
/* Convert to CP name. */
result = CPName_ConvertTo(name,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
name);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: CP conversion "
.kill_sb = kill_anon_super,
};
+extern int USE_VMCI;
/*
* Private functions implementations.
hgfsVersionRename = HGFS_OP_RENAME_V3;
hgfsVersionQueryVolumeInfo = HGFS_OP_QUERY_VOLUME_INFO_V3;
hgfsVersionCreateSymlink = HGFS_OP_CREATE_SYMLINK_V3;
+
+ if (USE_VMCI) {
+ hgfsVersionRead = HGFS_OP_READ_FAST_V3;
+ hgfsVersionWrite = HGFS_OP_WRITE_FAST_V3;
+ }
+
}
length = replyV3->symlinkTarget.length;
/* Skip the symlinkTarget if it's too long. */
- if (length > HGFS_NAME_BUFFER_SIZET(sizeof *replyV3 + sizeof(HgfsReply))) {
+ if (length > HGFS_NAME_BUFFER_SIZET(req->bufferSize, sizeof *replyV3 + sizeof(HgfsReply))) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink "
"target name too long, ignoring\n"));
return -ENAMETOOLONG;
length = replyV2->symlinkTarget.length;
/* Skip the symlinkTarget if it's too long. */
- if (length > HGFS_NAME_BUFFER_SIZE(replyV2)) {
+ if (length > HGFS_NAME_BUFFER_SIZE(req->bufferSize, replyV2)) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink "
"target name too long, ignoring\n"));
return -ENAMETOOLONG;
}
requestV3->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize);
break;
}
fileNameLength = &requestV2->fileName.length;
}
reqSize = sizeof *requestV2;
- reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV2);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2);
break;
}
fileName = requestV1->fileName.name;
fileNameLength = &requestV1->fileName.length;
reqSize = sizeof *requestV1;
- reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV1);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV1);
break;
}
}
/* Build full name to send to server. */
- if (HgfsBuildPath(fileName, HGFS_NAME_BUFFER_SIZET(reqSize),
+ if (HgfsBuildPath(fileName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: build path failed\n"));
result = -EINVAL;
/* Convert to CP name. */
result = CPName_ConvertTo(fileName,
- HGFS_NAME_BUFFER_SIZET(reqSize),
+ HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
fileName);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: CP conversion failed\n"));
}
requestV3->reserved = 0;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
- reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize);
/*
* We only support changing these attributes:
fileNameLength = &requestV2->fileName.length;
}
reqSize = sizeof *requestV2;
- reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV2);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2);
/*
* We only support changing these attributes:
fileName = request->fileName.name;
fileNameLength = &request->fileName.length;
reqSize = sizeof *request;
- reqBufferSize = HGFS_NAME_BUFFER_SIZE(request);
+ reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, request);
/*
/* Build full name to send to server. */
if (HgfsBuildPath(fileName,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: build path "
"failed\n"));
/* Convert to CP name. */
result = CPName_ConvertTo(fileName,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
fileName);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: CP "
}
/* Build full old name to send to server. */
- if (HgfsBuildPath(oldName, HGFS_NAME_BUFFER_SIZET(reqSize),
+ if (HgfsBuildPath(oldName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
oldDentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build old path failed\n"));
result = -EINVAL;
/* Convert old name to CP format. */
result = CPName_ConvertTo(oldName,
- HGFS_NAME_BUFFER_SIZET(reqSize),
+ HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
oldName);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: oldName CP "
newNameLength = &newNameP->length;
}
- if (HgfsBuildPath(newName, HGFS_NAME_BUFFER_SIZET(reqSize) - result,
+ if (HgfsBuildPath(newName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result,
newDentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build new path failed\n"));
result = -EINVAL;
/* Convert new name to CP format. */
result = CPName_ConvertTo(newName,
- HGFS_NAME_BUFFER_SIZET(reqSize) - result,
+ HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result,
newName);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: newName CP "
return -EPROTO;
}
- if (HgfsBuildPath(symlinkName, HGFS_PACKET_MAX - (requestSize - 1),
+ if (HgfsBuildPath(symlinkName, req->bufferSize - (requestSize - 1),
dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: build symlink path "
"failed\n"));
/* Convert symlink name to CP format. */
result = CPName_ConvertTo(symlinkName,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
symlinkName);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: symlinkName CP "
targetNameBytes = strlen(symname) + 1;
/* Copy target name into request packet. */
- if (targetNameBytes > HGFS_PACKET_MAX - (requestSize - 1)) {
+ if (targetNameBytes > req->bufferSize - (requestSize - 1)) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: target name is too "
"big\n"));
return -EINVAL;
#include "inode.h"
#include "vm_assert.h"
#include "vm_basic_types.h"
+#include "hgfsTransport.h"
+
/* Private functions. */
static int HgfsDoWrite(HgfsHandle handle,
- const char *buf,
- size_t count,
+ HgfsDataPacket dataPacket[],
+ uint32 numEntries,
loff_t offset);
static int HgfsDoRead(HgfsHandle handle,
- char *buf,
- size_t count,
+ HgfsDataPacket dataPacket[],
+ uint32 numEntries,
loff_t offset);
static int HgfsDoReadpage(HgfsHandle handle,
struct page *page,
* It is assumed that this function is never called with a larger read than
* what can be sent in one request.
*
+ * HgfsDataPacket is an array of pages into which data will be read.
+ *
* Results:
* Returns the number of bytes read on success, or an error on failure.
*
*/
static int
-HgfsDoRead(HgfsHandle handle, // IN: Handle for this file
- char *buf, // OUT: Buffer to copy data into
- size_t count, // IN: Number of bytes to read
- loff_t offset) // IN: Offset at which to read
+HgfsDoRead(HgfsHandle handle, // IN: Handle for this file
+ HgfsDataPacket dataPacket[], // IN/OUT: Data description
+ uint32 numEntries, // IN: Number of entries in dataPacket
+ loff_t offset) // IN: Offset at which to read
{
HgfsReq *req;
HgfsOp opUsed;
uint32 actualSize = 0;
char *payload = NULL;
HgfsStatus replyStatus;
-
- ASSERT(buf);
+ char *buf;
+ ASSERT(numEntries == 1);
+ uint32 count = dataPacket[0].len;
req = HgfsGetNewRequest();
if (!req) {
retry:
opUsed = hgfsVersionRead;
- if (opUsed == HGFS_OP_READ_V3) {
+ if (opUsed == HGFS_OP_READ_FAST_V3) {
+ HgfsRequest *header;
+ HgfsRequestReadV3 *request;
+
+ header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req));
+ header->id = req->id;
+ header->op = opUsed;
+
+ request = (HgfsRequestReadV3 *)(HGFS_REQ_PAYLOAD_V3(req));
+ request->file = handle;
+ request->offset = offset;
+ request->requiredSize = count;
+ request->reserved = 0;
+ req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0],
+ GFP_KERNEL);
+ if (!req->dataPacket) {
+ LOG(4, (KERN_DEBUG "%s: Failed to allocate mem\n", __func__));
+ result = -ENOMEM;
+ goto out;
+ }
+ memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]);
+ req->numEntries = numEntries;
+
+ LOG(4, (KERN_DEBUG "VMware hgfs: Fast Read\n"));
+ } else if (opUsed == HGFS_OP_READ_V3) {
HgfsRequest *header;
HgfsRequestReadV3 *request;
request->offset = offset;
request->requiredSize = count;
request->reserved = 0;
+ req->dataPacket = NULL;
req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
} else {
HgfsRequestRead *request;
request->file = handle;
request->offset = offset;
request->requiredSize = count;
+ req->dataPacket = NULL;
req->payloadSize = sizeof *request;
}
-
/* Send the request and process the reply. */
result = HgfsSendRequest(req);
if (result == 0) {
switch (result) {
case 0:
- if (opUsed == HGFS_OP_READ_V3) {
+ if (opUsed == HGFS_OP_READ_FAST_V3) {
+ actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
+ } else if (opUsed == HGFS_OP_READ_V3) {
actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
payload = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->payload;
} else {
}
if (!actualSize) {
- /* We got no bytes, so don't need to copy to user. */
+ /* We got no bytes. */
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: server returned "
"zero\n"));
result = actualSize;
}
/* Return result. */
- memcpy(buf, payload, actualSize);
- LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: copied %u\n",
- actualSize));
+ if (opUsed == HGFS_OP_READ_V3 || opUsed == HGFS_OP_READ) {
+ buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+ ASSERT(buf);
+ memcpy(buf, payload, actualSize);
+ LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: copied %u\n",
+ actualSize));
+ kunmap(dataPacket[0].page);
+ }
result = actualSize;
break;
case -EPROTO:
/* Retry with older version(s). Set globally. */
- if (opUsed == HGFS_OP_READ_V3) {
+ switch (opUsed) {
+ case HGFS_OP_READ_FAST_V3:
+ LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoRead: Fast Read not "
+ "supported. Falling back to V3 Read.\n"));
+ hgfsVersionRead = HGFS_OP_READ_V3;
+ goto retry;
+
+ case HGFS_OP_READ_V3:
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoRead: Version 3 not "
"supported. Falling back to version 1.\n"));
hgfsVersionRead = HGFS_OP_READ;
goto retry;
+
+ default:
+ break;
}
break;
}
out:
+ if (req->dataPacket) {
+ kfree(req->dataPacket);
+ }
HgfsFreeRequest(req);
return result;
}
* It is assumed that this function is never called with a larger write
* than what can be sent in one request.
*
+ * HgfsDataPacket is an array of pages from which data will be written
+ * to file.
+ *
* Results:
* Returns the number of bytes written on success, or an error on failure.
*
*/
static int
-HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file
- const char *buf, // IN: Buffer containing data
- size_t count, // IN: Number of bytes to write
- loff_t offset) // IN: Offset to begin writing at
+HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file
+ HgfsDataPacket dataPacket[], // IN: Data description
+ uint32 numEntries, // IN: Number of entries in dataPacket
+ loff_t offset) // IN: Offset to begin writing at
{
HgfsReq *req;
int result = 0;
char *payload = NULL;
uint32 reqSize;
HgfsStatus replyStatus;
-
- ASSERT(buf);
+ char *buf;
+ ASSERT(numEntries == 1);
+ uint32 count = dataPacket[0].len;
req = HgfsGetNewRequest();
if (!req) {
retry:
opUsed = hgfsVersionWrite;
- if (opUsed == HGFS_OP_WRITE_V3) {
+ if (opUsed == HGFS_OP_WRITE_FAST_V3) {
HgfsRequest *header;
HgfsRequestWriteV3 *request;
request->reserved = 0;
payload = request->payload;
requiredSize = request->requiredSize;
+
+ req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0],
+ GFP_KERNEL);
+ if (!req->dataPacket) {
+ LOG(4, (KERN_DEBUG "%s: Failed to allocate mem\n", __func__));
+ result = -ENOMEM;
+ goto out;
+ }
+ memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]);
+ req->numEntries = numEntries;
reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+ req->payloadSize = reqSize;
+ LOG(4, (KERN_DEBUG "VMware hgfs: Fast Write\n"));
+ } else if (opUsed == HGFS_OP_WRITE_V3) {
+ HgfsRequest *header;
+ HgfsRequestWriteV3 *request;
+
+ header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req));
+ header->id = req->id;
+ header->op = opUsed;
+
+ request = (HgfsRequestWriteV3 *)(HGFS_REQ_PAYLOAD_V3(req));
+ request->file = handle;
+ request->flags = 0;
+ request->offset = offset;
+ request->requiredSize = count;
+ request->reserved = 0;
+ payload = request->payload;
+ requiredSize = request->requiredSize;
+ reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+ req->dataPacket = NULL;
+ buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+ memcpy(payload, buf, requiredSize);
+ kunmap(dataPacket[0].page);
+
+ req->payloadSize = reqSize + requiredSize - 1;
} else {
HgfsRequestWrite *request;
payload = request->payload;
requiredSize = request->requiredSize;
reqSize = sizeof *request;
- }
+ req->dataPacket = NULL;
+ buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+ memcpy(payload, buf, requiredSize);
+ kunmap(dataPacket[0].page);
- memcpy(payload, buf, requiredSize);
- req->payloadSize = reqSize + requiredSize - 1;
+ req->payloadSize = reqSize + requiredSize - 1;
+ }
/* Send the request and process the reply. */
result = HgfsSendRequest(req);
switch (result) {
case 0:
- if (opUsed == HGFS_OP_WRITE_V3) {
+ if (opUsed == HGFS_OP_WRITE_V3 || opUsed == HGFS_OP_WRITE_FAST_V3) {
actualSize = ((HgfsReplyWriteV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
} else {
actualSize = ((HgfsReplyWrite *)HGFS_REQ_PAYLOAD(req))->actualSize;
case -EPROTO:
/* Retry with older version(s). Set globally. */
- if (opUsed == HGFS_OP_WRITE_V3) {
+ switch (opUsed) {
+ case HGFS_OP_WRITE_FAST_V3:
+ LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWrite: Fast Write not "
+ "supported. Falling back to V3 write.\n"));
+ hgfsVersionRead = HGFS_OP_WRITE_V3;
+ goto retry;
+
+ case HGFS_OP_WRITE_V3:
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWrite: Version 3 not "
"supported. Falling back to version 1.\n"));
hgfsVersionWrite = HGFS_OP_WRITE;
goto retry;
+
+ default:
+ break;
}
break;
}
out:
+ if (req->dataPacket) {
+ kfree(req->dataPacket);
+ }
HgfsFreeRequest(req);
return result;
}
unsigned pageTo) // IN: Where to stop reading
{
int result = 0;
- char *buffer = kmap(page) + pageFrom;
loff_t curOffset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageFrom;
size_t nextCount, remainingCount = pageTo - pageFrom;
+ HgfsDataPacket dataPacket[1];
LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoReadpage: read %Zu bytes from fh %u "
"at offset %Lu\n", remainingCount, handle, curOffset));
do {
nextCount = (remainingCount > HGFS_IO_MAX) ?
HGFS_IO_MAX : remainingCount;
- result = HgfsDoRead(handle, buffer, nextCount, curOffset);
+ dataPacket[0].page = page;
+ dataPacket[0].offset = pageFrom;
+ dataPacket[0].len = nextCount;
+ result = HgfsDoRead(handle, dataPacket, 1, curOffset);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoReadpage: read error %d\n",
result));
}
remainingCount -= result;
curOffset += result;
- buffer += result;
+ pageFrom += result;
} while ((result > 0) && (remainingCount > 0));
/*
* than a page in the file from this offset, so we should zero the rest of
* the page's memory.
*/
- memset(buffer, 0, remainingCount);
+ if (remainingCount) {
+ char *buffer = kmap(page) + pageTo;
+ memset(buffer - remainingCount, 0, remainingCount);
+ kunmap(page);
+ }
/*
* We read a full page (or all of the page that actually belongs to the
result = 0;
out:
- kunmap(page);
return result;
}
unsigned pageTo) // IN: Ending page offset
{
int result = 0;
- char *buffer = kmap(page) + pageFrom;
loff_t curOffset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageFrom;
size_t nextCount;
size_t remainingCount = pageTo - pageFrom;
struct inode *inode;
+ HgfsDataPacket dataPacket[1];
ASSERT(page->mapping);
ASSERT(page->mapping->host);
do {
nextCount = (remainingCount > HGFS_IO_MAX) ?
HGFS_IO_MAX : remainingCount;
- result = HgfsDoWrite(handle, buffer, nextCount, curOffset);
+ dataPacket[0].page = page;
+ dataPacket[0].offset = pageFrom;
+ dataPacket[0].len = nextCount;
+ result = HgfsDoWrite(handle, dataPacket, 1, curOffset);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWritepage: write error %d\n",
result));
}
remainingCount -= result;
curOffset += result;
- buffer += result;
+ pageFrom += result;
/* Update the inode's size now rather than waiting for a revalidate. */
if (curOffset > compat_i_size_read(inode)) {
result = 0;
out:
- kunmap(page);
return result;
}
static void
HgfsRequestInit(HgfsReq *req, // IN: request to initialize
- size_t bufferSize, // Size of the buffer allocated with request
int requestId) // IN: ID assigned to the request
{
ASSERT(req);
init_waitqueue_head(&req->queue);
req->id = requestId;
req->payloadSize = 0;
- req->bufferSize = bufferSize;
req->state = HGFS_REQ_STATE_ALLOCATED;
+ req->numEntries = 0;
}
/*
return NULL;
}
- HgfsRequestInit(req, HGFS_PACKET_MAX,
- atomic_inc_return(&hgfsIdCounter) - 1);
+ HgfsRequestInit(req, atomic_inc_return(&hgfsIdCounter) - 1);
return req;
}
+
/*
*----------------------------------------------------------------------
*
return NULL;
}
- HgfsRequestInit(newReq, req->bufferSize, req->id);
+ HgfsRequestInit(newReq, req->id);
+
+ memcpy(newReq->dataPacket, req->dataPacket,
+ req->numEntries * sizeof (req->dataPacket[0]));
- /* Copy payload from the original request. */
+ newReq->numEntries = req->numEntries;
newReq->payloadSize = req->payloadSize;
memcpy(newReq->payload, req->payload, req->payloadSize);
int ret;
ASSERT(req);
- ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
-
+ ASSERT(req->payloadSize <= req->bufferSize);
+ LOG(4, (KERN_WARNING "Size of buffer %Zu\n", req->bufferSize));
req->state = HGFS_REQ_STATE_UNSENT;
LOG(8, (KERN_DEBUG "VMware hgfs: HgfsSendRequest: Sending request id %d\n",
LOG(10, (KERN_DEBUG "VMware hgfs: %s: freeing request %d\n",
__func__, req->id));
- kfree(req);
+ HgfsTransportFreeRequest(req);
}
/*
#include "compat_wait.h"
#include "hgfs.h" /* For common HGFS definitions. */
+#include "hgfsTransport.h"
#include "vm_basic_types.h"
/* Macros for accessing the payload portion of the HGFS request packet. */
#define HGFS_REQ_PAYLOAD_V3(hgfsReq) (HGFS_REQ_PAYLOAD(hgfsReq) + sizeof(HgfsRequest))
#define HGFS_REP_PAYLOAD_V3(hgfsRep) (HGFS_REQ_PAYLOAD(hgfsRep) + sizeof(HgfsReply))
+#define HGFS_MAX_PAGES 2
+
/*
* HGFS_REQ_STATE_ALLOCATED:
* The filesystem half has allocated the request from the slab
HGFS_REQ_STATE_COMPLETED, /* Both header and payload were received. */
} HgfsState;
+/*
+ * Each page that is sent from guest to host is described in the following
+ * format.
+ */
+typedef struct HgfsDataPacket {
+ struct page *page;
+ uint32 offset;
+ uint32 len;
+} HgfsDataPacket;
+
/*
* A request to be sent to the user process.
*/
/*
* Size of the data buffer (below), not including size of chunk
* used by transport. Must be enough to hold both request and
- * reply (but not at the same time).
+ * reply (but not at the same time). Initialized in channels.
*/
size_t bufferSize;
+ /*
+ * Used by read and write calls. Hgfs client passes in
+ * pages to the vmci channel using datapackets and vmci channel
+ * uses it to pass PA's to the host.
+ */
+ HgfsDataPacket *dataPacket;
+
+ /* Number of entries in data packet */
+ uint32 numEntries;
+
/*
* Packet of data, for both incoming and outgoing messages.
* Include room for the command.
}
/* Build full name to send to server. */
- if (HgfsBuildPath(name, HGFS_PACKET_MAX - (requestSize - 1),
+ if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1),
dentry) < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: build path failed\n"));
return -EINVAL;
/* Convert to CP name. */
result = CPName_ConvertTo(name,
- HGFS_PACKET_MAX - (requestSize - 1),
+ req->bufferSize - (requestSize - 1),
name);
if (result < 0) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: CP conversion failed\n"));
#include "hgfsProto.h"
#include "hgfsDevLinux.h"
#include "module.h"
-#include "tcp.h"
+#include "transport.h"
static char *HOST_IP;
module_param(HOST_IP, charp, 0444);
static void (*oldSocketDataReady)(struct sock *, int);
+static Bool HgfsVSocketChannelOpen(HgfsTransportChannel *channel);
+static int HgfsSocketChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+static void HgfsVSocketChannelClose(HgfsTransportChannel *channel);
+static Bool HgfsTcpChannelOpen(HgfsTransportChannel *channel);
+static void HgfsTcpChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsSocketChannelAllocate(size_t payloadSize);
+void HgfsSocketChannelFree(HgfsReq *req);
+
+static HgfsTransportChannel vsockChannel = {
+ .name = "vsocket",
+ .ops.close = HgfsVSocketChannelClose,
+ .ops.send = HgfsSocketChannelSend,
+ .ops.open = HgfsVSocketChannelOpen,
+ .ops.allocate = NULL,
+ .ops.free = NULL,
+ .priv = NULL,
+ .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+static HgfsTransportChannel tcpChannel = {
+ .name = "tcp",
+ .ops.open = HgfsTcpChannelOpen,
+ .ops.close = HgfsTcpChannelClose,
+ .ops.allocate = HgfsSocketChannelAllocate,
+ .ops.free = HgfsSocketChannelFree,
+ .ops.send = HgfsSocketChannelSend,
+ .priv = NULL,
+ .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
/*
*----------------------------------------------------------------------
*
GFP_KERNEL);
if (likely(req)) {
req->payload = req->buffer + sizeof(HgfsSocketHeader);
+ req->bufferSize = payloadSize;
}
return req;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsSocketChannelFree --
+ *
+ * Free previously allocated request.
+ *
+ * Results:
+ * none
+ *
+ * Side effects:
+ * Object is freed
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsSocketChannelFree(HgfsReq *req)
+{
+ ASSERT(req);
+ kfree(req);
+}
+
+
/*
*----------------------------------------------------------------------
*
HgfsTransportChannel *
HgfsGetTcpChannel(void)
{
- static HgfsTransportChannel channel;
-
- channel.name = "tcp";
- channel.ops.open = HgfsTcpChannelOpen;
- channel.ops.close = HgfsTcpChannelClose;
- channel.ops.allocate = HgfsSocketChannelAllocate;
- channel.ops.send = HgfsSocketChannelSend;
- channel.priv = NULL;
- channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
if (!HOST_IP) {
return NULL;
}
- return &channel;
+ return &tcpChannel;
}
HgfsTransportChannel *
HgfsGetVSocketChannel(void)
{
- static HgfsTransportChannel channel;
-
- channel.name = "vsocket";
- channel.ops.open = HgfsVSocketChannelOpen;
- channel.ops.close = HgfsVSocketChannelClose;
- channel.ops.send = HgfsSocketChannelSend;
- channel.priv = NULL;
- channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
if (!HOST_VSOCKET_PORT) {
return NULL;
}
- return &channel;
+ return &vsockChannel;
}
+
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2006 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *********************************************************/
-
-/*
- * tcp.h --
- *
- * Tcp channel implementation.
- */
-
-#ifndef _HGFS_DRIVER_TCP_H_
-#define _HGFS_DRIVER_TCP_H_
-
-#include "transport.h"
-
-HgfsTransportChannel* HgfsGetTcpChannel(void);
-HgfsTransportChannel* HgfsGetVSocketChannel(void);
-
-#endif // _HGFS_DRIVER_TCP_H_
/* Must be included after sched.h. */
#include <linux/smp_lock.h>
-#include "bdhandler.h"
#include "hgfsDevLinux.h"
#include "hgfsProto.h"
#include "module.h"
#include "request.h"
-#include "tcp.h"
#include "transport.h"
#include "vm_assert.h"
+extern int USE_VMCI;
+
COMPAT_KTHREAD_DECLARE_STOP_INFO();
static HgfsTransportChannel *hgfsChannel; /* Current active channel. */
static compat_mutex_t hgfsChannelLock; /* Lock to protect hgfsChannel. */
{
HgfsTransportChannel *newChannel;
+ newChannel = HgfsGetVmciChannel();
+ if (newChannel != NULL) {
+ if (HgfsTransportOpenChannel(newChannel)) {
+ hgfsChannel = newChannel;
+ LOG(10, ("CHANNEL: Vmci channel\n"));
+ return TRUE;
+ }
+ }
+
+ USE_VMCI = 0;
+
newChannel = HgfsGetVSocketChannel();
if (newChannel != NULL) {
if (HgfsTransportOpenChannel(newChannel)) {
hgfsChannel = newChannel;
+ LOG(10, ("CHANNEL: Vsocket channel\n"));
return TRUE;
}
}
if (newChannel != NULL) {
if (HgfsTransportOpenChannel(newChannel)) {
hgfsChannel = newChannel;
+ LOG(10, ("CHANNEL: Tcp channel\n"));
return TRUE;
}
}
newChannel = HgfsGetBdChannel();
+ LOG(10, ("CHANNEL: Bd channel\n"));
ASSERT(newChannel);
hgfsChannel = newChannel;
return HgfsTransportOpenChannel(newChannel);
return req;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsTransportFreeRequest --
+ *
+ * Free HGFS request structre using channel-specific free function.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+HgfsTransportFreeRequest(HgfsReq *req) // IN: size of the buffer
+{
+ /*
+ * We cannot use hgfsChannel structre because global channel could
+ * changes in the meantime. We remember the channel when we do
+ * allocation and call the same channel for de-allocation. Smart.
+ */
+
+ HgfsTransportChannel *channel = (HgfsTransportChannel *)req->transportId;
+ channel->ops.free(req);
+ return;
+}
+
/*
*----------------------------------------------------------------------
ASSERT(req);
ASSERT(req->state == HGFS_REQ_STATE_UNSENT);
- ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
+ ASSERT(req->payloadSize <= req->bufferSize);
compat_mutex_lock(&hgfsChannelLock);
ASSERT(hgfsChannel->ops.send);
/* If channel changed since we created request we need to adjust */
- if (req->transportId != hgfsChannel) {
+ if (req->transportId != hgfsChannel) {
HgfsTransportRemovePendingRequest(req);
void (*close)(struct HgfsTransportChannel *);
HgfsReq* (*allocate)(size_t payloadSize);
int (*send)(struct HgfsTransportChannel *, HgfsReq *);
+ void (*free)(HgfsReq *);
} HgfsTransportChannelOps;
typedef enum {
void HgfsTransportInit(void);
void HgfsTransportExit(void);
HgfsReq *HgfsTransportAllocateRequest(size_t payloadSize);
+void HgfsTransportFreeRequest(HgfsReq *req);
int HgfsTransportSendRequest(HgfsReq *req);
HgfsReq *HgfsTransportGetPendingRequest(HgfsHandle id);
void HgfsTransportFinishRequest(HgfsReq *req, Bool success, Bool do_put);
void HgfsTransportFlushRequests(void);
void HgfsTransportMarkDead(void);
+HgfsTransportChannel* HgfsGetVmciChannel(void);
+HgfsTransportChannel* HgfsGetTcpChannel(void);
+HgfsTransportChannel* HgfsGetVSocketChannel(void);
+HgfsTransportChannel *HgfsGetBdChannel(void);
+
#endif // _HGFS_DRIVER_TRANSPORT_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmci.c --
+ *
+ * Provides VMCI transport channel to the HGFS client.
+ */
+
+/* Must come before any kernel header file. */
+#include "driver-config.h"
+
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+
+#include "compat_mm.h"
+#include "hgfsProto.h"
+#include "hgfsTransport.h"
+#include "module.h"
+#include "request.h"
+#include "transport.h"
+#include "vm_assert.h"
+#include "vmci_call_defs.h"
+#include "vmci_defs.h"
+#include "vmciGuestKernelAPI.h"
+
+static Bool HgfsVmciChannelOpen(HgfsTransportChannel *channel);
+static void HgfsVmciChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsVmciChannelAllocate(size_t payloadSize);
+void HgfsVmciChannelFree(HgfsReq *req);
+static int HgfsVmciChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+
+int USE_VMCI = 0;
+module_param(USE_VMCI, int, 0444);
+
+static HgfsTransportChannel channel = {
+ .name = "vmci",
+ .ops.open = HgfsVmciChannelOpen,
+ .ops.close = HgfsVmciChannelClose,
+ .ops.allocate = HgfsVmciChannelAllocate,
+ .ops.free = HgfsVmciChannelFree,
+ .ops.send = HgfsVmciChannelSend,
+ .priv = NULL,
+ .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelCallback --
+ *
+ * Called when VMCI datagram is received.
+ *
+ * Results:
+ * Always 0.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int HgfsVmciChannelCallback(void *data, VMCIDatagram *dg)
+{
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelOpen --
+ *
+ * Open VMCI channel.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsVmciChannelOpen(HgfsTransportChannel *channel) // IN: Channel
+{
+ HgfsVmciTransportHeader transportHeader;
+ VMCIDatagram *dg;
+ int ret;
+
+ ASSERT(channel->status == HGFS_CHANNEL_NOTCONNECTED);
+ ASSERT(channel->priv == NULL);
+
+ if (USE_VMCI == 0) {
+ return FALSE;
+ }
+
+ channel->priv = kmalloc(sizeof(VMCIHandle), GFP_KERNEL);
+ if (NULL == channel->priv) {
+ return FALSE;
+ }
+
+ ret = VMCIDatagram_CreateHnd(VMCI_INVALID_ID, /* Resource ID */
+ VMCI_FLAG_DG_NONE, /* Flags */
+ HgfsVmciChannelCallback,/* Datagram Recv Callback*/
+ NULL, /* Callback data */
+ channel->priv); /* VMCI outhandle */
+ if (ret != VMCI_SUCCESS) {
+ LOG(1, (KERN_WARNING "Failed to create VMCI handle %d\n", ret));
+ kfree(channel->priv);
+ return FALSE;
+ }
+
+ transportHeader.version = HGFS_VMCI_VERSION_1;
+ transportHeader.iovCount = 0;
+
+ /*
+ * Send a datagram to the VMX with the HgfsTransportHeader as the datagram
+ * payload
+ */
+ dg = kmalloc(sizeof *dg + sizeof transportHeader, GFP_KERNEL);
+ if (NULL == dg) {
+ LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__));
+ VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+ kfree(channel->priv);
+ return FALSE;
+ }
+
+ memcpy(VMCI_DG_PAYLOAD(dg), &transportHeader, sizeof transportHeader);
+
+ dg->src = *(VMCIHandle *)channel->priv;
+ dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT);
+ dg->payloadSize = sizeof transportHeader;
+
+ if ((ret = VMCIDatagram_Send(dg)) < VMCI_SUCCESS) {
+ LOG(4, (KERN_WARNING "Failure with %d\n", ret));
+ VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+ kfree(dg);
+ kfree(channel->priv);
+ return FALSE;
+ }
+
+ kfree(dg);
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelClose --
+ *
+ * Destroy vmci handle.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsVmciChannelClose(HgfsTransportChannel *channel) // IN: Channel
+{
+ ASSERT(channel->priv != NULL);
+
+ VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+ kfree(channel->priv);
+ channel->priv = NULL;
+
+ LOG(8, ("VMware hgfs: %s: vmci closed.\n", __func__));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelAllocate --
+ *
+ * Allocate request in the way that is suitable for sending through
+ * vmci. Today, we just allocate a page for the request and we ignore
+ * payloadSize. We need this to support variable sized requests in future.
+ *
+ * Results:
+ * NULL on failure; otherwise address of the new request.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static HgfsReq *
+HgfsVmciChannelAllocate(size_t payloadSize) // IN: Ignored
+{
+ HgfsReq *req = NULL;
+ const size_t size = PAGE_SIZE;
+
+ req = kmalloc(size, GFP_KERNEL);
+ if (likely(req)) {
+ req->payload = req->buffer + sizeof (HgfsVmciTransportStatus);
+ req->bufferSize = size - sizeof (HgfsVmciTransportStatus) - sizeof *req;
+ }
+
+ /* We asked for PAGE_SIZE, it should be page aligned */
+ ASSERT(((long)req & 0x00000fff) == 0);
+ LOG(10, (KERN_WARNING "%s: Allocated Request\n", __func__));
+ return req;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelFree --
+ *
+ * Free previously allocated request.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsVmciChannelFree(HgfsReq *req)
+{
+ ASSERT(req);
+ kfree(req);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsVmciChannelSend --
+ *
+ * Send a request via vmci.
+ *
+ * Results:
+ * 0 on success, negative error on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HgfsVmciChannelSend(HgfsTransportChannel *channel, // IN: Channel
+ HgfsReq *req) // IN: request to send
+{
+ int ret;
+ int iovCount = 0;
+ HgfsReply *reply;
+ VMCIDatagram *dg;
+ HgfsVmciTransportHeader *transportHeader;
+ HgfsVmciTransportStatus *transportStatus;
+ size_t transportHeaderSize;
+ size_t bufferSize;
+ size_t total;
+ uint64 pa;
+ uint64 len;
+ size_t va;
+ int j;
+
+ ASSERT(req);
+ ASSERT(req->state == HGFS_REQ_STATE_UNSENT || req->state == HGFS_REQ_STATE_ALLOCATED);
+ ASSERT(req->payloadSize <= req->bufferSize);
+
+ LOG(4, ("VMware hgfs: %s: VMCI sending.\n", __func__));
+
+ /*
+ +------------+
+ + page 1 + <----- We can have request starting from here
+ +------------+
+ + page 2 +
+ +------------+
+ + page 3 + <----- ..and ending here
+ +------------+
+ */
+
+ /* Note that req->bufferSize does not include chunk used by the transport. */
+ total = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+ bufferSize = 0;
+
+ /* Calculate number of entries for metaPacket */
+ iovCount = 1;
+ va = (size_t)req->buffer;
+ len = total < (PAGE_SIZE - va % PAGE_SIZE) ? total : (PAGE_SIZE - va % PAGE_SIZE);
+ total -= len;
+ iovCount += (total + PAGE_SIZE - 1)/ PAGE_SIZE;
+
+ ASSERT(iovCount >= 1);
+ transportHeaderSize = sizeof *transportHeader +
+ (iovCount + req->numEntries - 1) * sizeof (HgfsIov);
+ dg = kmalloc(sizeof *dg + transportHeaderSize, GFP_KERNEL);
+ if (NULL == dg) {
+ LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__));
+ return -ENOMEM;
+ }
+
+ /* Initialize datagram */
+ dg->src = *(VMCIHandle *)channel->priv;
+ dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT);
+ dg->payloadSize = transportHeaderSize;
+
+ transportHeader = VMCI_DG_PAYLOAD(dg);
+
+ /* Initialize transport header */
+ transportHeader->version = HGFS_VMCI_VERSION_1;
+
+ total = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+ bufferSize = 0;
+ for (iovCount = 0; bufferSize < req->bufferSize; iovCount++) {
+ /*
+ * req->buffer should have been allocated by kmalloc()/ __get_free_pages().
+ * Specifically, it cannot be a buffer that is mapped from high memory.
+ * virt_to_phys() does not work for those.
+ */
+ pa = virt_to_phys(req->buffer + bufferSize);
+ len = total < (PAGE_SIZE - pa % PAGE_SIZE) ? total : (PAGE_SIZE - pa % PAGE_SIZE);
+ bufferSize += len;
+ total -= len;
+ transportHeader->iov[iovCount].pa = pa;
+ transportHeader->iov[iovCount].len = len;
+ LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount,
+ transportHeader->iov[iovCount].pa, transportHeader->iov[iovCount].len));
+ }
+
+ /* Right now we do not expect discontigous request packet */
+ ASSERT(iovCount == 1);
+ ASSERT(total == 0);
+ ASSERT(bufferSize == req->bufferSize + sizeof (HgfsVmciTransportStatus));
+
+ LOG(8, ("Size of request is %Zu %Zu\n", req->payloadSize, sizeof (HgfsRequest)));
+
+ for (j = 0; j < req->numEntries; j++, iovCount++) {
+ /* I will have to probably do page table walk here, haven't figured it out yet */
+ transportHeader->iov[iovCount].pa = page_to_phys(req->dataPacket[j].page);
+ transportHeader->iov[iovCount].pa += req->dataPacket[j].offset;
+ transportHeader->iov[iovCount].len = req->dataPacket[j].len;
+ LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount,
+ transportHeader->iov[iovCount].pa,
+ transportHeader->iov[iovCount].len));
+ }
+
+ transportHeader->iovCount = iovCount;
+
+ ASSERT(iovCount <= HGFS_MAX_IOV);
+
+ /* Initialize transport Status */
+ transportStatus = (HgfsVmciTransportStatus *)req->buffer;
+ transportStatus->status = HGFS_VMCI_IO_PENDING;
+ transportStatus->flags = 0;
+ transportStatus->size = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+
+ LOG(8, (KERN_WARNING "Physical addr is %"FMT64"x len=%u iovCount=%u numEntries=%u\n",
+ transportHeader->iov[0].pa,
+ transportHeader->iov[0].len,
+ transportHeader->iovCount,
+ req->numEntries));
+ LOG(8, (KERN_WARNING "Id = %u op = %u\n",
+ ((HgfsRequest *)req->payload)->id,
+ ((HgfsRequest *)req->payload)->op));
+
+ if((ret = VMCIDatagram_Send(dg)) < VMCI_SUCCESS) {
+ if (ret == HGFS_VMCI_TRANSPORT_ERROR) {
+ LOG(0, (KERN_WARNING "HGFS Transport error occured. Don't blame VMCI\n"));
+ }
+ req->state = HGFS_REQ_STATE_UNSENT;
+ kfree(dg);
+ return -EIO;
+ }
+
+ LOG(8, (KERN_WARNING "VMware hgfs: %s: VMCI reply received.\n", __func__));
+
+ /* For HgfsVmciStage2 everything should complete sync. */
+ ASSERT(transportStatus->status == HGFS_VMCI_IO_COMPLETE);
+
+ if (transportStatus->status == HGFS_VMCI_IO_COMPLETE) {
+ reply = (HgfsReply *)req->payload;
+ req->payloadSize = transportStatus->size;
+ ASSERT(transportStatus->size <= (req->bufferSize + sizeof (HgfsVmciTransportStatus)));
+ HgfsCompleteReq(req);
+ LOG(8, (KERN_WARNING "IO_COMPLETE: id = %u status = %u\n",
+ (uint32)reply->id, (uint32)reply->status));
+ }
+
+ kfree(dg);
+ return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsGetVmciChannel --
+ *
+ * Initialize Vmci channel.
+ *
+ * Results:
+ * Always return pointer to Vmci channel.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+HgfsTransportChannel*
+HgfsGetVmciChannel(void)
+{
+ return &channel;
+}