|
|
//--------------------------------------------------------------------
// 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;
ASSERT(dwInputDataSize <= MAX_PDU_SIZE);
*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
} 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; memcpy(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; }
|