/**MOD+**********************************************************************/ /* Module: ncapi.cpp */ /* */ /* Purpose: Node Controller API/callbacks */ /* */ /* Copyright(C) Microsoft Corporation 1997-1999 */ /* */ /****************************************************************************/ #include extern "C" { #define TRC_GROUP TRC_GROUP_NETWORK #define TRC_FILE "ncapi" #include } #include "autil.h" #include "nc.h" #include "cd.h" #include "nl.h" #include "mcs.h" #include "cchan.h" /****************************************************************************/ /* MCS user data header bytes. */ /****************************************************************************/ const DCINT8 ncMCSHeader[NC_MCS_HDRLEN] = { 0x00, 0x05, 0x00, 0x14, 0x7C, 0x00, 0x01 }; /****************************************************************************/ /* GCC CreateConferenceRequest PDU body */ /****************************************************************************/ const DCINT8 ncGCCBody[NC_GCC_REQLEN] = { 0x00, /* extension bit; 3 * choice bits; 3 * optional fields */ 0x08, /* 5*Optional (user data only);2*ConfName options;length bit 0 */ 0x00, /* Length bits 1-7; pad bit */ 0x10, /* Conference name (numeric) = "1"; locked; listed; */ 0x00, /* conductible; 2*Terminate =automatic; pad */ 0x01, /* Number of UserData fields */ '\xC0', /* optional;choice;6*size (0=>4 octets) */ 0x00 /* 2* size; 6* pad */ }; CNC::CNC(CObjs* objs) { _pClientObjects = objs; } CNC::~CNC() { } #ifdef OS_WIN32 /**PROC+*********************************************************************/ /* Name: NC_Main */ /* */ /* Purpose: Receiver Thread message loop */ /* */ /* Returns: None */ /* */ /* Params: None */ /* */ /**PROC-*********************************************************************/ DCVOID DCAPI CNC::NC_Main(DCVOID) { MSG msg; DC_BEGIN_FN("NC_Main"); TRC_NRM((TB, _T("Receiver Thread initialization"))); #if defined(OS_WINCE) && defined(WINCE_USEBRUSHCACHE) BrushCacheInitialize(); #endif _pCd = _pClientObjects->_pCdObject; _pCc = _pClientObjects->_pCcObject; _pMcs = _pClientObjects->_pMCSObject; _pUt = _pClientObjects->_pUtObject; _pRcv = _pClientObjects->_pRcvObject; _pNl = _pClientObjects->_pNlObject; _pSl = _pClientObjects->_pSlObject; _pUi = _pClientObjects->_pUiObject; _pChan = _pClientObjects->_pChanObject; NC_Init(); TRC_NRM((TB, _T("Start Receiver Thread message loop"))); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } TRC_NRM((TB, _T("Exit Receiver Thread message loop"))); NC_Term(); #if defined(OS_WINCE) && defined(WINCE_USEBRUSHCACHE) BrushCacheUninitialize(); #endif /************************************************************************/ /* This is the end of the Receiver Thread. */ /************************************************************************/ TRC_NRM((TB, _T("Receiver Thread terminates"))); DC_END_FN(); return; } /* NC_Main */ #endif /* OS_WIN32 */ /**PROC+*********************************************************************/ /* Name: NC_Init */ /* */ /* Purpose: Initialize the Node Controller */ /* */ /* Returns: None */ /* */ /* Params: None */ /* */ /**PROC-*********************************************************************/ DCVOID DCAPI CNC::NC_Init(DCVOID) { DC_BEGIN_FN("NC_Init"); /************************************************************************/ /* Initialize global data. */ /************************************************************************/ DC_MEMSET(&_NC, 0, sizeof(_NC)); /************************************************************************/ /* Register with CD, to receive messages. */ /************************************************************************/ _pCd->CD_RegisterComponent(CD_RCV_COMPONENT); /************************************************************************/ /* Initialize lower layers. */ /************************************************************************/ _pMcs->MCS_Init(); /************************************************************************/ /* Initialize virtual channel stuff */ /************************************************************************/ _pChan->ChannelOnInitializing(); TRC_NRM((TB, _T("NC successfully initialized"))); /************************************************************************/ /* Tell the Core that we are initialized */ /************************************************************************/ _pNl->_NL.callbacks.onInitialized(_pSl); _pChan->ChannelOnInitialized(); DC_END_FN(); return; } /* NC_Init */ /**PROC+*********************************************************************/ /* Name: NC_Term */ /* */ /* Purpose: Terminate the Node Controller */ /* */ /* Returns: None */ /* */ /* Params: None */ /* */ /**PROC-*********************************************************************/ DCVOID DCAPI CNC::NC_Term(DCVOID) { DC_BEGIN_FN("NC_Term"); /************************************************************************/ /* Tell core that we are terminating */ /************************************************************************/ _pNl->_NL.callbacks.onTerminating(_pSl); _pChan->ChannelOnTerminating(); /************************************************************************/ /* Terminate lower NL layers. */ /************************************************************************/ _pMcs->MCS_Term(); /************************************************************************/ /* Unregister with CD */ /************************************************************************/ _pCd->CD_UnregisterComponent(CD_RCV_COMPONENT); DC_END_FN(); return; } /* NC_Term */ /**PROC+*********************************************************************/ /* Name: NC_Connect */ /* */ /* Purpose: Connect to the requested Server by calling MCS */ /* */ /* Returns: None */ /* */ /* Params: IN pData - user data (SL + Core) */ /* IN dataLen - length */ /* */ /* Operation: Send an MCSConnectProvider request with a GCC Create */ /* Conference request encoded in the user data. The encoding is */ /* as follows: */ /* */ /* number of bytes value */ /* =============== ===== */ /* NC_MCS_HDRLEN MCS header */ /* 1 or 2 Total GCC PDU length */ /* NC_GCC_REQLEN GCC CreateConference PDU body */ /* 4 H221 key */ /* 1 or 2 length of GCC user data */ /* ? GCC user data */ /* */ /**PROC-*********************************************************************/ DCVOID DCAPI CNC::NC_Connect(PDCVOID pData, DCUINT dataLen) { PNC_CONNECT_DATA pConn; PDCUINT8 pAddress; PDCUINT8 pProtocol; PDCUINT8 pUserData; DCUINT userDataLen; DCUINT mcsUserDataLen; DCUINT gccPDULen; PDCUINT8 pGCCPDU; DCUINT8 mcsUserData[NC_GCCREQ_MAX_PDULEN]; RNS_UD_CS_NET netUserData; PCHANNEL_DEF pVirtualChannels; BOOL bInitateConnect; DC_BEGIN_FN("NC_Connect"); DC_IGNORE_PARAMETER(dataLen); /************************************************************************/ /* We are about to dereference pData as NC_CONNECT_DATA. Thus, we must */ /* have at least that much in our PDU. */ /************************************************************************/ if (dataLen < ((ULONG)FIELDOFFSET(NC_CONNECT_DATA, userDataLen) + (ULONG)FIELDSIZE(NC_CONNECT_DATA, userDataLen))) { DCUINT errorCode; TRC_ABORT((TB, _T("Not enough data for NC_CONNECT_DATA struct: %u"), dataLen)); /************************************************************************/ /* We haven't even called into the MCS layer yet, so the disconnect */ /* is a bit tricky. Uninitialize our layer and bubble up. */ /************************************************************************/ errorCode = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOUSERDATA); NC_OnMCSDisconnected(errorCode); DC_QUIT; } pConn = (PNC_CONNECT_DATA)pData; bInitateConnect = pConn->bInitateConnect; if( bInitateConnect ) { pAddress = pConn->data; TRC_ASSERT((pConn->addressLen > 0), (TB, _T("Invalid address length"))); } else { pAddress = NULL; TRC_ASSERT((pConn->addressLen == 0), (TB, _T("Invalid address length %u"), pConn->addressLen)); } pProtocol = pConn->data + pConn->addressLen; pUserData = pConn->data + pConn->addressLen + pConn->protocolLen; /************************************************************************/ /* Verify that pUserdata sits within the data passed in, since */ /* we just get the pointer from an offset specified in the packet. */ /************************************************************************/ if (!IsContainedPointer(pData,dataLen,pUserData)) { DCUINT errorCode; TRC_ABORT((TB, _T("Invalid offset in data (pConn->addressLen): %u"), pConn->addressLen)); /************************************************************************/ /* We haven't even called into the MCS layer yet, so the disconnect */ /* is a bit tricky. Uninitialize our layer and bubble up. */ /************************************************************************/ errorCode = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOUSERDATA); NC_OnMCSDisconnected(errorCode); DC_QUIT; } if( bInitateConnect ) { TRC_DBG((TB, _T("Server address %s"), pProtocol)); } else { TRC_DBG((TB, _T("Server address : not initiate connection%s"))); } TRC_DBG((TB, _T("Protocol %s"), pProtocol)); TRC_DBG((TB, _T("User data length %u"), pConn->userDataLen)); TRC_DATA_NRM("User data from Core+SL", pUserData, pConn->userDataLen); /************************************************************************/ /* Get Virtual Channel user data */ /************************************************************************/ userDataLen = pConn->userDataLen; _pChan->ChannelOnConnecting(&pVirtualChannels, &(netUserData.channelCount)); TRC_NRM((TB, _T("%d virtual channels"), netUserData.channelCount)); if (netUserData.channelCount != 0) { netUserData.header.type = RNS_UD_CS_NET_ID; netUserData.header.length = (DCUINT16)(sizeof(RNS_UD_CS_NET) + (netUserData.channelCount * sizeof(CHANNEL_DEF))); pConn->userDataLen += netUserData.header.length; TRC_NRM((TB, _T("User data length (NET/total): %d/%d"), netUserData.header.length, pConn->userDataLen)); } TRC_ASSERT((pConn->userDataLen <= NC_MAX_UDLEN), (TB, _T("Too much userdata (%u)"), pConn->userDataLen)); /************************************************************************/ /* Work out the length of the GCC PDU: Fixed body + H221 Key + */ /* userDataLength (1 or 2) + user Data */ /************************************************************************/ gccPDULen = NC_GCC_REQLEN + H221_KEY_LEN + 1 + pConn->userDataLen; if (pConn->userDataLen >= 128) { TRC_DBG((TB, _T("Two byte GCC PDU length field"))); gccPDULen++; } TRC_DBG((TB, _T("GCC PDU Length %u"), gccPDULen)); /************************************************************************/ /* Write fixed MCS header */ /************************************************************************/ pGCCPDU = &(mcsUserData[0]); DC_MEMCPY(pGCCPDU, ncMCSHeader, NC_MCS_HDRLEN); pGCCPDU += NC_MCS_HDRLEN; /************************************************************************/ /* SECURITY: Note that the first few fields that we write into pGCCPDU */ /* don't have to be validated for buffer overruns. This is because */ /* they are fixed-size, and pGCCPDU points to a fixed-size buffer. */ /* The first variable-length field that is written into this buffer is */ /* pUserData (len==userDataLen), which is below. */ /************************************************************************/ if (gccPDULen < 128) { /********************************************************************/ /* single length byte */ /********************************************************************/ *pGCCPDU++ = (DCUINT8)gccPDULen; } else { /********************************************************************/ /* two length bytes */ /********************************************************************/ *pGCCPDU++ = (DCUINT8)((gccPDULen >> 8) | 0x0080); *pGCCPDU++ = (DCUINT8)(gccPDULen & 0x00FF); } /************************************************************************/ /* Fixed GCC PDU body */ /************************************************************************/ DC_MEMCPY(pGCCPDU, ncGCCBody, NC_GCC_REQLEN); pGCCPDU += NC_GCC_REQLEN; /************************************************************************/ /* H221 key */ /************************************************************************/ DC_MEMCPY(pGCCPDU, CLIENT_H221_KEY, H221_KEY_LEN); pGCCPDU += H221_KEY_LEN; /************************************************************************/ /* Total Length = MCS header + GCC PDU + 1 or 2 length bytes. */ /************************************************************************/ mcsUserDataLen = NC_MCS_HDRLEN + gccPDULen + 1; /************************************************************************/ /* The GCC user data length field - 2 bytes if length > 127. */ /************************************************************************/ if (pConn->userDataLen < 128) { *pGCCPDU++ = (DCUINT8)(pConn->userDataLen & 0x00ff); } else { TRC_NRM((TB, _T("Long UserData %d"), pConn->userDataLen)); *pGCCPDU++ = (DCUINT8)((pConn->userDataLen >> 8) | 0x0080); *pGCCPDU++ = (DCUINT8)(pConn->userDataLen & 0x00ff); /********************************************************************/ /* Add extra length byte */ /********************************************************************/ mcsUserDataLen++; } /********************************************************************/ /* Verify that the buffer has enough room, AND the source has */ /* enough data. */ /********************************************************************/ if (!IsContainedMemory(&(mcsUserData[0]), NC_GCCREQ_MAX_PDULEN, pGCCPDU, userDataLen) || !IsContainedMemory(pData, dataLen, pUserData, userDataLen)) { DCUINT errorCode; TRC_ABORT((TB, _T("Data source/dest size mismatch: targetsize=%u, sourcebuf=%u, copysize=%u"), NC_GCCREQ_MAX_PDULEN, dataLen, userDataLen)); /************************************************************************/ /* Again, haven't called into MCS layer yet, so disconnect by calling */ /* NC_OnMCSDisconnected directly. */ /************************************************************************/ errorCode = NL_MAKE_DISCONNECT_ERR(NL_ERR_NCNOUSERDATA); NC_OnMCSDisconnected(errorCode); DC_QUIT; } /************************************************************************/ /* Write the SL + core UserData. */ /************************************************************************/ DC_MEMCPY(pGCCPDU, pUserData, userDataLen); /************************************************************************/ /* Write the NET user data */ /************************************************************************/ if (netUserData.channelCount != 0) { TRC_NRM((TB, _T("Append NET user data"))); pGCCPDU += userDataLen; DC_MEMCPY(pGCCPDU, &netUserData, sizeof(netUserData)); pGCCPDU += sizeof(netUserData); DC_MEMCPY(pGCCPDU, pVirtualChannels, netUserData.header.length - sizeof(netUserData)); } TRC_DATA_NRM("MCS User Data passed in", mcsUserData, mcsUserDataLen); /************************************************************************/ /* Call MCS_Connect passing in the GCC CreateConference PDU as */ /* userdata. */ /************************************************************************/ _pMcs->MCS_Connect(bInitateConnect, (PDCTCHAR)pAddress, mcsUserData, mcsUserDataLen); DC_EXIT_POINT: DC_END_FN(); return; } /* NC_Connect */ /**PROC+*********************************************************************/ /* Name: NC_Disconnect */ /* */ /* Purpose: Disconnect from the Server by calling MCS */ /* */ /* Returns: None */ /* */ /* Params: IN unused - unused parameter */ /* */ /**PROC-*********************************************************************/ DCVOID DCAPI CNC::NC_Disconnect(ULONG_PTR unused) { DC_BEGIN_FN("NC_Disconnect"); DC_IGNORE_PARAMETER(unused); /************************************************************************/ /* Disconnect from the server by calling MCS_Disconnect. */ /************************************************************************/ TRC_NRM((TB, _T("Call MCS_Disconnect"))); _pMcs->MCS_Disconnect(); DC_END_FN(); return; } /* NC_Disconnect */