From: VMware, Inc <> Date: Mon, 26 Apr 2010 17:56:09 +0000 (-0700) Subject: Guest/Host Interface for VMCI. X-Git-Tag: 2010.04.25-253928~63 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=19186660a8a23bf633b0ce6e04996dd7e65a5fc7;p=thirdparty%2Fopen-vm-tools.git Guest/Host Interface for VMCI. 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 --- diff --git a/open-vm-tools/lib/hgfsServer/Makefile.am b/open-vm-tools/lib/hgfsServer/Makefile.am index acd2b3954..d39942f0e 100644 --- a/open-vm-tools/lib/hgfsServer/Makefile.am +++ b/open-vm-tools/lib/hgfsServer/Makefile.am @@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libHgfsServer.la 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 = diff --git a/open-vm-tools/lib/hgfsServer/hgfsServer.c b/open-vm-tools/lib/hgfsServer/hgfsServer.c index bcfeaf185..3218c7029 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServer.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServer.c @@ -31,6 +31,7 @@ #include "util.h" #include "wiper.h" #include "hgfsDirNotify.h" +#include "hgfsTransport.h" #if defined(_WIN32) #include @@ -153,18 +154,17 @@ struct HgfsStaticSession { #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. @@ -2489,10 +2489,11 @@ HgfsUpdateNodeNames(const char *oldLocalName, // IN: Name of file to look for */ 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; @@ -2516,8 +2517,9 @@ HgfsServerClose(char const *packetIn, // IN: incoming packet 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; } @@ -2525,8 +2527,7 @@ HgfsServerClose(char const *packetIn, // IN: incoming packet return 0; error: - free(packetOut); - + HSPU_PutReplyPacket(input->packet, session); return status; } @@ -2549,10 +2550,11 @@ error: */ 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; @@ -2576,8 +2578,9 @@ HgfsServerSearchClose(char const *packetIn, // IN: incoming packet 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; } @@ -2585,8 +2588,7 @@ HgfsServerSearchClose(char const *packetIn, // IN: incoming packet return 0; error: - free(packetOut); - + HSPU_PutReplyPacket(input->packet, session); return status; } @@ -2596,9 +2598,7 @@ error: /* 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; @@ -2646,7 +2646,8 @@ static struct { { HgfsServerSymlinkCreate, HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3) }, { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange) }, { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) }, - + { HgfsServerRead, HGFS_SIZEOF_OP(HgfsRequestReadV3) }, + { HgfsServerWrite, HGFS_SIZEOF_OP(HgfsRequestWriteV3) }, }; @@ -2669,6 +2670,8 @@ static struct { * 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 * @@ -2679,20 +2682,21 @@ static struct { */ 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__, @@ -2701,14 +2705,28 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet 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; } @@ -2717,18 +2735,20 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet 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__)); @@ -2737,10 +2757,13 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet 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 { /* @@ -2765,26 +2788,41 @@ err: 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); } } } @@ -2905,9 +2943,9 @@ HgfsServer_ExitState(void) */ 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); @@ -2991,7 +3029,7 @@ HgfsServerSessionConnect(void *transportData, // IN: transport session co 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. */ @@ -3220,6 +3258,7 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet size_t *packetLen, // IN/OUT: packet length HgfsReceiveFlags flags) // IN: flags { + HgfsPacket packet; ASSERT(packetIn); ASSERT(packetOut); ASSERT(packetLen); @@ -3245,7 +3284,18 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet 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 @@ -3255,12 +3305,10 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet 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 @@ -3285,10 +3333,12 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet */ 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); } @@ -3309,25 +3359,29 @@ HgfsServerSessionSendComplete(void *clientData, // IN: session currently unused */ 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 } @@ -3355,23 +3409,25 @@ HgfsPacketSend(char *packet, // IN: packet buffer */ 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); } @@ -5093,7 +5149,7 @@ HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct * Allocates hgfs reply packet and initializes its header. * * Results: - * Size of the allocated packet. + * TRUE on success, FALSE on failure. * * Side effects: * None @@ -5101,24 +5157,31 @@ HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo, // IN: open info struct *----------------------------------------------------------------------------- */ -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, @@ -5129,6 +5192,10 @@ HgfsAllocInitReply(char const *packetIn, // IN: incoming packet HgfsRequest const *request = (HgfsRequest const *)packetIn; HgfsPackLegacyReplyHeader(status, request->id, (HgfsReply *)*packetOut); } + + return TRUE; +exit: + return FALSE; } @@ -5149,12 +5216,15 @@ HgfsAllocInitReply(char const *packetIn, // IN: incoming packet */ 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); @@ -5166,32 +5236,43 @@ HgfsPackOpenReply(char const *packetIn, // IN: incoming packet 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; } @@ -5323,7 +5404,7 @@ HgfsUnpackCloseRequest(char const *packetIn, // IN: request packet * Pack hgfs close reply to the HgfsReplyClose(V3) structure. * * Results: - * Always TRUE. + * TRUE on success, FALSE on failure * * Side effects: * None @@ -5332,12 +5413,15 @@ HgfsUnpackCloseRequest(char const *packetIn, // IN: request packet */ 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); @@ -5348,23 +5432,23 @@ HgfsPackCloseReply(char const *packetIn, // IN: incoming packet 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; } @@ -5497,8 +5581,7 @@ HgfsUnpackSearchCloseRequest(char const *packetIn, // IN: request packet * 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 @@ -5507,12 +5590,15 @@ HgfsUnpackSearchCloseRequest(char const *packetIn, // IN: request packet */ 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); @@ -5523,23 +5609,23 @@ HgfsPackSearchCloseReply(char const *packetIn, // IN: incoming packet 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; } @@ -5911,11 +5997,13 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet */ 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); @@ -5930,8 +6018,8 @@ HgfsPackDeleteReply(char const *packetIn, // IN: incoming packet 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: @@ -5940,8 +6028,8 @@ HgfsPackDeleteReply(char const *packetIn, // IN: incoming packet 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: @@ -6319,11 +6407,13 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet */ 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); @@ -6336,16 +6426,16 @@ HgfsPackRenameReply(char const *packetIn, // IN: incoming packet 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: @@ -6897,14 +6987,17 @@ HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet */ 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); @@ -6916,11 +7009,15 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet 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; @@ -6931,11 +7028,15 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet 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, @@ -6950,8 +7051,12 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet 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; } @@ -6959,11 +7064,11 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet default: LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__)); NOT_REACHED(); - - return FALSE; + result = FALSE; } - return TRUE; +error: + return result; } @@ -7173,14 +7278,17 @@ HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet */ 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; @@ -7191,11 +7299,16 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet 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; @@ -7205,11 +7318,16 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet 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, @@ -7222,11 +7340,16 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet 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, @@ -7238,11 +7361,12 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet default: { LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__)); NOT_REACHED(); - return FALSE; + result = FALSE; } } - return TRUE; +error: + return result; } @@ -7544,11 +7668,13 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet */ 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; @@ -7561,16 +7687,16 @@ HgfsPackSetattrReply(char const *packetIn, // IN: incoming packet 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: @@ -7842,11 +7968,13 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet */ 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; @@ -7859,22 +7987,22 @@ HgfsPackCreateDirReply(char const *packetIn, // IN: create dir operation ve 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: @@ -8003,14 +8131,17 @@ HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet */ 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); @@ -8022,11 +8153,13 @@ HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet 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; } diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h index 83e493726..34f8c0aa2 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h +++ b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h @@ -98,6 +98,22 @@ # 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 @@ -305,8 +321,8 @@ typedef struct HgfsSessionInfo { /* 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; @@ -438,6 +454,14 @@ typedef struct { 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 @@ -524,79 +548,49 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator */ 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. */ @@ -606,12 +600,13 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: incoming packet 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 @@ -633,11 +628,13 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet 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 @@ -654,21 +651,24 @@ 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 @@ -677,13 +677,15 @@ HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet 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 @@ -696,12 +698,13 @@ 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 @@ -709,11 +712,13 @@ 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 @@ -725,34 +730,44 @@ 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. */ @@ -909,21 +924,83 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info /* 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__ */ diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c index 095fb07df..b5eda9ff2 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c @@ -3397,10 +3397,11 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in */ 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; @@ -3519,10 +3520,10 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet 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; @@ -3563,10 +3564,10 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet */ 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; @@ -3579,12 +3580,38 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet 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; @@ -3598,18 +3625,19 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet 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; @@ -3638,7 +3666,9 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet 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; @@ -3652,14 +3682,13 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet 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__) @@ -3712,17 +3741,23 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet 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; } @@ -3745,12 +3780,12 @@ error: */ 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; @@ -3762,38 +3797,84 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet 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; @@ -3808,10 +3889,18 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet 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) ? @@ -3820,26 +3909,13 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet 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__) @@ -3893,14 +3969,19 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet *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; } @@ -3923,10 +4004,11 @@ error: */ 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; @@ -3939,6 +4021,7 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet uint32 dirNameLength; HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; size_t replySize; + size_t replyPacketSize; char *packetOut; HgfsShareInfo shareInfo; @@ -3951,7 +4034,9 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet 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); @@ -3970,7 +4055,9 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet 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); @@ -4087,15 +4174,15 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet */ *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; } @@ -4118,10 +4205,11 @@ exit: */ 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; @@ -4319,8 +4407,8 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * 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; } @@ -4330,8 +4418,9 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet 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; } @@ -4341,13 +4430,13 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet 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; } @@ -4371,10 +4460,11 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet */ 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; @@ -4479,13 +4569,13 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet } 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: @@ -4511,10 +4601,11 @@ 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; @@ -4542,12 +4633,13 @@ HgfsServerSetattr(char const *packetIn, // IN: incoming packet 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; @@ -4577,10 +4669,11 @@ exit: */ 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; @@ -4670,12 +4763,12 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet 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; } @@ -4702,10 +4795,11 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet */ 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; @@ -4777,11 +4871,12 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet 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; } @@ -4808,10 +4903,11 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet */ 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; @@ -4891,11 +4987,12 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet 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; } @@ -4922,10 +5019,11 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet */ 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; @@ -5109,12 +5207,13 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet */ 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: @@ -5150,10 +5249,11 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet */ 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; @@ -5178,6 +5278,7 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet uint64 *totalBytes; char *packetOut; size_t packetOutSize; + size_t replyPacketSize; HgfsShareInfo shareInfo; ASSERT(packetIn); @@ -5191,7 +5292,10 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet 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); /* @@ -5221,7 +5325,10 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet 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; @@ -5230,7 +5337,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet /* Enforced by the dispatch function. */ ASSERT(packetSize >= sizeof *request); extra = packetSize - sizeof *request; - fileName = request->fileName.name; fileNameLength = request->fileName.length; } @@ -5401,14 +5507,14 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet *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; } @@ -5431,10 +5537,11 @@ exit: */ 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; @@ -5449,6 +5556,7 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet HgfsShareOptions configOptions; char *packetOut = NULL; size_t packetOutSize; + size_t replyPacketSize; HgfsInternalStatus status = 0; size_t localSymlinkNameLen; HgfsShareInfo shareInfo; @@ -5486,54 +5594,59 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet */ 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, @@ -5609,7 +5722,8 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet } status = 0; - if (!HgfsPackAndSendPacket(packetOut, packetOutSize, status, header->id, + if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize, + status, header->id, session, 0)) { goto exit; } @@ -5618,7 +5732,7 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet exit: free(localSymlinkName); - free(packetOut); + HSPU_PutReplyPacket(input->packet, session); return status; } @@ -5775,9 +5889,7 @@ exit: */ 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; } @@ -5802,9 +5914,7 @@ HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet */ 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; } diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c b/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c new file mode 100644 index 000000000..77ce074d6 --- /dev/null +++ b/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c @@ -0,0 +1,606 @@ +/********************************************************* + * 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 +#include +#include + +#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); + } +} + + diff --git a/open-vm-tools/lib/include/hgfsChannel.h b/open-vm-tools/lib/include/hgfsChannel.h index 6fe7c569d..02cf108ff 100644 --- a/open-vm-tools/lib/include/hgfsChannel.h +++ b/open-vm-tools/lib/include/hgfsChannel.h @@ -47,5 +47,4 @@ typedef struct HgfsChannelCBTable { 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 diff --git a/open-vm-tools/lib/include/hgfsProto.h b/open-vm-tools/lib/include/hgfsProto.h index 077ba726c..9fbe80ec6 100644 --- a/open-vm-tools/lib/include/hgfsProto.h +++ b/open-vm-tools/lib/include/hgfsProto.h @@ -118,7 +118,8 @@ typedef enum { 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. */ @@ -165,55 +166,6 @@ typedef enum { #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. diff --git a/open-vm-tools/lib/include/hgfsServer.h b/open-vm-tools/lib/include/hgfsServer.h index 9a7102ed1..e8f01f7b9 100644 --- a/open-vm-tools/lib/include/hgfsServer.h +++ b/open-vm-tools/lib/include/hgfsServer.h @@ -35,6 +35,49 @@ typedef struct HgfsServerStateLogger { 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. @@ -75,13 +118,21 @@ HgfsSessionSendFunc(void *opaqueSession, // IN 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 *); diff --git a/open-vm-tools/lib/include/hgfsTransport.h b/open-vm-tools/lib/include/hgfsTransport.h new file mode 100644 index 000000000..2e68f8534 --- /dev/null +++ b/open-vm-tools/lib/include/hgfsTransport.h @@ -0,0 +1,161 @@ +/********************************************************* + * 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_ */ + diff --git a/open-vm-tools/lib/include/hgfsUtil.h b/open-vm-tools/lib/include/hgfsUtil.h index d814b41f9..e95894d80 100644 --- a/open-vm-tools/lib/include/hgfsUtil.h +++ b/open-vm-tools/lib/include/hgfsUtil.h @@ -114,8 +114,8 @@ struct timespec { #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 /* diff --git a/open-vm-tools/lib/include/vmci_defs.h b/open-vm-tools/lib/include/vmci_defs.h new file mode 100644 index 000000000..76d141660 --- /dev/null +++ b/open-vm-tools/lib/include/vmci_defs.h @@ -0,0 +1,790 @@ +/********************************************************* + * 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 + diff --git a/open-vm-tools/modules/freebsd/vmhgfs/transport.c b/open-vm-tools/modules/freebsd/vmhgfs/transport.c index 3078e670a..4ea26674f 100644 --- a/open-vm-tools/modules/freebsd/vmhgfs/transport.c +++ b/open-vm-tools/modules/freebsd/vmhgfs/transport.c @@ -90,7 +90,7 @@ HgfsSendOpenDirRequest(HgfsSuperInfo *sip, // IN: Superinfo pointer 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 @@ -190,7 +190,7 @@ HgfsSendOpenRequest(HgfsSuperInfo *sip, // IN: Superinfo pointer 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); diff --git a/open-vm-tools/modules/freebsd/vmhgfs/vfsopscommon.c b/open-vm-tools/modules/freebsd/vmhgfs/vfsopscommon.c index 8b9b59c58..06064083e 100644 --- a/open-vm-tools/modules/freebsd/vmhgfs/vfsopscommon.c +++ b/open-vm-tools/modules/freebsd/vmhgfs/vfsopscommon.c @@ -92,7 +92,7 @@ HgfsStatfsInt(struct vnode *vp, // IN: vnode 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); diff --git a/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c b/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c index cfe4d1fbc..79ede7764 100644 --- a/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c +++ b/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c @@ -554,7 +554,7 @@ HgfsSetattrInt(struct vnode *vp, // IN : vnode of the file 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 @@ -1431,7 +1431,7 @@ HgfsMkdirInt(struct vnode *dvp, // IN : directory vnode 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 @@ -2179,7 +2179,7 @@ HgfsDelete(HgfsSuperInfo *sip, // IN: Superinfo 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 @@ -2523,7 +2523,7 @@ HgfsSymlinkInt(struct vnode *dvp, // IN : directory vnode 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 @@ -2781,7 +2781,7 @@ HgfsQueryAttrInt(const char *path, // IN : Path to get attributes for 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 diff --git a/open-vm-tools/modules/linux/shared/vmci_defs.h b/open-vm-tools/modules/linux/shared/vmci_defs.h index 3ae90f1f6..c58b6d8ac 100644 --- a/open-vm-tools/modules/linux/shared/vmci_defs.h +++ b/open-vm-tools/modules/linux/shared/vmci_defs.h @@ -93,7 +93,8 @@ typedef uint32 VMCI_Resource; #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; @@ -107,7 +108,9 @@ static INLINE VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid, VMCIId rid) { - VMCIHandle h = {cid, rid}; + VMCIHandle h; + h.context = cid; + h.resource = rid; return h; } @@ -263,6 +266,10 @@ static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID, #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) diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c index 935c8a92e..5bcac3f55 100644 --- a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c +++ b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c @@ -27,17 +27,34 @@ #include -#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 +}; + + /* *----------------------------------------------------------------------------- * @@ -104,7 +121,7 @@ HgfsBdChannelClose(HgfsTransportChannel *channel) // IN: Channel * * 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: @@ -129,12 +146,37 @@ HgfsBdChannelAllocate(size_t payloadSize) // IN: size of requests payload 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); +} + + /* *---------------------------------------------------------------------- * @@ -161,7 +203,7 @@ HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel 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; @@ -200,15 +242,5 @@ HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel 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; } diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.h b/open-vm-tools/modules/linux/vmhgfs/bdhandler.h deleted file mode 100644 index 2689e9cae..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/bdhandler.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************* - * 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_ diff --git a/open-vm-tools/modules/linux/vmhgfs/dir.c b/open-vm-tools/modules/linux/vmhgfs/dir.c index b9f6ddbef..c94c9518f 100644 --- a/open-vm-tools/modules/linux/vmhgfs/dir.c +++ b/open-vm-tools/modules/linux/vmhgfs/dir.c @@ -167,7 +167,7 @@ HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet * Make sure name length is legal. */ if (fileNameLength > NAME_MAX || - fileNameLength > HGFS_PACKET_MAX - replySize) { + fileNameLength > req->bufferSize - replySize) { return -ENAMETOOLONG; } @@ -395,7 +395,7 @@ HgfsPackDirOpenRequest(struct file *file, // IN: File pointer for this open } /* 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; @@ -405,7 +405,7 @@ HgfsPackDirOpenRequest(struct file *file, // IN: File pointer for this open /* 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")); diff --git a/open-vm-tools/modules/linux/vmhgfs/file.c b/open-vm-tools/modules/linux/vmhgfs/file.c index c7ab86ec9..f486f71d5 100644 --- a/open-vm-tools/modules/linux/vmhgfs/file.c +++ b/open-vm-tools/modules/linux/vmhgfs/file.c @@ -315,7 +315,7 @@ HgfsPackOpenRequest(struct inode *inode, // IN: Inode of the file to open /* 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")); @@ -327,7 +327,7 @@ HgfsPackOpenRequest(struct inode *inode, // IN: Inode of the file to open /* 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 " diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.c b/open-vm-tools/modules/linux/vmhgfs/filesystem.c index a1ae581f4..338ed5526 100644 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.c +++ b/open-vm-tools/modules/linux/vmhgfs/filesystem.c @@ -117,6 +117,7 @@ static struct file_system_type hgfsType = { .kill_sb = kill_anon_super, }; +extern int USE_VMCI; /* * Private functions implementations. @@ -527,6 +528,12 @@ HgfsResetOps(void) 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; + } + } diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.c b/open-vm-tools/modules/linux/vmhgfs/fsutil.c index 39fd8aa0c..4c0b9fdba 100644 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.c +++ b/open-vm-tools/modules/linux/vmhgfs/fsutil.c @@ -164,7 +164,7 @@ HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet 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; @@ -176,7 +176,7 @@ HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet 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; @@ -279,7 +279,7 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer } 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; } @@ -308,7 +308,7 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer fileNameLength = &requestV2->fileName.length; } reqSize = sizeof *requestV2; - reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV2); + reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2); break; } @@ -322,7 +322,7 @@ HgfsPackGetattrRequest(HgfsReq *req, // IN/OUT: Request buffer 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; } diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.c b/open-vm-tools/modules/linux/vmhgfs/inode.c index 8361cbccf..a9f57c857 100644 --- a/open-vm-tools/modules/linux/vmhgfs/inode.c +++ b/open-vm-tools/modules/linux/vmhgfs/inode.c @@ -238,7 +238,7 @@ HgfsDelete(struct inode *dir, // IN: Parent dir of file/dir to delete } /* 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; @@ -249,7 +249,7 @@ HgfsDelete(struct inode *dir, // IN: Parent dir of file/dir to delete /* 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")); @@ -449,7 +449,7 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from } 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: @@ -552,7 +552,7 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from 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: @@ -626,7 +626,7 @@ HgfsPackSetattrRequest(struct iattr *iattr, // IN: Inode attrs to update from 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); /* @@ -811,7 +811,7 @@ HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create /* 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")); @@ -822,7 +822,7 @@ HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create /* 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 " @@ -1364,7 +1364,7 @@ retry: } /* 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; @@ -1375,7 +1375,7 @@ retry: /* 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 " @@ -1413,7 +1413,7 @@ retry: 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; @@ -1424,7 +1424,7 @@ retry: /* 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 " @@ -1545,7 +1545,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry, // IN: File pointer for th 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")); @@ -1557,7 +1557,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry, // IN: File pointer for th /* 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 " @@ -1597,7 +1597,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry, // IN: File pointer for th 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; diff --git a/open-vm-tools/modules/linux/vmhgfs/page.c b/open-vm-tools/modules/linux/vmhgfs/page.c index 746165294..5ec0bf094 100644 --- a/open-vm-tools/modules/linux/vmhgfs/page.c +++ b/open-vm-tools/modules/linux/vmhgfs/page.c @@ -43,15 +43,17 @@ #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, @@ -143,6 +145,8 @@ struct address_space_operations HgfsAddressSpaceOperations = { * 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. * @@ -153,10 +157,10 @@ struct address_space_operations HgfsAddressSpaceOperations = { */ 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; @@ -164,8 +168,9 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file uint32 actualSize = 0; char *payload = NULL; HgfsStatus replyStatus; - - ASSERT(buf); + char *buf; + ASSERT(numEntries == 1); + uint32 count = dataPacket[0].len; req = HgfsGetNewRequest(); if (!req) { @@ -177,7 +182,31 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file 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; @@ -190,6 +219,7 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file request->offset = offset; request->requiredSize = count; request->reserved = 0; + req->dataPacket = NULL; req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); } else { HgfsRequestRead *request; @@ -200,10 +230,10 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file 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) { @@ -213,7 +243,9 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file 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 { @@ -229,7 +261,7 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file } 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; @@ -237,19 +269,34 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file } /* 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; @@ -267,6 +314,9 @@ HgfsDoRead(HgfsHandle handle, // IN: Handle for this file } out: + if (req->dataPacket) { + kfree(req->dataPacket); + } HgfsFreeRequest(req); return result; } @@ -286,6 +336,9 @@ out: * 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. * @@ -296,10 +349,10 @@ out: */ 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; @@ -309,8 +362,9 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file char *payload = NULL; uint32 reqSize; HgfsStatus replyStatus; - - ASSERT(buf); + char *buf; + ASSERT(numEntries == 1); + uint32 count = dataPacket[0].len; req = HgfsGetNewRequest(); if (!req) { @@ -322,7 +376,7 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file retry: opUsed = hgfsVersionWrite; - if (opUsed == HGFS_OP_WRITE_V3) { + if (opUsed == HGFS_OP_WRITE_FAST_V3) { HgfsRequest *header; HgfsRequestWriteV3 *request; @@ -338,7 +392,42 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file 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; @@ -352,10 +441,13 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file 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); @@ -366,7 +458,7 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file 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; @@ -380,11 +472,21 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file 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; @@ -404,6 +506,9 @@ HgfsDoWrite(HgfsHandle handle, // IN: Handle for this file } out: + if (req->dataPacket) { + kfree(req->dataPacket); + } HgfsFreeRequest(req); return result; } @@ -436,9 +541,9 @@ HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading 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)); @@ -452,7 +557,10 @@ HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading 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)); @@ -460,7 +568,7 @@ HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading } remainingCount -= result; curOffset += result; - buffer += result; + pageFrom += result; } while ((result > 0) && (remainingCount > 0)); /* @@ -468,7 +576,11 @@ HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading * 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 @@ -480,7 +592,6 @@ HgfsDoReadpage(HgfsHandle handle, // IN: Handle to use for reading result = 0; out: - kunmap(page); return result; } @@ -526,11 +637,11 @@ HgfsDoWritepage(HgfsHandle handle, // IN: Handle to use for writing 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); @@ -545,7 +656,10 @@ HgfsDoWritepage(HgfsHandle handle, // IN: Handle to use for writing 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)); @@ -553,7 +667,7 @@ HgfsDoWritepage(HgfsHandle handle, // IN: Handle to use for writing } 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)) { @@ -564,7 +678,6 @@ HgfsDoWritepage(HgfsHandle handle, // IN: Handle to use for writing result = 0; out: - kunmap(page); return result; } diff --git a/open-vm-tools/modules/linux/vmhgfs/request.c b/open-vm-tools/modules/linux/vmhgfs/request.c index 0bd6cb880..f0d3b7474 100644 --- a/open-vm-tools/modules/linux/vmhgfs/request.c +++ b/open-vm-tools/modules/linux/vmhgfs/request.c @@ -59,7 +59,6 @@ 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); @@ -69,8 +68,8 @@ HgfsRequestInit(HgfsReq *req, // IN: request to initialize init_waitqueue_head(&req->queue); req->id = requestId; req->payloadSize = 0; - req->bufferSize = bufferSize; req->state = HGFS_REQ_STATE_ALLOCATED; + req->numEntries = 0; } /* @@ -102,12 +101,12 @@ HgfsGetNewRequest(void) return NULL; } - HgfsRequestInit(req, HGFS_PACKET_MAX, - atomic_inc_return(&hgfsIdCounter) - 1); + HgfsRequestInit(req, atomic_inc_return(&hgfsIdCounter) - 1); return req; } + /* *---------------------------------------------------------------------- * @@ -139,9 +138,12 @@ HgfsCopyRequest(HgfsReq *req) // IN: request to be copied 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); @@ -170,8 +172,8 @@ HgfsSendRequest(HgfsReq *req) // IN/OUT: Outgoing request 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", @@ -205,7 +207,7 @@ static void HgfsRequestFreeMemory(struct kref *kref) LOG(10, (KERN_DEBUG "VMware hgfs: %s: freeing request %d\n", __func__, req->id)); - kfree(req); + HgfsTransportFreeRequest(req); } /* diff --git a/open-vm-tools/modules/linux/vmhgfs/request.h b/open-vm-tools/modules/linux/vmhgfs/request.h index e4a9bdebf..29a5483f7 100644 --- a/open-vm-tools/modules/linux/vmhgfs/request.h +++ b/open-vm-tools/modules/linux/vmhgfs/request.h @@ -35,6 +35,7 @@ #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. */ @@ -44,6 +45,8 @@ #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 @@ -76,6 +79,16 @@ typedef enum { 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. */ @@ -111,10 +124,20 @@ typedef struct HgfsReq { /* * 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. diff --git a/open-vm-tools/modules/linux/vmhgfs/super.c b/open-vm-tools/modules/linux/vmhgfs/super.c index 49460c2cf..1502513b2 100644 --- a/open-vm-tools/modules/linux/vmhgfs/super.c +++ b/open-vm-tools/modules/linux/vmhgfs/super.c @@ -227,7 +227,7 @@ HgfsPackQueryVolumeRequest(struct dentry *dentry, // IN: File pointer for this } /* 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; @@ -237,7 +237,7 @@ HgfsPackQueryVolumeRequest(struct dentry *dentry, // IN: File pointer for this /* 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")); diff --git a/open-vm-tools/modules/linux/vmhgfs/tcp.c b/open-vm-tools/modules/linux/vmhgfs/tcp.c index d2071d986..0b6990efb 100644 --- a/open-vm-tools/modules/linux/vmhgfs/tcp.c +++ b/open-vm-tools/modules/linux/vmhgfs/tcp.c @@ -47,7 +47,7 @@ #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); @@ -113,6 +113,37 @@ static unsigned long hgfsRecvThreadFlags; /* Used to signal recv data availabili 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 +}; + + /* *---------------------------------------------------------------------- * @@ -855,12 +886,37 @@ HgfsSocketChannelAllocate(size_t payloadSize) // IN: size of the payload 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); +} + + /* *---------------------------------------------------------------------- * @@ -880,21 +936,11 @@ HgfsSocketChannelAllocate(size_t payloadSize) // IN: size of the payload 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; } @@ -917,18 +963,10 @@ HgfsGetTcpChannel(void) 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; } + diff --git a/open-vm-tools/modules/linux/vmhgfs/tcp.h b/open-vm-tools/modules/linux/vmhgfs/tcp.h deleted file mode 100644 index b24f8a150..000000000 --- a/open-vm-tools/modules/linux/vmhgfs/tcp.h +++ /dev/null @@ -1,33 +0,0 @@ -/********************************************************* - * 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_ diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.c b/open-vm-tools/modules/linux/vmhgfs/transport.c index 747e92c7d..735aa0bf2 100644 --- a/open-vm-tools/modules/linux/vmhgfs/transport.c +++ b/open-vm-tools/modules/linux/vmhgfs/transport.c @@ -45,15 +45,15 @@ /* Must be included after sched.h. */ #include -#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. */ @@ -157,10 +157,22 @@ HgfsTransportSetupNewChannel(void) { 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; } } @@ -169,11 +181,13 @@ HgfsTransportSetupNewChannel(void) 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); @@ -345,6 +359,36 @@ HgfsTransportAllocateRequest(size_t bufferSize) // IN: size of the buffer 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; +} + /* *---------------------------------------------------------------------- @@ -370,7 +414,7 @@ HgfsTransportSendRequest(HgfsReq *req) // IN: Request to send ASSERT(req); ASSERT(req->state == HGFS_REQ_STATE_UNSENT); - ASSERT(req->payloadSize <= HGFS_PACKET_MAX); + ASSERT(req->payloadSize <= req->bufferSize); compat_mutex_lock(&hgfsChannelLock); @@ -393,7 +437,7 @@ HgfsTransportSendRequest(HgfsReq *req) // IN: Request to send 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); diff --git a/open-vm-tools/modules/linux/vmhgfs/transport.h b/open-vm-tools/modules/linux/vmhgfs/transport.h index 478b59d11..e4ce8e3bc 100644 --- a/open-vm-tools/modules/linux/vmhgfs/transport.h +++ b/open-vm-tools/modules/linux/vmhgfs/transport.h @@ -36,6 +36,7 @@ typedef struct HgfsTransportChannelOps { void (*close)(struct HgfsTransportChannel *); HgfsReq* (*allocate)(size_t payloadSize); int (*send)(struct HgfsTransportChannel *, HgfsReq *); + void (*free)(HgfsReq *); } HgfsTransportChannelOps; typedef enum { @@ -57,10 +58,16 @@ typedef struct HgfsTransportChannel { 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_ diff --git a/open-vm-tools/modules/linux/vmhgfs/vmci.c b/open-vm-tools/modules/linux/vmhgfs/vmci.c new file mode 100644 index 000000000..b3c139df2 --- /dev/null +++ b/open-vm-tools/modules/linux/vmhgfs/vmci.c @@ -0,0 +1,438 @@ +/********************************************************* + * 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 +#include +#include + +#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; +}