//-------------------------------------------------------------------- // Copyright (C)1998 Microsoft Corporation, All Rights Reserved. // // scep.cpp // // This file holds most of the implementation of CSCEP_CONNECTION // objects. Each active connection to a camera is represented by // a separate CSCEP_CONNECTION object. The CSCEP_CONNECTION is then // destroyed when the connection (socket) to the camera is closed. // // Author: // // Edward Reus (edwardr) 02-24-98 Initial coding. // //-------------------------------------------------------------------- #include "precomp.h" typedef struct _ATTRIBUTE_TOKEN { DWORD dwTokenType; UCHAR *pChars; DWORD dwSize; } ATTRIBUTE_TOKEN; #define ATTRIBUTE_NAME_SIZE 2 #define COLON ':' #define ONE '1' #define SPACE ' ' #define TAB '\t' #define CR 0x0d #define LF 0x0a #define ATTRIBUTE_NAME 0 #define ATTRIBUTE_COLON 1 #define ATTRIBUTE_VALUE 2 #define ATTRIBUTE_CRLF 3 #define ATTR_PDU_SIZE 0 #define ATTR_PRODUCT_ID 1 #define ATTR_USER_NAME 2 #define ATTR_PASSWORD 3 //-------------------------------------------------------------------- // Globals: //-------------------------------------------------------------------- static DWORD g_adwPduSizes[] = { PDU_SIZE_1, PDU_SIZE_2, PDU_SIZE_3, PDU_SIZE_4 }; #ifdef DBG_MEM static LONG g_lCScepConnectionCount = 0; #endif //-------------------------------------------------------------------- // SkipBlanks() // //-------------------------------------------------------------------- void SkipBlanks( IN OUT UCHAR **ppAttributes, IN OUT DWORD *pdwAttributeSize ) { while ( (*pdwAttributeSize > 0) && ((**ppAttributes == SPACE)||(**ppAttributes == TAB)) ) { (*ppAttributes)++; (*pdwAttributeSize)--; } } //-------------------------------------------------------------------- // NextToken() // //-------------------------------------------------------------------- ATTRIBUTE_TOKEN *NextToken( IN DWORD dwTokenType, IN OUT UCHAR **ppAttributes, IN OUT DWORD *pdwAttributeSize ) { ATTRIBUTE_TOKEN *pToken = 0; SkipBlanks(ppAttributes,pdwAttributeSize); if ((!*ppAttributes) || (*pdwAttributeSize == 0)) { return 0; } pToken = (ATTRIBUTE_TOKEN*)AllocateMemory(sizeof(ATTRIBUTE_TOKEN)); if (!pToken) { return 0; } pToken->dwTokenType = dwTokenType; switch (dwTokenType) { case ATTRIBUTE_NAME: if (*pdwAttributeSize < ATTRIBUTE_NAME_SIZE) { FreeMemory(pToken); pToken = 0; break; } pToken->pChars = *ppAttributes; pToken->dwSize = ATTRIBUTE_NAME_SIZE; *ppAttributes += ATTRIBUTE_NAME_SIZE; *pdwAttributeSize -= ATTRIBUTE_NAME_SIZE; break; case ATTRIBUTE_COLON: if (**ppAttributes == COLON) { pToken->pChars = *ppAttributes; pToken->dwSize = 1; *ppAttributes += 1; *pdwAttributeSize -= 1; } break; case ATTRIBUTE_VALUE: pToken->pChars = *ppAttributes; pToken->dwSize = 0; while ((**ppAttributes != CR) && (*pdwAttributeSize > 0)) { (*ppAttributes)++; (*pdwAttributeSize)--; (pToken->dwSize)++; } break; case ATTRIBUTE_CRLF: pToken->pChars = *ppAttributes; pToken->dwSize = 2; *ppAttributes += 2; *pdwAttributeSize -= 2; if ((pToken->pChars[0] != CR)||(pToken->pChars[1] != LF)) { FreeMemory(pToken); pToken = 0; } break; default: FreeMemory(pToken); pToken = 0; break; } return pToken; } //-------------------------------------------------------------------- // IsAttributeName() // //-------------------------------------------------------------------- BOOL IsAttributeName( ATTRIBUTE_TOKEN *pToken, int *piAttribute ) { BOOL fIsName = FALSE; if ((pToken->pChars[0] == 'f')&&(pToken->pChars[1] == 'r')) { fIsName = TRUE; *piAttribute = ATTR_PDU_SIZE; } else if ((pToken->pChars[0] == 'i')&&(pToken->pChars[1] == 'd')) { fIsName = TRUE; *piAttribute = ATTR_PRODUCT_ID; } else if ((pToken->pChars[0] == 'n')&&(pToken->pChars[1] == 'm')) { fIsName = TRUE; *piAttribute = ATTR_USER_NAME; } else if ((pToken->pChars[0] == 'p')&&(pToken->pChars[1] == 'w')) { fIsName = TRUE; *piAttribute = ATTR_PASSWORD; } return fIsName; } //-------------------------------------------------------------------- // NewTokenString() // //-------------------------------------------------------------------- UCHAR *NewTokenString( IN ATTRIBUTE_TOKEN *pToken, OUT DWORD *pdwStatus ) { UCHAR *pszNewStr = (UCHAR*)AllocateMemory(1+pToken->dwSize); if (!pszNewStr) { *pdwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; return 0; } memcpy(pszNewStr,pToken->pChars,pToken->dwSize); pszNewStr[pToken->dwSize] = 0; return pszNewStr; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CSCEP_CONNECTION() // //-------------------------------------------------------------------- CSCEP_CONNECTION::CSCEP_CONNECTION() { m_dwConnectionState = STATE_CLOSED; m_dwPduSendSize = PDU_SIZE_1; // default is 512 bytes. m_dwPduReceiveSize = PDU_SIZE_4; m_CFlag = 0; m_pPrimaryMachineId = 0; m_pSecondaryMachineId = 0; m_DestPid = DEFAULT_PID; m_SrcPid = DEFAULT_PID; m_pszUserName = 0; m_pszPassword = 0; m_pAssembleBuffer = 0; m_dwAssembleBufferSize = 0; m_dwMaxAssembleBufferSize = 0; m_fDidByteSwap = FALSE; m_Fragmented = FALSE; m_DFlag = 0; m_dwSequenceNo = 0; m_dwRestNo = 0; m_dwCommandId = 0; m_pCommandHeader = 0; m_pszFileName = 0; m_pszLongFileName = 0; m_pwszFileName = 0; m_CreateTime.dwLowDateTime = 0; // Picture create date/time. m_CreateTime.dwHighDateTime = 0; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::~CSCEP_CONNECTION() // //-------------------------------------------------------------------- CSCEP_CONNECTION::~CSCEP_CONNECTION() { if (m_pPrimaryMachineId) { FreeMemory(m_pPrimaryMachineId); } if (m_pSecondaryMachineId) { FreeMemory(m_pSecondaryMachineId); } if (m_pszUserName) { FreeMemory(m_pszUserName); } if (m_pszPassword) { FreeMemory(m_pszPassword); } if (m_pAssembleBuffer) { FreeMemory(m_pAssembleBuffer); } if (m_pCommandHeader) { FreeMemory(m_pCommandHeader); } if (m_pszFileName) { FreeMemory(m_pszFileName); } if (m_pszLongFileName) { FreeMemory(m_pszLongFileName); } if (m_pwszFileName) { FreeMemory(m_pwszFileName); } } //------------------------------------------------------------------------ // CSCEP_CONNECTION::operator new() // //------------------------------------------------------------------------ void *CSCEP_CONNECTION::operator new( IN size_t Size ) { void *pObj = AllocateMemory(Size); #ifdef DBG_MEM if (pObj) { InterlockedIncrement(&g_lCScepConnectionCount); } #endif return pObj; } //------------------------------------------------------------------------ // CSCEP_CONNECTION::operator delete() // //------------------------------------------------------------------------ void CSCEP_CONNECTION::operator delete( IN void *pObj, IN size_t Size ) { if (pObj) { DWORD dwStatus = FreeMemory(pObj); #ifdef DBG_MEM if (dwStatus) { DbgPrint("IrXfer: IrTran-P: CSCEP_CONNECTION::delete: FreeMemory() Failed: %d\n"dwStatus); } InterlockedDecrement(&g_lCScepConnectionCount); if (g_lCScepConnectionCount < 0) { DbgPrint("IrXfer: IrTran-P: CSCEP_CONNECTION::delete: Count: %d\n", g_lCScepConnectionCount); } #endif } } //-------------------------------------------------------------------- // CSCEP_CONNECTION::AssemblePdu() // // Take in bits of data as its read in. When a complete SCEP PDU has // been read and assembled return it. // // pInputData - This is the data that just came in. // // dwInputDataSize - Size in bytes of pInputData. // // ppPdu - Returns a complete SCEP PDU when this function // returns NO_ERROR, otherwise set to 0. // // pdwPduSize - Size of the returned PDU. // // Return values: // // NO_ERROR - A new SCEP PDU is complete and ready. // ERROR_CONTINUE - Data read so far is Ok, still waiting for more. // ERROR_SCEP_INVALID_PROTOCOL // ERROR_IRTRANP_OUT_OF_MEMORY // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::AssemblePdu( IN void *pInputData, IN DWORD dwInputDataSize, OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = ERROR_CONTINUE; UCHAR *pEnd; if (dwInputDataSize > MAX_PDU_SIZE) return ERROR_SCEP_INVALID_PROTOCOL; *ppPdu = 0; *pdwPduSize = 0; if (dwInputDataSize > 0) { if (!m_pAssembleBuffer) { m_dwMaxAssembleBufferSize = 2*MAX_PDU_SIZE; m_pAssembleBuffer = (UCHAR*)AllocateMemory(m_dwMaxAssembleBufferSize); if (!m_pAssembleBuffer) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memcpy(m_pAssembleBuffer,pInputData,dwInputDataSize); m_dwAssembleBufferSize = dwInputDataSize; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: Start: %d\n",m_dwAssembleBufferSize); #endif } else { if (m_dwAssembleBufferSize+dwInputDataSize >= m_dwMaxAssembleBufferSize) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::AssemblePdu(): Buffer Overrun!\n"); #endif return ERROR_SCEP_INVALID_PROTOCOL; } pEnd = &(m_pAssembleBuffer[m_dwAssembleBufferSize]); memcpy(pEnd,pInputData,dwInputDataSize); m_dwAssembleBufferSize += dwInputDataSize; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: Add: %d NewSize: %d\n", dwInputDataSize,m_dwAssembleBufferSize); #endif } } // Check to see if enough data has come in for a complete PDU. dwStatus = CheckPdu(ppPdu,pdwPduSize); return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CheckPdu() // // Run through the "current" PDU and see if its complete. If its // not yet complete, return ERROR_CONTINUE. If it is complete then // return NO_ERROR. // // Return values: // // NO_ERROR - The current SCEP PDU is complete and ready. // ERROR_CONTINUE - Data read so far is Ok, still waiting for more. // ERROR_SCEP_INVALID_PROTOCOL // ERROR_IRTRANP_OUT_OF_MEMORY // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::CheckPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus; DWORD dwSize; SCEP_NEGOTIATION *pInfNegotiation; if (m_dwAssembleBufferSize < 2) { return ERROR_CONTINUE; } switch ( ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType ) { case MSG_TYPE_CONNECT_REQ: dwStatus = CheckConnectPdu(ppPdu,pdwPduSize); break; case MSG_TYPE_CONNECT_RESP: dwStatus = CheckConnectRespPdu(ppPdu,pdwPduSize); break; case MSG_TYPE_DATA: dwStatus = CheckDataPdu(ppPdu,pdwPduSize); break; case MSG_TYPE_DISCONNECT: dwStatus = CheckDisconnectPdu(ppPdu,pdwPduSize); break; default: #ifdef DBG_ERROR DbgPrint("CheckPdu(): Invalid Msgtype: %d\n", ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType ); #endif dwStatus = ERROR_SCEP_INVALID_PROTOCOL; break; } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CheckConnectPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::CheckConnectPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus; DWORD dwSize; SCEP_VERSION *pInfVersion; SCEP_NEGOTIATION *pInfNegotiation; SCEP_EXTEND *pInfExtend; ASSERT( ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType == MSG_TYPE_CONNECT_REQ); if (m_dwAssembleBufferSize < MIN_PDU_SIZE_CONNECT) { return ERROR_CONTINUE; } if (m_dwAssembleBufferSize > MAX_PDU_SIZE_CONNECT) { return ERROR_SCEP_INVALID_PROTOCOL; } pInfVersion = (SCEP_VERSION*)(((SCEP_HEADER*)m_pAssembleBuffer)->Rest); pInfNegotiation = (SCEP_NEGOTIATION*)( sizeof(SCEP_VERSION) + (char*)pInfVersion ); pInfExtend = (SCEP_EXTEND*)( FIELD_OFFSET(SCEP_NEGOTIATION,InfVersion) + pInfNegotiation->Length + (char*)pInfNegotiation ); // Check to see if we have a complete connect PDU size-wise: dwSize = 10 + pInfNegotiation->Length; if (m_dwAssembleBufferSize == dwSize) { // Have a complete PDU. dwStatus = NO_ERROR; } else if (m_dwAssembleBufferSize < dwSize) { // Need to wait for more data to arrive dwStatus = ERROR_CONTINUE; } else { // Too much data... dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if (dwStatus == NO_ERROR) { // Check to make sure the contents of the PDU "look" Ok: if ( (pInfVersion->InfType != INF_TYPE_VERSION) || (pInfVersion->Version != PROTOCOL_VERSION) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if ( (pInfNegotiation->InfType != INF_TYPE_NEGOTIATION) || (pInfNegotiation->InfVersion < INF_VERSION) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if ( (pInfExtend->InfType != INF_TYPE_EXTEND) || (pInfExtend->Length != (sizeof(pInfExtend->Parameter1) +sizeof(pInfExtend->Parameter2))) || (pInfExtend->Parameter1 != 0) || (pInfExtend->Parameter2 != 0) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } if (dwStatus == NO_ERROR) { *ppPdu = NewPdu(); if (!*ppPdu) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::CheckConnectPdu(): Out of memory.\n"); #endif dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { *pdwPduSize = m_dwAssembleBufferSize; memcpy(*ppPdu,m_pAssembleBuffer,m_dwAssembleBufferSize); m_dwAssembleBufferSize = 0; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: PDU: %d Reset: %d\n", *pdwPduSize, m_dwAssembleBufferSize ); #endif } } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CheckConnectRespPdu() CLIENT // // A connect response from the IrTran-P server is either a ACK or // NACK PDU. If we get here then it's an ACK. We'll make sure the // entire PDU is here and that it is formatted correctly. There is // a specific message type for ACK PDUs, the NACK is just a special // case of MSG_TYPE_DATA and is handled elsewere (CheckDataPdu()). // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::CheckConnectRespPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus; DWORD dwSize; SCEP_HEADER *pHeader; SCEP_NEGOTIATION *pInfNegotiation; ASSERT( ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType == MSG_TYPE_CONNECT_RESP); if (m_dwAssembleBufferSize < MIN_PDU_SIZE_CONNECT_RESP) { return ERROR_CONTINUE; } if (m_dwAssembleBufferSize > MAX_PDU_SIZE_CONNECT_RESP) { return ERROR_SCEP_INVALID_PROTOCOL; } pHeader = (SCEP_HEADER*)m_pAssembleBuffer; pInfNegotiation = (SCEP_NEGOTIATION*)(pHeader->Rest); // Check to see if we have a complete connect PDU size-wise: dwSize = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_NEGOTIATION,InfVersion) + pInfNegotiation->Length; if (m_dwAssembleBufferSize == dwSize) { // Have a complete PDU. dwStatus = NO_ERROR; } else if (m_dwAssembleBufferSize < dwSize) { // Need to wait for more data to arrive dwStatus = ERROR_CONTINUE; } else { // Too much data... dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if (dwStatus == NO_ERROR) { // Check to make sure the contents of the PDU "look" Ok: if ( (pInfNegotiation->InfType != INF_TYPE_NEGOTIATION) || (pInfNegotiation->InfVersion < INF_VERSION) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } if (dwStatus == NO_ERROR) { *ppPdu = NewPdu(); if (!*ppPdu) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::CheckConnectRespPdu(): Out of memory.\n"); #endif dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { *pdwPduSize = m_dwAssembleBufferSize; memcpy(*ppPdu,m_pAssembleBuffer,m_dwAssembleBufferSize); m_dwAssembleBufferSize = 0; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: PDU: %d Reset: %d\n", *pdwPduSize, m_dwAssembleBufferSize ); #endif } } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CheckDisconnectPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::CheckDisconnectPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwSize; SCEP_DISCONNECT *pDisconnect; ASSERT( ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType == MSG_TYPE_DISCONNECT); if (m_dwAssembleBufferSize < MIN_PDU_SIZE_DISCONNECT) { return ERROR_CONTINUE; } pDisconnect = (SCEP_DISCONNECT*)(((SCEP_HEADER*)m_pAssembleBuffer)->Rest); // Check to make sure the contents of the PDU "look" Ok: if (pDisconnect->InfType != INF_TYPE_REASON) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if (pDisconnect->Length1 != sizeof(USHORT)) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } if (dwStatus == NO_ERROR) { *ppPdu = NewPdu(); if (!*ppPdu) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::CheckDisonnectPdu(): Out of memory.\n"); #endif dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { *pdwPduSize = sizeof(SCEP_HEADER) + 2 + pDisconnect->Length1; memcpy(*ppPdu,m_pAssembleBuffer,*pdwPduSize); m_dwAssembleBufferSize -= *pdwPduSize; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: PDU: %d Reset: %d\n", *pdwPduSize, m_dwAssembleBufferSize ); #endif } } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::CheckDataPdu() // // The goal here is to check to see if we have a complete formatted // PDU, if yes the return NO_ERROR, if the PDU looks ok so far, but // isn't complete (we need to read more), then return ERROR_CONTINUE. // // Also if this is a little-endian machine, byteswap the header // fields accordingly. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::CheckDataPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus; DWORD dwExpectedPduSize; UCHAR *pEnd; SCEP_REQ_HEADER_SHORT *pReqHeaderShort; SCEP_REQ_HEADER_LONG *pReqHeaderLong; ASSERT( ((SCEP_HEADER*)m_pAssembleBuffer)->MsgType == MSG_TYPE_DATA); if (m_dwAssembleBufferSize < MIN_PDU_SIZE_DATA) { return ERROR_CONTINUE; } // Get the length out of the PDU and see if we have a // complete PDU: pReqHeaderShort = (SCEP_REQ_HEADER_SHORT*) (((SCEP_HEADER*)m_pAssembleBuffer)->Rest); if (pReqHeaderShort->Length1 == USE_LENGTH2) { // We have a long PDU: pReqHeaderLong = (SCEP_REQ_HEADER_LONG*)(pReqHeaderShort); #ifdef LITTLE_ENDIAN if (!m_fDidByteSwap) { ByteSwapReqHeaderLong(pReqHeaderLong); m_fDidByteSwap = TRUE; } #endif dwExpectedPduSize = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_LONG,InfVersion) + pReqHeaderLong->Length2; } else { // We have a short PDU: #ifdef LITTLE_ENDIAN if (!m_fDidByteSwap) { ByteSwapReqHeaderShort(pReqHeaderShort); m_fDidByteSwap = TRUE; } #endif dwExpectedPduSize = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT,InfVersion) + pReqHeaderShort->Length1; } // Ok, see if we have a complete PDU: if (m_dwAssembleBufferSize == dwExpectedPduSize) { *ppPdu = NewPdu(); if (!*ppPdu) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::CheckDataPdu(): Out of memory.\n"); #endif dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { *pdwPduSize = dwExpectedPduSize; memcpy(*ppPdu,m_pAssembleBuffer,dwExpectedPduSize); m_dwAssembleBufferSize = 0; m_fDidByteSwap = FALSE; #ifdef DBG_ASSEMBLE DbgPrint("Assemble: PDU: %d Reset: %d\n", *pdwPduSize, m_dwAssembleBufferSize ); #endif dwStatus = NO_ERROR; } } else if (m_dwAssembleBufferSize > dwExpectedPduSize) { *ppPdu = NewPdu(); if (!*ppPdu) { #ifdef DBG_ERROR DbgPrint("CSCEP_CONNECTION::CheckDataPdu(): Out of memory.\n"); #endif dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { *pdwPduSize = dwExpectedPduSize; memcpy(*ppPdu,m_pAssembleBuffer,dwExpectedPduSize); pEnd = dwExpectedPduSize + (UCHAR*)m_pAssembleBuffer; m_dwAssembleBufferSize -= dwExpectedPduSize; m_fDidByteSwap = FALSE; // // move the data remaining to the front of the buffer // memmove(m_pAssembleBuffer,pEnd,m_dwAssembleBufferSize); #ifdef DBG_ASSEMBLE DbgPrint("Assemble: PDU: %d Reset: %d\n", *pdwPduSize, m_dwAssembleBufferSize ); #endif dwStatus = NO_ERROR; } } else { dwStatus = ERROR_CONTINUE; } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseConnectPdu() // // AssemblePDU() already did basic integrity checking of the PDU // (via CheckConnectPdu()), so at this point we'll assume everything // is Ok. // // NOTE: The Connect PDU is limited to 256 bytes in total length, // so it will never be fragmented. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParseConnectPdu( IN SCEP_HEADER *pPdu, IN DWORD dwInputDataSize ) { DWORD dwStatus; DWORD dwLength; if (dwInputDataSize > MAX_PDU_SIZE_CONNECT) { return ERROR_SCEP_INVALID_PROTOCOL; } SCEP_VERSION *pInfVersion; SCEP_NEGOTIATION *pInfNegotiation; SCEP_EXTEND *pInfExtend; pInfVersion = (SCEP_VERSION*)pPdu->Rest; pInfNegotiation = (SCEP_NEGOTIATION*)( sizeof(SCEP_VERSION) + (char*)pInfVersion ); pInfExtend = (SCEP_EXTEND*)( FIELD_OFFSET(SCEP_NEGOTIATION,InfVersion) + pInfNegotiation->Length + (char*)pInfNegotiation ); // m_CFlag = pInfNegotiation->CFlag; m_pSecondaryMachineId = (UCHAR*)AllocateMemory(MACHINE_ID_SIZE); if (!m_pSecondaryMachineId) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memcpy( m_pSecondaryMachineId, pInfNegotiation->SecondaryMachineId, MACHINE_ID_SIZE ); m_pPrimaryMachineId = (UCHAR*)AllocateMemory(MACHINE_ID_SIZE); if (!m_pPrimaryMachineId) { FreeMemory(m_pSecondaryMachineId); return ERROR_IRTRANP_OUT_OF_MEMORY; } memcpy( m_pPrimaryMachineId, pInfNegotiation->PrimaryMachineId, MACHINE_ID_SIZE ); // NOTE: The size of the negotiaion "text" is 18 bytes less than // the length in the SCEP_NEGOTIATION record: dwLength = pInfNegotiation->Length - ( sizeof(pInfNegotiation->InfVersion) + sizeof(pInfNegotiation->CFlag) + sizeof(pInfNegotiation->SecondaryMachineId) + sizeof(pInfNegotiation->PrimaryMachineId)); dwStatus = ParseNegotiation( pInfNegotiation->Negotiation, dwLength ); return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseConnectRespPdu() // // AssemblePDU() already did basic integrity checking of the PDU // (via CheckConnectRespPdu()), so at this point we'll assume // everything is Ok. // // NOTE: The Connect Response PDU is limited to 255 bytes in total // length, so it will never be fragmented. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParseConnectRespPdu( IN SCEP_HEADER *pPdu, IN DWORD dwPduSize ) { DWORD dwStatus; DWORD dwLength; SCEP_NEGOTIATION *pInfNegotiation; if (dwPduSize > MAX_PDU_SIZE_CONNECT) { return ERROR_SCEP_INVALID_PROTOCOL; } pInfNegotiation = (SCEP_NEGOTIATION*)( sizeof(SCEP_HEADER) + (char*)pPdu ); // This is the CFlag sent by the other machine. m_CFlag = pInfNegotiation->CFlag; m_pSecondaryMachineId = (UCHAR*)AllocateMemory(MACHINE_ID_SIZE); if (!m_pSecondaryMachineId) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memcpy( m_pSecondaryMachineId, pInfNegotiation->SecondaryMachineId, MACHINE_ID_SIZE ); m_pPrimaryMachineId = (UCHAR*)AllocateMemory(MACHINE_ID_SIZE); if (!m_pPrimaryMachineId) { FreeMemory(m_pSecondaryMachineId); return ERROR_IRTRANP_OUT_OF_MEMORY; } memcpy( m_pPrimaryMachineId, pInfNegotiation->PrimaryMachineId, MACHINE_ID_SIZE ); // NOTE: The size of the negotiaion "text" is 18 bytes less than // the length in the SCEP_NEGOTIATION record: dwLength = pInfNegotiation->Length - ( sizeof(pInfNegotiation->InfVersion) + sizeof(pInfNegotiation->CFlag) + sizeof(pInfNegotiation->SecondaryMachineId) + sizeof(pInfNegotiation->PrimaryMachineId)); dwStatus = ParseNegotiation( pInfNegotiation->Negotiation, dwLength ); return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseNegotiation() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParseNegotiation( IN UCHAR *pNegotiation, IN DWORD dwNegotiationSize ) { DWORD dwStatus = NO_ERROR; UCHAR *pNext = pNegotiation; DWORD dwSize = dwNegotiationSize; if (dwNegotiationSize <= 1) { return NO_ERROR; } if (*(pNext++) < NEGOTIATION_VERSION) { return ERROR_SCEP_INVALID_PROTOCOL; } dwSize--; while (pNext=ParseAttribute(pNext, &dwSize, &dwStatus)) { if (dwStatus != NO_ERROR) { break; } } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseAttribute() // // Attributes are of the form: // // Attr <- AttrName Colon AttrValue CrLf // // AttrName <- Two byte attribute name. // // Colon <- ':' // // AttrValue <- Character string (bytes > 0x1f and < 0x8f). // // CrLf <- 0x0d 0x0a // //-------------------------------------------------------------------- UCHAR *CSCEP_CONNECTION::ParseAttribute( IN UCHAR *pAttributes, IN DWORD *pdwAttributeSize, OUT DWORD *pdwStatus ) { int iAttribute; int iPduSize; ATTRIBUTE_TOKEN *pToken1 = 0; ATTRIBUTE_TOKEN *pToken2 = 0; ATTRIBUTE_TOKEN *pToken3 = 0; ATTRIBUTE_TOKEN *pToken4 = 0; *pdwStatus = NO_ERROR; if ( (pToken1=NextToken(ATTRIBUTE_NAME,&pAttributes,pdwAttributeSize)) && (IsAttributeName(pToken1,&iAttribute)) && (pToken2=NextToken(ATTRIBUTE_COLON,&pAttributes,pdwAttributeSize)) && (pToken3=NextToken(ATTRIBUTE_VALUE,&pAttributes,pdwAttributeSize)) && (pToken4=NextToken(ATTRIBUTE_CRLF,&pAttributes,pdwAttributeSize)) ) { if (iAttribute == ATTR_PDU_SIZE) { iPduSize = pToken3->pChars[0] - ONE; if ((pToken3->dwSize == 1)&&(iPduSize >= 1)&&(iPduSize <= 4)) { m_dwPduSendSize = g_adwPduSizes[iPduSize]; #ifdef DBG_IO DbgPrint("ParseAttribute(): PduSendSize: %d\n",m_dwPduSendSize); #endif } } else if (iAttribute == ATTR_PRODUCT_ID) { m_pszProductId = NewTokenString(pToken3,pdwStatus); if (!m_pszProductId) { pAttributes = 0; #ifdef DBG_IO DbgPrint("ParseAttribute(): Product: %s\n",m_pszProductId); #endif } } else if (iAttribute == ATTR_USER_NAME) { m_pszUserName = NewTokenString(pToken3,pdwStatus); if (!m_pszUserName) { pAttributes = 0; } } else if (iAttribute == ATTR_PASSWORD) { m_pszPassword = NewTokenString(pToken3,pdwStatus); if (!m_pszPassword) { pAttributes = 0; } } } else { if (*pdwAttributeSize > 0) { *pdwStatus = ERROR_SCEP_INVALID_PROTOCOL; } pAttributes = 0; } if (pToken1) FreeMemory(pToken1); if (pToken2) FreeMemory(pToken2); if (pToken3) FreeMemory(pToken3); if (pToken4) FreeMemory(pToken4); return pAttributes; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseDataPdu() // // AssemblePDU() already did basic integrity checking of the PDU // (via CheckConnectPdu()), so at this point we'll assume everything // is Ok. // // NOTE: The Data PDU is limited to m_dwPduReceiveSize bytes in total // length, if data is longer then you will get the fragmented versions // of the Data PDU. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParseDataPdu( IN SCEP_HEADER *pPdu, IN DWORD dwPduSize, OUT COMMAND_HEADER **ppCommand, OUT UCHAR **ppUserData, OUT DWORD *pdwUserDataSize ) { DWORD dwStatus = NO_ERROR; DWORD dwLengthOffset1; DWORD dwLengthOffset3; // There are four cases of Data PDUs, single (unfragmented) // "short" and "long" PDUs, and fragmented "short" and // "long" PDUs: SCEP_REQ_HEADER_SHORT *pReqHeaderShort; SCEP_REQ_HEADER_LONG *pReqHeaderLong; SCEP_REQ_HEADER_SHORT_FRAG *pReqHeaderShortFrag; SCEP_REQ_HEADER_LONG_FRAG *pReqHeaderLongFrag; *ppCommand = 0; // Make sure the packet length makes sense... if (dwPduSize > m_dwPduReceiveSize) { return ERROR_SCEP_INVALID_PROTOCOL; } pReqHeaderShort = (SCEP_REQ_HEADER_SHORT*)(pPdu->Rest); if (pReqHeaderShort->InfType != INF_TYPE_USER_DATA) { return ERROR_SCEP_INVALID_PROTOCOL; } // // See if we have a short or long PDU: // if (pReqHeaderShort->Length1 != USE_LENGTH2) { // This is a short PDU (use Length1). m_DFlag = pReqHeaderShort->DFlag; if ( (pReqHeaderShort->DFlag == DFLAG_SINGLE_PDU) || (pReqHeaderShort->DFlag == DFLAG_CONNECT_REJECT)) { // // This is a short unfragmented PDU. // // Make sure that a command header is present: if (pReqHeaderShort->Length1 > 4) { *ppCommand = (COMMAND_HEADER*)(pReqHeaderShort->CommandHeader); m_SrcPid = (*ppCommand)->SrcPid; m_DestPid = (*ppCommand)->DestPid; m_dwCommandId = (*ppCommand)->CommandId; } else { *ppCommand = 0; } *ppUserData = COMMAND_HEADER_SIZE + pReqHeaderShort->CommandHeader; *pdwUserDataSize = pReqHeaderShort->Length3 - COMMAND_HEADER_SIZE; m_Fragmented = FALSE; m_dwSequenceNo = 0; m_dwRestNo = 0; // In this case, there are two different lengths // in the PDU that must add up to dwPduSize... // // Note: Not currently testing Length1 for consistency... // dwLengthOffset3 = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT,CommandHeader); if (dwPduSize != dwLengthOffset3+pReqHeaderShort->Length3) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else if (pReqHeaderShort->DFlag == DFLAG_FIRST_FRAGMENT) { // // This is a short fragmented PDU, and is the first // fragment, so it will contain a COMMAND_HEADER. // // In practice, this should probably never show up... pReqHeaderShortFrag = (SCEP_REQ_HEADER_SHORT_FRAG*)pReqHeaderShort; // The command header is present only on the first fragment // of a multi-fragment PDU: if (pReqHeaderShortFrag->SequenceNo == 0) { *ppCommand = (COMMAND_HEADER*)(pReqHeaderShortFrag->CommandHeader); m_SrcPid = (*ppCommand)->SrcPid; m_DestPid = (*ppCommand)->DestPid; m_dwCommandId = (*ppCommand)->CommandId; } else { *ppCommand = 0; } *ppUserData = COMMAND_HEADER_SIZE + pReqHeaderShortFrag->CommandHeader; *pdwUserDataSize = pReqHeaderShortFrag->Length3 - COMMAND_HEADER_SIZE; m_Fragmented = TRUE; m_dwSequenceNo = pReqHeaderShortFrag->SequenceNo; m_dwRestNo = pReqHeaderShortFrag->RestNo; // Check the two length fields for consistency: dwLengthOffset1 = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT_FRAG,InfVersion); dwLengthOffset3 = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT_FRAG,SequenceNo); if ( (dwPduSize != dwLengthOffset1+pReqHeaderShortFrag->Length1) || (dwPduSize != dwLengthOffset3+pReqHeaderShortFrag->Length3) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else if ( (pReqHeaderShort->DFlag == DFLAG_FRAGMENT) || (pReqHeaderShort->DFlag == DFLAG_LAST_FRAGMENT)) { // // This is a short fragmented PDU. // // The 2nd through last fragmented PDUs don't contain a // COMMAND_HEADER, just data after Length3. pReqHeaderShortFrag = (SCEP_REQ_HEADER_SHORT_FRAG*)pReqHeaderShort; // The command header is present only on the first fragment // of a multi-fragment PDU: if (pReqHeaderShortFrag->SequenceNo == 0) { *ppCommand = (COMMAND_HEADER*)(pReqHeaderShortFrag->CommandHeader); m_SrcPid = (*ppCommand)->SrcPid; m_DestPid = (*ppCommand)->DestPid; m_dwCommandId = (*ppCommand)->CommandId; } else { *ppCommand = 0; } *ppUserData = pReqHeaderShortFrag->CommandHeader; *pdwUserDataSize = pReqHeaderShortFrag->Length3; m_Fragmented = TRUE; m_dwSequenceNo = pReqHeaderShortFrag->SequenceNo; m_dwRestNo = pReqHeaderShortFrag->RestNo; // Check the two length fields for consistency: dwLengthOffset1 = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT_FRAG,InfVersion); dwLengthOffset3 = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_SHORT_FRAG,SequenceNo); if ( (dwPduSize != dwLengthOffset1+pReqHeaderShortFrag->Length1) || (dwPduSize != dwLengthOffset3+pReqHeaderShortFrag->Length3) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else { // Undefined DFlag, we've got a problem... dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else { // We have a long PDU. pReqHeaderLong = (SCEP_REQ_HEADER_LONG*)pReqHeaderShort; m_DFlag = pReqHeaderLong->DFlag; if ( (pReqHeaderLong->DFlag == DFLAG_SINGLE_PDU) || (pReqHeaderLong->DFlag == DFLAG_CONNECT_REJECT)) { // // This is a long unfragmented PDU. // *ppCommand = (COMMAND_HEADER*)(pReqHeaderLong->CommandHeader); *ppUserData = COMMAND_HEADER_SIZE + pReqHeaderLong->CommandHeader; *pdwUserDataSize = pReqHeaderLong->Length3 - COMMAND_HEADER_SIZE; m_Fragmented = FALSE; m_dwSequenceNo = 0; m_dwRestNo = 0; m_SrcPid = (*ppCommand)->SrcPid; m_DestPid = (*ppCommand)->DestPid; m_dwCommandId = (*ppCommand)->CommandId; // In this case, there are two different lengths // in the PDU that must add up to dwPduSize... if ( (dwPduSize != 6UL+pReqHeaderLong->Length2) || (dwPduSize != 10UL+pReqHeaderLong->Length3)) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else if (pReqHeaderLong->DFlag == DFLAG_FIRST_FRAGMENT) { // // This is the first fragment of a long fragmented PDU. // pReqHeaderLongFrag = (SCEP_REQ_HEADER_LONG_FRAG*)pReqHeaderLong; m_pCommandHeader = (COMMAND_HEADER*)AllocateMemory(sizeof(COMMAND_HEADER)); if (!m_pCommandHeader) { dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY; } else { memcpy(m_pCommandHeader, pReqHeaderLongFrag->CommandHeader, COMMAND_HEADER_SIZE ); *ppCommand = m_pCommandHeader; } *ppUserData = COMMAND_HEADER_SIZE + pReqHeaderLongFrag->CommandHeader; *pdwUserDataSize = pReqHeaderLongFrag->Length3 - COMMAND_HEADER_SIZE; m_Fragmented = TRUE; m_dwSequenceNo = pReqHeaderLongFrag->SequenceNo; m_dwRestNo = pReqHeaderLongFrag->RestNo; if (*ppCommand) { m_dwCommandId = (*ppCommand)->CommandId; } else { m_dwCommandId = 0; } // Check the two length fields for consistency: if ( (dwPduSize != (DWORD)6+pReqHeaderLongFrag->Length2) || (dwPduSize != (DWORD)18+pReqHeaderLongFrag->Length3) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else if ( (pReqHeaderLong->DFlag == DFLAG_FRAGMENT) || (pReqHeaderLong->DFlag == DFLAG_LAST_FRAGMENT) ) { // // This is the second through last fragment of a long // fragmented PDU. // // In this case the PDU doesn't contain a command // header, just more user data... // pReqHeaderLongFrag = (SCEP_REQ_HEADER_LONG_FRAG*)pReqHeaderLong; *ppCommand = m_pCommandHeader; *ppUserData = (UCHAR*)(pReqHeaderLongFrag->CommandHeader); *pdwUserDataSize = pReqHeaderLongFrag->Length3; m_Fragmented = TRUE; m_dwSequenceNo = pReqHeaderLongFrag->SequenceNo; m_dwRestNo = pReqHeaderLongFrag->RestNo; m_dwCommandId = (*ppCommand)->CommandId; // Check the two length fields for consistency: if ( (dwPduSize != (DWORD)6+pReqHeaderLongFrag->Length2) || (dwPduSize != (DWORD)18+pReqHeaderLongFrag->Length3) ) { dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } else { // Undefined DFlag, we've got a problem... dwStatus = ERROR_SCEP_INVALID_PROTOCOL; } } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParseDisconnectPdu() // // NOTE: In practice, reason codes should always be 2 bytes for // SCEP version 1.0. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParseDisconnectPdu( IN SCEP_HEADER *pPdu, IN DWORD dwPduSize ) { DWORD dwStatus; SCEP_DISCONNECT *pDisconnect = (SCEP_DISCONNECT*)(pPdu->Rest); if ( (pDisconnect->InfType != INF_TYPE_REASON) || (pDisconnect->Length1 != sizeof(USHORT)) || (pDisconnect->ReasonCode == 0) ) { dwStatus = ERROR_SCEP_UNSPECIFIED_DISCONNECT; } else if (pDisconnect->ReasonCode == 1) { dwStatus = ERROR_SCEP_USER_DISCONNECT; } else if (pDisconnect->ReasonCode == 2) { dwStatus = ERROR_SCEP_PROVIDER_DISCONNECT; } else { dwStatus = ERROR_SCEP_UNSPECIFIED_DISCONNECT; } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::ParsePdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::ParsePdu( IN SCEP_HEADER *pPdu, IN DWORD dwPduSize, OUT COMMAND_HEADER **ppCommandHeader, OUT UCHAR **ppUserData, OUT DWORD *pdwUserDataSize ) { DWORD dwStatus = NO_ERROR; *ppCommandHeader = 0; *ppUserData = 0; *pdwUserDataSize = 0; switch (pPdu->MsgType) { case MSG_TYPE_CONNECT_REQ: dwStatus = ParseConnectPdu( pPdu, dwPduSize ); break; case MSG_TYPE_CONNECT_RESP: dwStatus = ParseConnectRespPdu( pPdu, dwPduSize ); break; case MSG_TYPE_DATA: dwStatus = ParseDataPdu( pPdu, dwPduSize, ppCommandHeader, ppUserData, pdwUserDataSize ); break; case MSG_TYPE_DISCONNECT: dwStatus = ParseDisconnectPdu( pPdu, dwPduSize ); break; } return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildConnectPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildConnectPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; SCEP_VERSION *pVersion; SCEP_NEGOTIATION *pNegotiation; SCEP_EXTEND *pExtend; *ppPdu = 0; *pdwPduSize = 0; // Note that the PDU size doesn't include a trailing zero, as you // would think by lookin at "sizeof(CONNECT_PDU_ATTRIBUTES)" below. // The extra byte is for the first byte of the Negotiation string // (which is the Negotiation version), so the eqn below is +1-1... dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_VERSION) + sizeof(SCEP_NEGOTIATION) + sizeof(CONNECT_PDU_ATTRIBUTES) + sizeof(SCEP_EXTEND); pHeader = NewPdu(); // Defaulting dwPduSize to MAX_PDU_SIZE if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE since dwPduSize is defauled above. pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_CONNECT_REQ; pVersion = (SCEP_VERSION*)(pHeader->Rest); pVersion->InfType = INF_TYPE_VERSION; pVersion->Version = PROTOCOL_VERSION; pNegotiation = (SCEP_NEGOTIATION*)((char*)pVersion + sizeof(SCEP_VERSION)); pNegotiation->InfType = INF_TYPE_NEGOTIATION; pNegotiation->Length = 18 + sizeof(CONNECT_PDU_ATTRIBUTES); pNegotiation->InfVersion = INF_VERSION; pNegotiation->CFlag = CFLAG_ISSUE_OR_EXECUTE; // pNegotiation->SecondaryMachineId -- Leave set to zeros... // pNegotiation->PrimaryMachineId -- Leave set to zeros... pNegotiation->Negotiation[0] = NEGOTIATION_VERSION; memcpy( &(pNegotiation->Negotiation[1]), CONNECT_PDU_ATTRIBUTES, sizeof(CONNECT_PDU_ATTRIBUTES)-1 ); // No Trailing zero... pExtend = (SCEP_EXTEND*)( (char*)pHeader + dwPduSize - sizeof(SCEP_EXTEND)); pExtend->InfType = INF_TYPE_EXTEND; pExtend->Length = 2; pExtend->Parameter1 = 0; pExtend->Parameter2 = 0; *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildConnectRespPdu() // // This is the response PDU for a connection request from a camera. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildConnectRespPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; SCEP_NEGOTIATION *pNegotiation; *ppPdu = 0; *pdwPduSize = 0; // Note that the PDU size doesn't include a trailing zero, as you // would think by lookin at "sizeof(RESPONSE_PDU_ATTRIBUTES)" below, // the extra byte in for the first byte of the Negotiation string // which is the Negotiation version, so the eqn below is +1-1... dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_NEGOTIATION) + sizeof(RESPONSE_PDU_ATTRIBUTES); pHeader = NewPdu(); if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE is default arg in NewPdu(). pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_CONNECT_RESP; pNegotiation = (SCEP_NEGOTIATION*)(pHeader->Rest); pNegotiation->InfType = INF_TYPE_NEGOTIATION; pNegotiation->Length = 18 + sizeof(RESPONSE_PDU_ATTRIBUTES); pNegotiation->InfVersion = INF_VERSION; pNegotiation->CFlag = CFLAG_ISSUE_OR_EXECUTE; memcpy( pNegotiation->SecondaryMachineId, m_pPrimaryMachineId, MACHINE_ID_SIZE ); memcpy( pNegotiation->PrimaryMachineId, m_pSecondaryMachineId, MACHINE_ID_SIZE ); pNegotiation->Negotiation[0] = NEGOTIATION_VERSION; memcpy( &(pNegotiation->Negotiation[1]), RESPONSE_PDU_ATTRIBUTES, sizeof(RESPONSE_PDU_ATTRIBUTES)-1 ); // No Trailing zero... *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildConnectNackPdu() // // This is the response PDU for a connection request from a camera // when we want to reject the connection request. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildConnectNackPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_SHORT *pReqHeader; *ppPdu = 0; *pdwPduSize = 0; // A short PDU, there is now command header, so Length3 is zero... dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_REQ_HEADER_SHORT) - sizeof(COMMAND_HEADER); pHeader = NewPdu(); if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_CONNECT_REQ; pReqHeader = (SCEP_REQ_HEADER_SHORT*)(pHeader->Rest); pReqHeader->InfType = INF_TYPE_USER_DATA; pReqHeader->Length1 = sizeof(pReqHeader->InfVersion) + sizeof(pReqHeader->DFlag) + sizeof(pReqHeader->Length3); pReqHeader->InfVersion = INF_VERSION; pReqHeader->DFlag = DFLAG_CONNECT_REJECT; pReqHeader->Length3 = 0; *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildAbortPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildAbortPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; COMMAND_HEADER *pCommandHeader; SCEP_REQ_HEADER_SHORT *pReqHeader; *ppPdu = 0; *pdwPduSize = 0; dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_REQ_HEADER_SHORT); pHeader = NewPdu(); if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE is default arg for NewPdu(). pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DATA; pReqHeader = (SCEP_REQ_HEADER_SHORT*)(pHeader->Rest); pReqHeader->InfType = INF_TYPE_USER_DATA; pReqHeader->Length1 = 4 + sizeof(COMMAND_HEADER); pReqHeader->InfVersion = INF_VERSION; pReqHeader->DFlag = DFLAG_SINGLE_PDU; pReqHeader->Length3 = sizeof(COMMAND_HEADER); #ifdef LITTLE_ENDIAN pReqHeader->Length3 = ByteSwapShort(pReqHeader->Length3); #endif pCommandHeader = (COMMAND_HEADER*)(pReqHeader->CommandHeader); pCommandHeader->Marker58h = 0x58; pCommandHeader->PduType = PDU_TYPE_ABORT; pCommandHeader->Length4 = 22; pCommandHeader->DestPid = m_SrcPid; pCommandHeader->SrcPid = m_DestPid; pCommandHeader->CommandId = (USHORT)m_dwCommandId; #ifdef LITTLE_ENDIAN ByteSwapCommandHeader(pCommandHeader); #endif *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildStopPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildStopPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_SHORT *pReqHeader; *ppPdu = 0; *pdwPduSize = 0; dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_REQ_HEADER_SHORT) - sizeof(COMMAND_HEADER); pHeader = NewPdu(); if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE is default arg for NewPdu() above. pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DATA; pReqHeader = (SCEP_REQ_HEADER_SHORT*)(pHeader->Rest); pReqHeader->InfType = INF_TYPE_USER_DATA; pReqHeader->Length1 = 4; pReqHeader->InfVersion = INF_VERSION; pReqHeader->DFlag = DFLAG_INTERRUPT; pReqHeader->Length3 = 0; *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::BuildDisconnectPdu() // //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::BuildDisconnectPdu( IN USHORT ReasonCode, OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; SCEP_HEADER *pHeader; SCEP_DISCONNECT *pDisconnect; *ppPdu = 0; *pdwPduSize = 0; dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_DISCONNECT); pHeader = NewPdu(); if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; } memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE is default arg for NewPdu() above. pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DISCONNECT; pDisconnect = (SCEP_DISCONNECT*)(pHeader->Rest); pDisconnect->InfType = INF_TYPE_REASON; pDisconnect->Length1 = sizeof(pDisconnect->ReasonCode); pDisconnect->ReasonCode = ReasonCode; #ifdef LITTLE_ENDIAN pDisconnect->ReasonCode = ByteSwapShort(pDisconnect->ReasonCode); #endif *ppPdu = pHeader; *pdwPduSize = dwPduSize; return dwStatus; } //-------------------------------------------------------------------- // CSCEP_CONNECTION::SetScepLength() // // Update the length fields in a PDU to reflect the total length // of a PDU. // // WARNING: Currently only supports long fragmented PDUs. //-------------------------------------------------------------------- DWORD CSCEP_CONNECTION::SetScepLength( IN SCEP_HEADER *pPdu, IN DWORD dwTotalPduSize ) { DWORD dwStatus = NO_ERROR; SCEP_REQ_HEADER_LONG_FRAG *pScepHeader; if (dwTotalPduSize > MAX_PDU_SIZE) { dwStatus = ERROR_SCEP_PDU_TOO_LARGE; } else { pScepHeader = (SCEP_REQ_HEADER_LONG_FRAG *)(pPdu->Rest); pScepHeader->Length1 = USE_LENGTH2; pScepHeader->Length2 = (USHORT)dwTotalPduSize - 6; pScepHeader->Length3 = (USHORT)dwTotalPduSize - 18; #ifdef LITTLE_ENDIAN pScepHeader->Length2 = ByteSwapShort(pScepHeader->Length2); pScepHeader->Length3 = ByteSwapShort(pScepHeader->Length3); #endif } return dwStatus; }