Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1189 lines
55 KiB

/****************************************************************************/
// anmapi.c
//
// Network Manger
//
// Copyright(C) Microsoft Corporation 1997-1999
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_GROUP TRC_GROUP_NETWORK
#define TRC_FILE "anmapi"
#define pTRCWd (pRealNMHandle->pWDHandle)
#include <adcg.h>
#include <acomapi.h>
#include <anmint.h>
#include <asmapi.h>
#include <nwdwapi.h>
#include <anmapi.h>
#include <nprcount.h>
#include <tschannl.h>
/****************************************************************************/
/* Name: NM_GetDataSize */
/* */
/* Purpose: Returns size of per-instance NM data required */
/* */
/* Returns: size of data required */
/* */
/* Operation: NM stores per-instance data in a piece of memory allocated */
/* by WDW. This function returns the size of the data required. */
/* A pointer to this data (the 'NM Handle') is passed into all */
/* subsequent NM functions. */
/****************************************************************************/
unsigned RDPCALL NM_GetDataSize(void)
{
DC_BEGIN_FN("NM_GetDataSize");
DC_END_FN();
return(sizeof(NM_HANDLE_DATA));
} /* NM_GetDataSize */
/****************************************************************************/
/* Name: NM_Init */
/* */
/* Purpose: Initialize NM */
/* */
/* Returns: TRUE - Registered OK */
/* FALSE - Registration failed */
/* */
/* Params: pNMHandle - NM handle */
/* pSMHandle - SM handle, stored by NM and passed on callbacks */
/* to SM */
/* pWDHandle - WD handle, required for tracing */
/* hDomainKernel - MCS handle stored from MCSInitialize() and */
/* used to attach a user. */
/* */
/* Operation: Initialize NM: */
/* - initialize per-instance data */
/* - open channel for communication with PDMCS */
/****************************************************************************/
BOOL RDPCALL NM_Init(PVOID pNMHandle,
PVOID pSMHandle,
PTSHARE_WD pWDHandle,
DomainHandle hDomainKernel)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
DC_BEGIN_FN("NM_Init");
/************************************************************************/
/* WARNING: Don't trace before storing the WD Handle */
/************************************************************************/
pRealNMHandle->pWDHandle = pWDHandle;
pRealNMHandle->pSMHandle = pSMHandle;
pRealNMHandle->pContext = pWDHandle->pContext;
pRealNMHandle->hDomain = hDomainKernel;
DC_END_FN();
return(TRUE);
} /* NM_Init */
/****************************************************************************/
/* Name: NM_Term */
/* */
/* Purpose: Terminate NM */
/* */
/* Params: pNMHandle - NM handle */
/* */
/* Operation: Terminate NM */
/* - close channel opened by NM_Init */
/****************************************************************************/
void RDPCALL NM_Term(PVOID pNMHandle)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
unsigned i;
PNM_CHANNEL_DATA pChannelData;
DC_BEGIN_FN("NM_Term");
TRC_NRM((TB, "Terminate NM"));
/************************************************************************/
/* Free any half-received virtual channel data */
/************************************************************************/
for (i = 0, pChannelData = pRealNMHandle->channelData;
i < pRealNMHandle->channelArrayCount;
i++, pChannelData++)
{
if (pChannelData->pData != NULL)
{
TRC_NRM((TB, "Free %p", pChannelData->pData));
COM_Free(pChannelData->pData);
}
}
DC_END_FN();
} /* NM_Term */
/****************************************************************************/
/* Name: NM_Connect */
/* */
/* Purpose: Starts the process of connecting to the Client */
/* */
/* Returns: TRUE - Connect started OK */
/* FALSE - Connect failed to start */
/* */
/* Params: pNMHandle - NM handle */
/* pUserDataIn - user data received from Client */
/* */
/* Operation: Attach the user to the domain. PDMCS knows about only 1 */
/* domain, so that one is assumed. */
/* */
/* When the AttachUser completes, join two channels: */
/* - the dynamically allocated broadcast channel (ID returned on */
/* the SM_OnConnected callback) */
/* - the single-user channel for this user. */
/* */
/* Note that this function completes asynchronously. The caller */
/* must wait for a SM_OnConnected or SM_OnDisconnected */
/* callback to find out whether the Connect succeeded or failed. */
/****************************************************************************/
BOOL RDPCALL NM_Connect(PVOID pNMHandle, PRNS_UD_CS_NET pUserDataIn)
{
BOOL rc = FALSE;
BOOLEAN bCompleted;
MCSError MCSErr;
ChannelHandle hChannel;
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
unsigned i, j;
unsigned userDataOutLength;
PRNS_UD_SC_NET pUserDataOut = NULL;
PCHANNEL_DEF pChannel;
UINT16 *pMCSChannel;
ChannelID ChID;
UINT32 DataLenValidate;
// for unalignment use purpose
UserHandle UserHandleTemp;
unsigned MaxSendSizeTemp;
DC_BEGIN_FN("NM_Connect");
/************************************************************************/
/* Clear the connection status */
/************************************************************************/
pRealNMHandle->connectStatus = 0;
/************************************************************************/
/* Save virtual channel data */
/************************************************************************/
if (pUserDataIn != NULL)
{
TRC_DATA_NRM("Net User Data",
pUserDataIn,
pUserDataIn->header.length);
TRC_NRM((TB, "Protocol version %#x (%#x/%#x)",
pRealNMHandle->pWDHandle->version,
_RNS_MAJOR_VERSION(pRealNMHandle->pWDHandle->version),
_RNS_MINOR_VERSION(pRealNMHandle->pWDHandle->version)));
/********************************************************************/
/* Protocol version 0x00080002 used 2-byte channel data lengths. */
/* Protocol version 0x00080003 and higher use 4-byte data lengths. */
/* If this is a 2-byte version, ignore its virtual channels. */
/********************************************************************/
if (_RNS_MINOR_VERSION(pRealNMHandle->pWDHandle->version) >= 3)
{
// Validate channle count
DataLenValidate = pUserDataIn->channelCount * sizeof(CHANNEL_DEF);
DataLenValidate += sizeof(RNS_UD_CS_NET);
if (DataLenValidate > pUserDataIn->header.length)
{
TRC_ERR((TB, "Error: Virtual channel data length %u too short for %u",
pUserDataIn->header.length, DataLenValidate));
pRealNMHandle->channelCount = 0;
pRealNMHandle->channelArrayCount = 0;
WDW_LogAndDisconnect(pRealNMHandle->pWDHandle, TRUE,
Log_RDP_VChannelDataTooShort, (PBYTE)pUserDataIn, pUserDataIn->header.length);
DC_QUIT;
}
// we reserve channel 7 for RDPDD so we can allow only the
// buffer size - 1 channels.
if (pUserDataIn->channelCount > sizeof(pRealNMHandle->channelData)
/ sizeof(pRealNMHandle->channelData[0]) - 1) {
TRC_ERR((TB, "Error: Too many virtual channels to join: %u.",
pUserDataIn->channelCount));
pRealNMHandle->channelCount = 0;
pRealNMHandle->channelArrayCount = 0;
WDW_LogAndDisconnect(pRealNMHandle->pWDHandle, TRUE,
Log_RDP_VChannelsTooMany, (PBYTE)pUserDataIn,
pUserDataIn->header.length);
DC_QUIT;
}
pRealNMHandle->channelCount = pUserDataIn->channelCount;
pChannel = (PCHANNEL_DEF)(pUserDataIn + 1);
for (i = 0, j = 0; i < pRealNMHandle->channelCount; i++, j++)
{
/************************************************************/
/* Channel 7 is used by RDPDD, so skip it */
/************************************************************/
if (i == WD_THINWIRE_CHANNEL)
{
j++;
}
/************************************************************/
/* Save channel data */
/************************************************************/
strncpy(pRealNMHandle->channelData[j].name,
pChannel[i].name,
CHANNEL_NAME_LEN);
// make sure that the name is zero-terminated
(pRealNMHandle->channelData[j].name)[CHANNEL_NAME_LEN] = 0;
pRealNMHandle->channelData[j].flags = pChannel[i].options;
TRC_NRM((TB, "Channel %d (was %d): %s",
j, i, pChannel[i].name));
}
pRealNMHandle->channelArrayCount = j;
}
else
{
TRC_ERR((TB,
"Minor version %#x doesn't support 4-byte channel data lengths",
_RNS_MINOR_VERSION(pRealNMHandle->pWDHandle->version)));
pRealNMHandle->channelCount = 0;
pRealNMHandle->channelArrayCount = 0;
}
}
else
{
/********************************************************************/
/* No incoming user data = no virtual channels */
/********************************************************************/
TRC_NRM((TB, "No virtual channels"));
pRealNMHandle->channelCount = 0;
pRealNMHandle->channelArrayCount = 0;
}
/************************************************************************/
/* Allocate space for returned user data */
/************************************************************************/
userDataOutLength = (sizeof(RNS_UD_SC_NET) +
(sizeof(UINT16) * pRealNMHandle->channelCount));
userDataOutLength = (unsigned)(DC_ROUND_UP_4(userDataOutLength));
pUserDataOut = COM_Malloc(userDataOutLength);
if (pUserDataOut != NULL) {
memset(pUserDataOut, 0, userDataOutLength);
}
else {
TRC_ERR((TB, "Failed to alloc %d bytes for user data",
userDataOutLength));
DC_QUIT;
}
/************************************************************************/
/* Make the attach-user request call. */
/************************************************************************/
TRC_NRM((TB, "Attach User"));
UserHandleTemp = pRealNMHandle->hUser;
MaxSendSizeTemp = pRealNMHandle->maxPDUSize;
MCSErr = MCSAttachUserRequest(pRealNMHandle->hDomain,
NM_MCSUserCallback,
SM_MCSSendDataCallback,
pNMHandle,
&UserHandleTemp,
&MaxSendSizeTemp,
(BOOLEAN *)(&bCompleted));
pRealNMHandle->hUser = UserHandleTemp;
pRealNMHandle->maxPDUSize = MaxSendSizeTemp;
if (MCSErr == MCS_NO_ERROR) {
TRC_NRM((TB, "AttachUser OK, hUser %p", pRealNMHandle->hUser));
TRC_ASSERT((bCompleted),
(TB, "MCSAttachUser didn't complete synchronously"));
// Extract extra information.
pRealNMHandle->userID = MCSGetUserIDFromHandle(pRealNMHandle->hUser);
pRealNMHandle->connectStatus |= NM_CONNECT_ATTACH;
TRC_NRM((TB, "Attached as user %x, hUser %p",
pRealNMHandle->userID, pRealNMHandle->hUser));
}
else {
TRC_ERR((TB, "Failed AttachUserRequest, MCSErr %d", MCSErr));
DC_QUIT;
}
/************************************************************************/
/* Join the broadcast channel */
/************************************************************************/
MCSErr = MCSChannelJoinRequest(pRealNMHandle->hUser,
0,
&hChannel,
&bCompleted);
if (MCSErr == MCS_NO_ERROR) {
TRC_ASSERT((bCompleted),
(TB, "MCSChannelJoin didn't complete synchronously"));
// Extract information.
ChID = MCSGetChannelIDFromHandle(hChannel);
pRealNMHandle->channelID = ChID;
pRealNMHandle->hChannel = hChannel;
pRealNMHandle->connectStatus |= NM_CONNECT_JOIN_BROADCAST;
TRC_NRM((TB, "Joined broadcast channel %x (hChannel %p) OK",
ChID, hChannel));
}
else {
TRC_ERR((TB, "Failed to send ChannelJoinRequest, MCSErr %d", MCSErr));
DC_QUIT;
}
/************************************************************************/
/* Join the user channel */
/************************************************************************/
MCSErr = MCSChannelJoinRequest(pRealNMHandle->hUser,
pRealNMHandle->userID,
&hChannel,
&bCompleted);
if (MCSErr == MCS_NO_ERROR) {
TRC_ASSERT((bCompleted),
(TB, "MCSChannelJoin didn't complete synchronously"));
// Extract information.
pRealNMHandle->connectStatus |= NM_CONNECT_JOIN_USER;
TRC_NRM((TB, "Joined user channel (hChannel %p) OK", hChannel));
}
else {
TRC_ERR((TB, "Failed to send ChannelJoinRequest, MCSErr %d", MCSErr));
DC_QUIT;
}
/************************************************************************/
/* If no virtual channels, we're done. */
/************************************************************************/
if (pRealNMHandle->channelCount == 0)
{
TRC_NRM((TB, "No virtual channels to join"));
rc = TRUE;
DC_QUIT;
}
/************************************************************************/
/* Join virtual channels */
/************************************************************************/
for (i = 0; i < pRealNMHandle->channelArrayCount; i++)
{
if (i == WD_THINWIRE_CHANNEL)
{
TRC_NRM((TB, "Skip channel %d", WD_THINWIRE_CHANNEL));
continue;
}
MCSErr = MCSChannelJoinRequest(pRealNMHandle->hUser,
0,
&hChannel,
&bCompleted);
if (MCSErr == MCS_NO_ERROR) {
TRC_ASSERT((bCompleted),
(TB, "MCSChannelJoin didn't complete synchronously"));
ChID = MCSGetChannelIDFromHandle(hChannel);
pRealNMHandle->channelData[i].MCSChannelID = (UINT16)ChID;
TRC_NRM((TB, "Joined VC %d: %d (hChannel %p)", i, ChID, hChannel));
}
else {
TRC_ERR((TB, "ChannelJoinRequest failed, MCSErr %d", MCSErr));
DC_QUIT;
}
}
/************************************************************************/
/* Everything completed OK */
/************************************************************************/
rc = TRUE;
DC_EXIT_POINT:
if (rc)
{
/********************************************************************/
/* Everything is OK - Complete the user data */
/********************************************************************/
pUserDataOut->header.type = RNS_UD_SC_NET_ID;
pUserDataOut->header.length = (UINT16)userDataOutLength;
pUserDataOut->MCSChannelID = (UINT16)pRealNMHandle->channelID;
pUserDataOut->channelCount = (UINT16)pRealNMHandle->channelCount;
pMCSChannel = (UINT16 *)(pUserDataOut + 1);
TRC_NRM((TB, "Copy %d channels to user data out",
pRealNMHandle->channelCount));
for (i = 0, j = 0; i < pRealNMHandle->channelCount; i++, j++)
{
if (i == WD_THINWIRE_CHANNEL)
{
TRC_NRM((TB, "Skip channel %d", WD_THINWIRE_CHANNEL));
j++;
}
pMCSChannel[i] = pRealNMHandle->channelData[j].MCSChannelID;
TRC_NRM((TB, "Channel %d (%d) = %#x", i, j, pMCSChannel[i]));
}
/********************************************************************/
/* Tell SM we're connected now */
/********************************************************************/
TRC_NRM((TB, "Tell SM we're connecting"));
SM_OnConnected(pRealNMHandle->pSMHandle, pRealNMHandle->userID,
NM_CB_CONN_OK, pUserDataOut, pRealNMHandle->maxPDUSize);
}
else
{
/********************************************************************/
/* Something failed - abort the connection */
/********************************************************************/
TRC_NRM((TB, "Something failed - abort the connection"));
NMAbortConnect(pRealNMHandle);
}
/************************************************************************/
/* Whether we succeeded or failed, we don't need the user data any */
/* more. */
/************************************************************************/
TRC_NRM((TB, "Free user data"));
if (pUserDataOut != NULL) {
COM_Free(pUserDataOut);
}
DC_END_FN();
return(rc);
} /* NM_Connect */
/****************************************************************************/
/* Name: NM_GetMCSDomainInfo */
/* */
/* Purpose: Return the broadcast channel ID to allow shadowing of this */
/* share. */
/* */
/* Params: pNMHandle - NM handle */
/****************************************************************************/
ChannelID RDPCALL NM_GetMCSDomainInfo(PVOID pNMHandle)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
return pRealNMHandle->channelID;
}
/****************************************************************************/
/* Name: NM_Disconnect */
/* */
/* Purpose: Disconnect from a Client */
/* */
/* Returns: TRUE - Disconnect started OK */
/* FALSE - Disconnect failed */
/* */
/* Params: pNMHandle - NM handle */
/* */
/* Operation: Detach the user from the domain. */
/* */
/* Note that this function completes asynchronously. The caller */
/* must wait for a SM_OnDisconnected callback to find whether */
/* the Disconnect succeeded or failed. */
/****************************************************************************/
BOOL RDPCALL NM_Disconnect(PVOID pNMHandle)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
BOOL rc = TRUE;
DC_BEGIN_FN("NM_Disconnect");
/************************************************************************/
/* Detach from MCS */
/************************************************************************/
if (pRealNMHandle->connectStatus & NM_CONNECT_ATTACH)
{
TRC_NRM((TB, "User attached, need to detach"));
rc = NMDetachUserReq(pRealNMHandle);
}
DC_END_FN();
return(rc);
} /* NM_Disconnect */
/****************************************************************************/
/* Name: NM_AllocBuffer */
/* */
/* Purpose: Acquire a buffer for transmission */
/* */
/* Returns: TRUE - Buffer acquired OK */
/* FALSE - No buffer available */
/* */
/* Params: pNMHandle - NM handle */
/* ppBuffer - Buffer acquired (returned) */
/* bufferSize - size of buffer required */
/* */
/* Operation: Get a buffer from ICA (via IcaBufferAlloc) */
/* This function is synchronous. */
/****************************************************************************/
NTSTATUS __fastcall NM_AllocBuffer(PVOID pNMHandle,
PPVOID ppBuffer,
UINT32 bufferSize,
BOOLEAN fWait)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
NTSTATUS status;
POUTBUF pOutBuf;
int i;
UINT32 realBufferSize;
DC_BEGIN_FN("NM_AllocBuffer");
/************************************************************************/
/* Calculate the actual size of data required. Includes a POUTBUF */
/* prefix to point back to the beginning of the OutBuf so we can send */
/* the right thing to MCS. */
/************************************************************************/
TRC_ASSERT((bufferSize < 16384),
(TB,"Buffer req size %u will cause MCS fragmentation, unsupported",
bufferSize));
realBufferSize = bufferSize + SendDataReqPrefixBytes + sizeof(POUTBUF);
/************************************************************************/
/* Allocate an OutBuf */
/************************************************************************/
status = IcaBufferAlloc(pRealNMHandle->pContext,
fWait, /* wait/not wait for a buffer */
FALSE, /* not a control buffer */
realBufferSize,
NULL, /* no original buffer */
(PVOID *)(&pOutBuf));
if (status == STATUS_SUCCESS) { // NT_SUCCESS() does not fail STATUS_TIMEOUT
/********************************************************************/
/* The OutBuf returned includes a data buffer pointer, which points */
/* to a buffer containing */
/* - a pointer to the beginning of the OutBuf (which we set here) */
/* - SendDataReqPrefixBytes */
/* - user data buffer (size bufferSize) */
/* Set the OutBuf pBuffer pointer to the beginning of the user data.*/
/* MCS requires this. */
/* Return to the user a pointer to the user data buffer. */
/********************************************************************/
*((POUTBUF *)pOutBuf->pBuffer) = pOutBuf;
pOutBuf->pBuffer += SendDataReqPrefixBytes + sizeof(POUTBUF);
*ppBuffer = pOutBuf->pBuffer;
TRC_NRM((TB, "Alloc %d bytes OK", bufferSize));
}
else
{
TRC_ERR((TB, "Failed to alloc %d bytes, status %x",
bufferSize, status));
//
// TODO - consider disconnect client here instead of SM_AllocBuffer(),
// keep it in SM_AllocBuffer() so that we don't introduce any regression.
//
//
// IcaBufferAlloc() returns STATUS_IO_TIMEOUT, STATUS_NO_MEMORY, and
// IcaWaitForSingleObject() which returns KeWaitForSingleObject() or
// STATUS_CTX_CLOSE_PENDING. SM_AllocBuffer() need to disconnect this client only
// when error code is STATUS_IO_TIMEOUT so we keep this return code
}
DC_END_FN();
return status;
} /* NM_AllocBuffer */
/****************************************************************************/
/* Name: NM_FreeBuffer */
/* */
/* Purpose: Free a transmit buffer */
/* */
/* Params: pNMHandle - NM handle */
/* pBuffer - Buffer to free */
/* */
/* Operation: Free a buffer (via IcaBufferFree) */
/* This function assumes the buffer was allocated using */
/* NM_AllocBuffer. */
/* */
/* This function is only for freeing buffers which are not sent. */
/* It should not be called for buffers which are sent - */
/* NM_SendData frees the buffer whether the Send succeeds or */
/* not. */
/* */
/* This function is synchronous. */
/****************************************************************************/
void __fastcall NM_FreeBuffer(PVOID pNMHandle, PVOID pBuffer)
{
POUTBUF pOutBuf;
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
DC_BEGIN_FN("NM_FreeBuffer");
/************************************************************************/
/* Get the OutBuf pointer stored in prefix */
/************************************************************************/
pOutBuf = *((POUTBUF *)
((BYTE *)pBuffer - SendDataReqPrefixBytes - sizeof(POUTBUF)));
/************************************************************************/
/* Free the buffer */
/************************************************************************/
IcaBufferFree(pRealNMHandle->pContext, pOutBuf);
DC_END_FN();
} /* NM_FreeBuffer */
/****************************************************************************/
/* Name: NM_SendData */
/* */
/* Purpose: Send data to the appropriate net or pipe destination. */
/* */
/* Returns: TRUE - data sent OK */
/* FALSE - data not sent */
/* */
/* Params: pNMHandle - NM handle */
/* pData - data to send */
/* dataSize - length of data to send */
/* priority - priority to send the data on */
/* userID - user to send the data to (0 = broadcast data) */
/* FastPathOutputFlags - flags from higher layers. Low bit TRUE */
/* means send as fast-path output, using the rest of the */
/*
/* */
/* Operation: Send the data. */
/* - The buffer holding the data must have been allocated using */
/* NM_AllocBuffer. */
/* - Return code FALSE means that a network error occurred. The */
/* caller need do nothing - an NM_DISCONNECTED callback will */
/* eventually arrive. */
/* - The buffer is ALWAYS freed. */
/* */
/* This function is synchronous. */
/****************************************************************************/
BOOL __fastcall NM_SendData(
PVOID pNMHandle,
PBYTE pData,
UINT32 dataSize,
UINT32 priority,
UINT32 userID,
UINT32 FastPathOutputFlags)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
BOOL rc = TRUE;
POUTBUF pOutBuf;
MCSError MCSErr;
DC_BEGIN_FN("NM_SendData");
/************************************************************************/
/* Get the OutBuf pointer stored in prefix */
/************************************************************************/
pOutBuf = *((POUTBUF *)
((BYTE *)pData - SendDataReqPrefixBytes - sizeof(POUTBUF)));
/************************************************************************/
/* Complete the OutBuf. The pBuffer was already set up when the OutBuf */
/* was allocated. MCS needs the user data size set in the OutBuf. */
/************************************************************************/
pOutBuf->ByteCount = dataSize;
// All but shadow passthru stacks get the data sent to the network.
if (pRealNMHandle->pWDHandle->StackClass != Stack_Passthru) {
if (FastPathOutputFlags & NM_SEND_FASTPATH_OUTPUT) {
NTSTATUS Status;
SD_RAWWRITE SdWrite;
// Fast-path output skips MCS. We rewrite the security header
// into the fast-path format, complete the OutBuf, and send
// directly to the transport. For header format details, see
// at128.h. Note we need to wait for the security header
// to be written in SM before getting here in case this
// is a passthru stack.
// First, the 4-byte RNS_SECURITY_HEADER disappears, if present,
// collapsed into the high bit of the first byte.
// Note that the 8-byte MAC signature in RNS_SECURITY_HEADER1
// remains, if present.
if (!(FastPathOutputFlags & NM_NO_SECURITY_HEADER)) {
dataSize -= sizeof(RNS_SECURITY_HEADER);
pData += sizeof(RNS_SECURITY_HEADER);
}
// Work backwards from where we are: First, the total packet
// length including the header.
if (dataSize <= 125) {
// 1-byte form of length, high bit 0.
dataSize += 2;
pData -= 2;
*(pData + 1) = (BYTE)dataSize;
}
else {
// 2-byte form of length, first byte has high bit 1 and 7
// most significant bits.
dataSize += 3;
pData -= 3;
*(pData + 1) = (BYTE)(0x80 | ((dataSize & 0x7F00) >> 8));
*(pData + 2) = (BYTE)(dataSize & 0xFF);
}
// The header byte. This includes TS_OUTPUT_FASTPATH_ACTION_FASTPATH
// and TS_OUTPUT_FASTPATH_ENCRYPTED, if present in the
// fast-path output flags.
*pData = (BYTE)(TS_OUTPUT_FASTPATH_ACTION_FASTPATH |
(FastPathOutputFlags &
TS_OUTPUT_FASTPATH_ENCRYPTION_MASK));
// Set up the OutBuf with its final contents.
pOutBuf->pBuffer = pData;
pOutBuf->ByteCount = dataSize;
// Send downward.
SdWrite.pBuffer = NULL;
SdWrite.ByteCount = 0;
SdWrite.pOutBuf = pOutBuf;
Status = IcaCallNextDriver(pRealNMHandle->pWDHandle->pContext,
SD$RAWWRITE, &SdWrite);
if (NT_SUCCESS(Status)) {
// Increment protocol counters.
pRealNMHandle->pWDHandle->pProtocolStatus->Output.WdFrames++;
pRealNMHandle->pWDHandle->pProtocolStatus->Output.WdBytes +=
dataSize;
}
else {
TRC_ERR((TB,"Failed IcaRawWrite to network, status=%X",
Status));
rc = FALSE;
// We do not free the OutBuf here, TD is supposed to do it.
}
}
else {
TRC_DBG((TB, "Send data on channel %x", userID));
MCSErr = MCSSendDataRequest(pRealNMHandle->hUser,
userID == 0 ? pRealNMHandle->hChannel : NULL,
NORMAL_SEND_DATA,
(ChannelID)userID,
(MCSPriority)priority,
SEGMENTATION_BEGIN | SEGMENTATION_END,
pOutBuf);
if (MCSErr == MCS_NO_ERROR) {
TRC_DATA_NRM("Send OK", pOutBuf, dataSize);
}
else
{
TRC_ERR((TB, "Failed to send OutBuf %p, buffer %p, MCSErr %x",
pOutBuf, pData, MCSErr));
rc = FALSE;
}
}
#ifdef DC_COUNTERS
if (rc) {
PTSHARE_WD m_pTSWd = pRealNMHandle->pWDHandle;
if (dataSize > CORE_IN_COUNT[IN_MAX_PKT_SIZE])
{
CORE_IN_COUNT[IN_MAX_PKT_SIZE] = dataSize;
}
CORE_IN_COUNT[IN_PKT_TOTAL_SENT]++;
if (dataSize < 201) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD1]++;
} else if (dataSize < 401) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD2]++;
} else if (dataSize < 601) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD3]++;
} else if (dataSize < 801) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD4]++;
} else if (dataSize < 1001) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD5]++;
} else if (dataSize < 1201 ) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD6]++;
} else if (dataSize < 1401) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD7]++;
} else if (dataSize < 1601) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD8]++;
} else if (dataSize < 2001) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD9]++;
} else if (dataSize < 4001) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD10]++;
} else if (dataSize < 6001) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD11]++;
} else if (dataSize < 8001) {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD12]++;
} else {
CORE_IN_COUNT[IN_PKT_BYTE_SPREAD13]++;
}
}
#endif
}
// Raw write the potentially encrypted data to the shadow stack
else {
SD_RAWWRITE SdWrite;
NTSTATUS status;
TRC_ASSERT((!(FastPathOutputFlags & NM_SEND_FASTPATH_OUTPUT)),
(TB,"Fast-path output requested across shadow pipe!"));
SdWrite.pOutBuf = pOutBuf;
SdWrite.pBuffer = NULL;
SdWrite.ByteCount = 0;
status = IcaCallNextDriver(pRealNMHandle->pContext, SD$RAWWRITE, &SdWrite);
if (status == STATUS_SUCCESS) {
TRC_DBG((TB, "RawWrite: %ld bytes", dataSize));
}
else {
TRC_ERR((TB, "RawWrite failed: %lx", status));
}
}
DC_END_FN();
return rc;
} /* NM_SendData */
/****************************************************************************/
/* Name: NM_MCSUserCallback */
/* */
/* Purpose: Direct callback from MCS */
/* */
/* Returns: nothing */
/* */
/* Params: hUser - should be our user handle */
/* Message - the callback type */
/* Params - Cast to the right type of parameter depending on */
/* callback */
/* UserDefined - our NM handle */
/* */
/* Operation: Called by MCS for callbacks. */
/* */
/* Processing depends on the callback type */
/* - MCS_DETACH_USER_INDICATION */
/* - call SM_OnDisconnected */
/* - all others are ignored. */
/****************************************************************************/
void __stdcall NM_MCSUserCallback(UserHandle hUser,
unsigned Message,
void *Params,
void *UserDefined)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)UserDefined;
DC_BEGIN_FN("NM_MCSUserCallback");
/************************************************************************/
/* First check that this is our UserHandle */
/************************************************************************/
ASSERT(hUser == pRealNMHandle->hUser);
/************************************************************************/
/* If the Share Core is dead, don't do any of this */
/************************************************************************/
if (pRealNMHandle->dead)
{
TRC_ALT((TB, "Callback %s (%d) ignored because we're dead",
Message == MCS_ATTACH_USER_CONFIRM ? "MCS_ATTACH_USER_CONFIRM" :
Message == MCS_CHANNEL_JOIN_CONFIRM ? "MCS_CHANNEL_JOIN_CONFIRM" :
Message == MCS_DETACH_USER_INDICATION ? "MCS_DETACH_USER_INDICATION" :
Message == MCS_SEND_DATA_INDICATION ? "MCS_SEND_DATA_INDICATION" :
"- Unknown - ",
Message));
DC_QUIT;
}
/************************************************************************/
/* Handle callbacks we care about */
/************************************************************************/
switch (Message)
{
case MCS_DETACH_USER_INDICATION:
{
DetachUserIndication *pDUin;
TRC_NRM((TB, "DetachUserIndication"));
pDUin = (DetachUserIndication *)Params;
NMDetachUserInd(pRealNMHandle,
pDUin->Reason,
pDUin->UserID);
}
break;
default:
{
TRC_ERR((TB, "Unhandled MCS callback type %d", Message ));
}
break;
}
DC_EXIT_POINT:
DC_END_FN();
} /* NM_MCSUserCallback */
/****************************************************************************/
/* Name: NM_Dead */
/****************************************************************************/
void RDPCALL NM_Dead(PVOID pNMHandle, BOOL dead)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
DC_BEGIN_FN("NM_Dead");
TRC_NRM((TB, "NM Dead ? %s", pRealNMHandle->dead ? "Y" : "N"));
pRealNMHandle->dead = dead;
DC_END_FN();
} /* NM_Dead */
/****************************************************************************/
/* Name: NM_VirtualQueryBindings */
/* */
/* Purpose: Return virtual channel bindings to WD */
/* */
/* Params: pNMHandle - NM Handle */
/* pVBind - pointer to virtual bindings structure to fill in */
/* vBindLength - size (bytes) of virtual bindings structure */
/* pBytesReturned - size (bytes) of data returned */
/****************************************************************************/
NTSTATUS RDPCALL NM_VirtualQueryBindings(PVOID pNMHandle,
PSD_VCBIND pVBind,
ULONG vBindLength,
PULONG pBytesReturned)
{
NTSTATUS status;
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
USHORT virtualClass;
UINT i;
DC_BEGIN_FN("NM_VirtualQueryBindings");
/************************************************************************/
/* First see if we have any bindings to report */
/************************************************************************/
if (pRealNMHandle->channelCount == 0)
{
TRC_ALT((TB, "No Virtual Channels to report"));
*pBytesReturned = 0;
status = STATUS_SUCCESS;
DC_QUIT;
}
/************************************************************************/
/* Check there is enough space to report them */
/************************************************************************/
*pBytesReturned = (pRealNMHandle->channelCount * sizeof(SD_VCBIND));
if (vBindLength < *pBytesReturned)
{
TRC_ERR((TB, "Not enough space for %d VCs: need/got %d/%d",
pRealNMHandle->channelCount, *pBytesReturned, vBindLength));
status = STATUS_BUFFER_TOO_SMALL;
DC_QUIT;
}
/************************************************************************/
/* Copy channel names and assign numbers */
/************************************************************************/
for (i = 0, virtualClass = 0;
i < pRealNMHandle->channelCount;
i++, virtualClass++, pVBind++)
{
/********************************************************************/
/* Can't use channel 7 as it's used by RDPDD */
/********************************************************************/
if (i == WD_THINWIRE_CHANNEL)
{
TRC_NRM((TB, "Skip channel %d", i));
virtualClass++;
}
strcpy(pVBind->VirtualName,
pRealNMHandle->channelData[virtualClass].name);
pVBind->VirtualClass = virtualClass;
pVBind->Flags = 0;
if (pRealNMHandle->channelData[virtualClass].flags & CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT) {
pVBind->Flags |= SD_CHANNEL_FLAG_SHADOW_PERSISTENT;
}
TRC_NRM((TB, "Assigned channel %d to %s",
pVBind->VirtualClass, pVBind->VirtualName));
}
/************************************************************************/
/* That's all */
/************************************************************************/
status = STATUS_SUCCESS;
DC_EXIT_POINT:
DC_END_FN();
return(status);
} /* NM_VirtualQueryBindings */
/****************************************************************************/
/* Name: NM_MCSChannelToVirtual */
/* */
/* Purpose: Convert an MCS channel ID into a virtual channel ID */
/* */
/* Returns: Virtual Channel ID */
/* */
/* Params: pNMHandle - NM Handle */
/* channelID - MCS Channel ID */
/* ppChannelData - data stored for this channel (returned) */
/****************************************************************************/
VIRTUALCHANNELCLASS RDPCALL NM_MCSChannelToVirtual(
PVOID pNMHandle,
UINT16 channelID,
PPNM_CHANNEL_DATA ppChannelData)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
PNM_CHANNEL_DATA pChannelData;
unsigned i;
VIRTUALCHANNELCLASS rc;
DC_BEGIN_FN("NM_MCSChannelToVirtual");
/************************************************************************/
/* Find this MCS Channel */
/************************************************************************/
TRC_DBG((TB, "Find MCS channel %hx", channelID));
for (i = 0, pChannelData = pRealNMHandle->channelData;
i < pRealNMHandle->channelArrayCount;
i++, pChannelData++)
{
TRC_DBG((TB, "Compare entry %d: %hx", i, pChannelData->MCSChannelID));
if (pChannelData->MCSChannelID == channelID)
{
rc = i;
*ppChannelData = pChannelData;
TRC_NRM((TB, "MCS channel %hx is VC %d", channelID, rc));
DC_QUIT;
}
}
/************************************************************************/
/* If we get here, we failed to find a match */
/************************************************************************/
TRC_NRM((TB, "No match for MCS channel ID %hx", channelID));
rc = -1;
*ppChannelData = NULL;
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* NM_MCSChannelToVirtual */
/****************************************************************************/
/* Name: NM_VirtualChannelToMCS */
/* */
/* Purpose: Convert a virtual channel ID into an MCS channel ID */
/* */
/* Returns: MCS Channel ID */
/* */
/* Params: pNMHandle - NM Handle */
/* channelID - virtual channel ID */
/* ppChannelData - data stored for this channel (returned) */
/****************************************************************************/
INT16 RDPCALL NM_VirtualChannelToMCS(PVOID pNMHandle,
VIRTUALCHANNELCLASS channelID,
PPNM_CHANNEL_DATA ppChannelData)
{
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
INT16 rc;
DC_BEGIN_FN("NM_VirtualChannelToMCS");
/************************************************************************/
/* Check the virtual channel is in range */
/************************************************************************/
if (channelID >= (VIRTUALCHANNELCLASS)(pRealNMHandle->channelArrayCount))
{
TRC_ERR((TB, "Unknown virtual channel %d", channelID));
rc = -1;
DC_QUIT;
}
/************************************************************************/
/* Find this Virtual Channel */
/************************************************************************/
rc = pRealNMHandle->channelData[channelID].MCSChannelID;
*ppChannelData = &(pRealNMHandle->channelData[channelID]);
TRC_NRM((TB, "Virtual channel %d = MCS Channel %hx", channelID, rc));
DC_EXIT_POINT:
DC_END_FN();
return(rc);
} /* NM_VirtualChannelToMCS */
/****************************************************************************/
/* Name: NM_QueryChannels */
/* */
/* Purpose: Return virtual channel data */
/* */
/* Returns: TRUE/FALSE */
/* */
/* Params: pNMHandle - NM Handle */
/* pOutbuf - buffer to receive output data */
/* outbufLength - size of outbuf */
/* pBytesReturned - amount of data returned */
/****************************************************************************/
NTSTATUS RDPCALL NM_QueryChannels(PVOID pNMHandle,
PVOID pOutbuf,
unsigned outbufLength,
PULONG pBytesReturned)
{
NTSTATUS status;
PCHANNEL_CONNECT_IN pChannelConnect;
PCHANNEL_CONNECT_DEF pChannelDef;
PNM_HANDLE_DATA pRealNMHandle = (PNM_HANDLE_DATA)pNMHandle;
unsigned bytesNeeded;
unsigned i;
DC_BEGIN_FN("NM_QueryChannels");
/************************************************************************/
/* Check enough space has been supplied */
/************************************************************************/
bytesNeeded = sizeof(CHANNEL_CONNECT_IN) +
(pRealNMHandle->channelArrayCount * sizeof(CHANNEL_CONNECT_DEF));
if (outbufLength < bytesNeeded)
{
TRC_ERR((TB, "Not enough space: need/got %d/%d",
bytesNeeded, outbufLength));
status = STATUS_BUFFER_TOO_SMALL;
DC_QUIT;
}
/************************************************************************/
/* Complete the returned data */
/************************************************************************/
pChannelConnect = (PCHANNEL_CONNECT_IN)pOutbuf;
pChannelConnect->channelCount = pRealNMHandle->channelArrayCount;
pChannelDef = (PCHANNEL_CONNECT_DEF)(pChannelConnect + 1);
for (i = 0; i < pRealNMHandle->channelArrayCount; i++)
{
strcpy(pChannelDef[i].name, pRealNMHandle->channelData[i].name);
pChannelDef[i].ID = i;
}
/************************************************************************/
/* Return status and bytesReturned */
/************************************************************************/
*pBytesReturned = bytesNeeded;
status = STATUS_SUCCESS;
DC_EXIT_POINT:
DC_END_FN();
return(status);
} /* NM_QueryChannels */