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

1856 lines
67 KiB

//=============================================================================
// FILE: TransportParser.cpp
//
// Description: DPlay v8 Transport protocol parser
//
//
// Modification History:
//
// Michael Milirud 08/Aug/2000 Created
//=============================================================================
// uncomment to enable full parsing of DPlay Transport layer
//#define PARSE_DPLAY_TRANSPORT
//==================//
// Standard headers //
//==================//
#include <string>
//=====================//
// Proprietary headers //
//=====================//
// Prototypes
#include "TransportParser.hpp"
// Transport protocol header
#include "Frames.h"
typedef UNALIGNED struct dataframe_big DFBIG, *PDFBIG;
typedef UNALIGNED struct sackframe_big8 SFBIG8, *PSFBIG8;
struct dataframe_big
{
BYTE bCommand;
BYTE bControl;
BYTE bSeq;
BYTE bNRcv;
ULONG rgMask[4];
};
struct sackframe_big8
{
BYTE bCommand; // As above
BYTE bExtOpcode; // As above
BYTE bFlags; // Additional flags for sack frame
BYTE bRetry;
BYTE bNSeq; // Since this frame has no sequence number, this is the next Seq we
BYTE bNRcv; // As above
BYTE bReserved1; // We shipped DX8 with bad packing, so these were actually there
BYTE bReserved2; // We shipped DX8 with bad packing, so these were actually there
DWORD tTimestamp; // Local stamp when packet arrived
ULONG rgMask[4];
};
namespace
{
HPROTOCOL g_hTransportProtocol;
typedef __int64 QWORD;
//================//
// DCommand field //-------------------------------------------------------------------------------------------------
//================//
LABELED_BIT g_arr_DCommandBitLabels[] =
{ { 0, "INVALID", "Dataframe" }, // PACKET_COMMAND_DATA
{ 1, "Unreliable", "Reliable" }, // PACKET_COMMAND_RELIABLE
{ 2, "Nonsequenced", "Sequenced" }, // PACKET_COMMAND_SEQUENTIAL
{ 3, "ACK can be delayed", "ACK now" }, // PACKET_COMMAND_POLL
{ 4, "Not the first fragment of the message", "First fragment of the message" }, // PACKET_COMMAND_NEW_MSG
{ 5, "Not the last fragment of the message", "Last fragment of the message" }, // PACKET_COMMAND_END_MSG
{ 6, "User packet", "DirectPlay packet" }, // PACKET_COMMAND_USER_1
{ 7, "Data packet", "Voice packet" } }; // PACKET_COMMAND_USER_2
SET g_LabeledDCommandBitSet = { sizeof(g_arr_DCommandBitLabels) / sizeof(LABELED_BIT), g_arr_DCommandBitLabels };
//===============//
// Control field //--------------------------------------------------------------------------------------------------
//===============//
LABELED_BIT g_arr_ControlBitLabels[] =
{ { 0, "Original (not a retry)", "Retry" }, // PACKET_CONTROL_RETRY
{ 1, "Don't correlate", "Correlate" }, // PACKET_CONTROL_CORRELATE
{ 2, "Not a correlation response", "Correlation response" }, // PACKET_CONTROL_RESPONSE
{ 3, "Not the last packet in the stream", "Last packet in the stream" }, // PACKET_CONTROL_END_STREAM
{ 4, "Low DWORD of the RCVD mask is zero", "Low DWORD of the RCVD mask is nonzero" }, // PACKET_CONTROL_SACK_MASK1
{ 5, "High DWORD of the RCVD mask is zero", "High DWORD of the RCVD mask is nonzero" }, // PACKET_CONTROL_SACK_MASK2
{ 6, "Low DWORD of the DON'T CARE mask is zero", "Low DWORD of the DON'T CARE mask is nonzero" }, // PACKET_CONTROL_SEND_MASK1
{ 7, "High DWORD of the DON'T CARE mask is zero", "High DWORD of the DON'T CARE mask is nonzero" } }; // PACKET_CONTROL_SEND_MASK2
SET g_LabeledControlBitSet = { sizeof(g_arr_ControlBitLabels) / sizeof(LABELED_BIT), g_arr_ControlBitLabels };
//================//
// CCommand field //-------------------------------------------------------------------------------------------------
//================//
LABELED_BIT g_arr_CCommandBitLabels[] =
{ { 0, "Command Frame (1/2)", "INVALID" }, // PACKET_COMMAND_DATA
{ 1, "Unreliable", "Reliable" }, // PACKET_COMMAND_RELIABLE
{ 2, "Nonsequenced", "Sequenced" }, // PACKET_COMMAND_SEQUENTIAL
{ 3, "ACK can be delayed", "ACK now" }, // PACKET_COMMAND_POLL
{ 4, "RESERVED", "RESERVED" },
{ 5, "RESERVED", "RESERVED" },
{ 6, "RESERVED", "RESERVED" },
{ 7, "INVALID", "Command Frame (2/2)" } };
SET g_LabeledCCommandBitSet = { sizeof(g_arr_CCommandBitLabels) / sizeof(LABELED_BIT), g_arr_CCommandBitLabels };
//=======================//
// Extended Opcode field //------------------------------------------------------------------------------------------
//=======================//
LABELED_BYTE g_arr_ExOpcodeByteLabels[] = {
{ FRAME_EXOPCODE_CONNECT, "Establish a connection" },
{ FRAME_EXOPCODE_CONNECTED, "Connection request has been accepted" },
{ FRAME_EXOPCODE_HARD_DISCONNECT, "Connection has been hard disconnected" },
{ FRAME_EXOPCODE_SACK, "Selective Acknowledgement" } };
SET g_LabeledExOpcodeByteSet = { sizeof(g_arr_ExOpcodeByteLabels) / sizeof(LABELED_BYTE), g_arr_ExOpcodeByteLabels };
//==================//
// SACK flags field //-----------------------------------------------------------------------------------------------
//==================//
LABELED_BIT g_arr_SACKFlagsBitLabels[] =
{ { 0, "Retry and/or Timestamp fields are invalid", "Retry and Timestamp fields are valid" }, // SACK_FLAGS_RESPONSE
{ 1, "Low DWORD of the RCVD mask is not present", "Low DWORD of the RCVD mask is present" }, // SACK_FLAGS_SACK_MASK1
{ 2, "High DWORD of the RCVD mask is not present", "High DWORD of the RCVD mask is present" }, // SACK_FLAGS_SACK_MASK2
{ 3, "Low DWORD of the DON'T CARE mask is not present", "Low DWORD of the DON'T CARE mask is present" }, // SACK_FLAGS_SEND_MASK1
{ 4, "High DWORD of the DON'T CARE mask is not present", "High DWORD of the DON'T CARE mask is present" } }; // SACK_FLAGS_SEND_MASK2
SET g_LabeledSACKFlagsBitSet = { sizeof(g_arr_SACKFlagsBitLabels) / sizeof(LABELED_BIT), g_arr_SACKFlagsBitLabels };
//==================//
// Helper functions //===========================================================================
//==================//
enum BitmaskPart { LOW = 0, HIGH, ENTIRE };
enum BitmaskType { RCVD, DONTCARE };
std::string InterpretRCVDBitmask( BitmaskPart i_Part, BYTE i_byBase, UNALIGNED DWORD* i_pdwBitmask )
{
std::string strSummary = "Received Seq=";
// [i_bBase+1 .. i_bBase+1+LENGTH]
// RCVD bitmask doesn't include the base value, since receiver can't claim it didn't receive the next dataframe to be received (NRcv);
if ( i_Part == HIGH )
{
// NOTE: +1 is needed to cross from MSB of the first DWORD TO LSB of the second
i_byBase += 8*sizeof(DWORD)+1; // shift to LSB of the second DWORD
}
else
{
++i_byBase;
}
QWORD qwBitMask = *i_pdwBitmask;
if ( i_Part == ENTIRE )
{
qwBitMask |= *(i_pdwBitmask+1);
}
strSummary += "{";
bool bFirst = true;
// Processing from LSB to MSB
for ( ; qwBitMask; qwBitMask >>= 1, ++i_byBase )
{
if ( qwBitMask & 1 )
{
if ( bFirst )
{
bFirst = false;
}
else
{
strSummary += ", ";
}
char arr_cBuffer[10];
strSummary += _itoa(i_byBase, arr_cBuffer, 16);
}
}
strSummary += "}";
return strSummary;
}// InterpretRCVDBitmask
std::string InterpretDONTCAREBitmask( BitmaskPart i_Part, BYTE i_byBase, UNALIGNED DWORD* i_pdwBitmask )
{
std::string strSummary = "Cancelling Seq=";
// [i_bBase-1-LENGTH .. i_bBase-1]
// DON'T CARE doesn't include the base value, since transmitter can't resend/refuse resending a dataframe which is about to be sent next (NSeq).
if ( i_Part == LOW )
{
i_byBase -= 8*sizeof(DWORD); // shift to MSB of the first DWORD
}
else
{
i_byBase -= 8*sizeof(QWORD); // shift to MSB of the second DWORD
}
QWORD qwBitMask = *i_pdwBitmask;
if ( i_Part == ENTIRE )
{
qwBitMask |= *(i_pdwBitmask+1);
}
else
{
// QWORD.High = QWORD.Low; QWORD.Low = 0;
qwBitMask <<= 8*sizeof(DWORD);
}
strSummary += "{";
bool bFirst = true;
// Processing from MSB to LSB
for ( ; qwBitMask; ++i_byBase, qwBitMask <<= 1 )
{
if ( qwBitMask & 0x8000000000000000 )
{
if ( bFirst )
{
bFirst = false;
}
else
{
strSummary += ", ";
}
char arr_cBuffer[10];
strSummary += _itoa(i_byBase, arr_cBuffer, 16);
}
}
strSummary += "}";
return strSummary;
}// InterpretDONTCAREBitmask
////////////////////////////////
// Custom Property Formatters //======================================================================================
////////////////////////////////
// DESCRIPTION: Custom description formatter for the Transport packet summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_TransportSummary( LPPROPERTYINST io_pProperyInstance )
{
std::string strSummary;
char arr_cBuffer[10];
DFBIG& rDBigFrame = *reinterpret_cast<DFBIG*>(io_pProperyInstance->lpPropertyInstEx->lpData);
if ( (rDBigFrame.bCommand & PACKET_COMMAND_DATA) == PACKET_COMMAND_DATA ) // DFrame
{
if ( *reinterpret_cast<BOOL*>(io_pProperyInstance->lpPropertyInstEx->Dword) )
{
strSummary = "KeepAlive";
}
else if ( (rDBigFrame.bCommand & PACKET_COMMAND_USER_2) == PACKET_COMMAND_USER_2 )
{
strSummary = "Voice";
}
else
{
strSummary = "User data";
}
#if defined(PARSE_DPLAY_TRANSPORT)
strSummary += " : Seq=";
strSummary += _itoa(rDBigFrame.bSeq, arr_cBuffer, 16);
strSummary += ", NRcv=";
strSummary += _itoa(rDBigFrame.bNRcv, arr_cBuffer, 16);
#endif // PARSE_DPLAY_TRANSPORT
if ( (rDBigFrame.bCommand & PACKET_COMMAND_NEW_MSG) == PACKET_COMMAND_NEW_MSG )
{
if ( (rDBigFrame.bCommand & PACKET_COMMAND_END_MSG) != PACKET_COMMAND_END_MSG )
{
strSummary += ", First fragment";
}
}
else if ( (rDBigFrame.bCommand & PACKET_COMMAND_END_MSG) == PACKET_COMMAND_END_MSG )
{
strSummary += ", Last fragment";
}
if ( (rDBigFrame.bControl & PACKET_CONTROL_END_STREAM) == PACKET_CONTROL_END_STREAM )
{
strSummary += ", End of Stream";
}
if ( (rDBigFrame.bCommand & PACKET_COMMAND_POLL) == PACKET_COMMAND_POLL )
{
strSummary += ", ACK now";
}
if ( (rDBigFrame.bControl & PACKET_CONTROL_RETRY) == PACKET_CONTROL_RETRY )
{
strSummary += ", Retry";
}
if ( (rDBigFrame.bControl & PACKET_CONTROL_CORRELATE) == PACKET_CONTROL_CORRELATE )
{
strSummary += ", Correlate / Keep Alive";
}
int nBitMaskIndex = 0;
if ( (rDBigFrame.bControl & PACKET_CONTROL_SACK_MASK1) == PACKET_CONTROL_SACK_MASK1 )
{
strSummary += ", ";
if ( (rDBigFrame.bControl & PACKET_CONTROL_SACK_MASK2) == PACKET_CONTROL_SACK_MASK2 ) // Entire QWORD
{
strSummary += InterpretRCVDBitmask(ENTIRE, rDBigFrame.bNRcv, &rDBigFrame.rgMask[nBitMaskIndex]);
nBitMaskIndex += 2;
}
else // Low DWORD only
{
strSummary += InterpretRCVDBitmask(LOW, rDBigFrame.bNRcv, &rDBigFrame.rgMask[nBitMaskIndex]);
++nBitMaskIndex;
}
}
else if ( (rDBigFrame.bControl & PACKET_CONTROL_SACK_MASK2) == PACKET_CONTROL_SACK_MASK2 ) // High DWORD only
{
strSummary += ", " + InterpretRCVDBitmask(HIGH, rDBigFrame.bNRcv, &rDBigFrame.rgMask[nBitMaskIndex]);
++nBitMaskIndex;
}
if ( (rDBigFrame.bControl & PACKET_CONTROL_SEND_MASK1) == PACKET_CONTROL_SEND_MASK1 )
{
strSummary += ", ";
if ( (rDBigFrame.bControl & PACKET_CONTROL_SEND_MASK2) == PACKET_CONTROL_SEND_MASK2 ) // Entire QWORD
{
strSummary += InterpretDONTCAREBitmask(ENTIRE, rDBigFrame.bSeq, &rDBigFrame.rgMask[nBitMaskIndex]);
}
else // Low DWORD only
{
strSummary += InterpretDONTCAREBitmask(LOW, rDBigFrame.bSeq, &rDBigFrame.rgMask[nBitMaskIndex]);
}
}
else if ( (rDBigFrame.bControl & PACKET_CONTROL_SEND_MASK2) == PACKET_CONTROL_SEND_MASK2 ) // High DWORD only
{
strSummary += ", " + InterpretDONTCAREBitmask(HIGH, rDBigFrame.bSeq, &rDBigFrame.rgMask[nBitMaskIndex]);
}
}
else
{
CFRAME& rCFrame = *reinterpret_cast<CFRAME*>(io_pProperyInstance->lpPropertyInstEx->lpData);
if ( rCFrame.bExtOpcode == FRAME_EXOPCODE_SACK ) // SACK CFrame
{
SFBIG8* pSBigFrame = reinterpret_cast<SFBIG8*>(&rCFrame);
enum { SACK_FLAGS_ALL_MASKS = SACK_FLAGS_SACK_MASK1 | SACK_FLAGS_SACK_MASK2 |
SACK_FLAGS_SEND_MASK1 | SACK_FLAGS_SEND_MASK2 };
if ( pSBigFrame->bFlags & SACK_FLAGS_ALL_MASKS ) // at least one bitmask field is present
{
strSummary = "Selective Acknowledgement";
}
else // if not a single bitmask is present
{
strSummary = "Acknowledgement";
}
#if defined(PARSE_DPLAY_TRANSPORT)
strSummary += " : NSeq=";
strSummary += _itoa(pSBigFrame->bNSeq, arr_cBuffer, 16);
strSummary += ", NRcv=";
strSummary += _itoa(pSBigFrame->bNRcv, arr_cBuffer, 16);
#endif // PARSE_DPLAY_TRANSPORT
if ( (pSBigFrame->bCommand & PACKET_COMMAND_POLL) == PACKET_COMMAND_POLL )
{
strSummary += ", ACK now";
}
if ( ((pSBigFrame->bFlags & SACK_FLAGS_RESPONSE) == SACK_FLAGS_RESPONSE) && pSBigFrame->bRetry )
{
strSummary += ", Retry";
}
int nBitMaskIndex = 0;
UNALIGNED ULONG* pulMasks = 0;
// This is a Protocol version 1.0 frame
pulMasks = pSBigFrame->rgMask;
if ( (pSBigFrame->bFlags & SACK_FLAGS_SACK_MASK1) == SACK_FLAGS_SACK_MASK1 )
{
strSummary += ", ";
if ( (pSBigFrame->bFlags & SACK_FLAGS_SACK_MASK2) == SACK_FLAGS_SACK_MASK2 ) // Entire QWORD
{
strSummary += InterpretRCVDBitmask(ENTIRE, pSBigFrame->bNRcv, &pulMasks[nBitMaskIndex]);
nBitMaskIndex += 2;
}
else // Low DWORD only
{
strSummary += InterpretRCVDBitmask(LOW, pSBigFrame->bNRcv, &pulMasks[nBitMaskIndex]);
++nBitMaskIndex;
}
}
else if ( (pSBigFrame->bFlags & SACK_FLAGS_SACK_MASK2) == SACK_FLAGS_SACK_MASK2 ) // High DWORD only
{
strSummary += ", " + InterpretRCVDBitmask(HIGH, pSBigFrame->bNRcv, &pulMasks[nBitMaskIndex]);
++nBitMaskIndex;
}
if ( (pSBigFrame->bFlags & SACK_FLAGS_SEND_MASK1) == SACK_FLAGS_SEND_MASK1 )
{
strSummary += ", ";
if ( (pSBigFrame->bFlags & SACK_FLAGS_SEND_MASK2) == SACK_FLAGS_SEND_MASK2 ) // Entire QWORD
{
strSummary += InterpretDONTCAREBitmask(ENTIRE, pSBigFrame->bNSeq, &pulMasks[nBitMaskIndex]);
}
else // Low DWORD only
{
strSummary += InterpretDONTCAREBitmask(LOW, pSBigFrame->bNSeq, &pulMasks[nBitMaskIndex]);
}
}
else if ( (pSBigFrame->bFlags & SACK_FLAGS_SEND_MASK2) == SACK_FLAGS_SEND_MASK2 ) // High DWORD only
{
strSummary += ", " + InterpretDONTCAREBitmask(HIGH, pSBigFrame->bNSeq, &pulMasks[nBitMaskIndex]);
}
}
else // Connection Control CFrame
{
strSummary = "Connection Control - ";
for ( int n = 0; n < sizeof(g_arr_ExOpcodeByteLabels) / sizeof(LABELED_BYTE); ++ n )
{
if ( g_arr_ExOpcodeByteLabels[n].Value == rCFrame.bExtOpcode )
{
strSummary += g_arr_ExOpcodeByteLabels[n].Label;
break;
}
}
if ( (rCFrame.bCommand & PACKET_COMMAND_POLL) == PACKET_COMMAND_POLL )
{
strSummary += " : ACK now";
}
}
}
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_TransportSummary
// DESCRIPTION: Custom description formatter for the dataframe's Command field summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_DCommandSummary( LPPROPERTYINST io_pProperyInstance )
{
BYTE bCommand = *reinterpret_cast<BYTE*>(io_pProperyInstance->lpData);
std::string strSummary = "Command: ";
strSummary += ( (bCommand & PACKET_COMMAND_RELIABLE) == PACKET_COMMAND_RELIABLE ) ? "Reliable" : "Unreliable";
strSummary += ( (bCommand & PACKET_COMMAND_SEQUENTIAL) == PACKET_COMMAND_SEQUENTIAL ) ? ", Sequenced" : ", Nonsequenced";
strSummary += ( (bCommand & PACKET_COMMAND_POLL) == PACKET_COMMAND_POLL ) ? ", Must be ACK'ed immediately" : ", ACK can be delayed";
if ( (bCommand & PACKET_COMMAND_NEW_MSG) == PACKET_COMMAND_NEW_MSG )
{
if ( (bCommand & PACKET_COMMAND_END_MSG) != PACKET_COMMAND_END_MSG )
{
strSummary += ", First fragment of the message";
}
}
else if ( (bCommand & PACKET_COMMAND_END_MSG) == PACKET_COMMAND_END_MSG )
{
strSummary += ", Last fragment of the message";
}
strSummary += ( (bCommand & PACKET_COMMAND_USER_1) == PACKET_COMMAND_USER_1 ) ? ", DirectPlay packet" : ", User packet";
strSummary += ( (bCommand & PACKET_COMMAND_USER_2) == PACKET_COMMAND_USER_2 ) ? ", Voice packet" : ", Data packet";
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_DCommandSummary
// DESCRIPTION: Custom description formatter for the Command Frame's Command field summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_CCommandSummary( LPPROPERTYINST io_pProperyInstance )
{
BYTE bCommand = *reinterpret_cast<BYTE*>(io_pProperyInstance->lpData);
std::string strSummary = "Command: ";
strSummary += ( (bCommand & PACKET_COMMAND_RELIABLE) == PACKET_COMMAND_RELIABLE ) ? "Reliable" : "Unreliable";
strSummary += ( (bCommand & PACKET_COMMAND_SEQUENTIAL) == PACKET_COMMAND_SEQUENTIAL ) ? ", Sequenced" : ", Nonsequenced";
strSummary += ( (bCommand & PACKET_COMMAND_POLL) == PACKET_COMMAND_POLL ) ? ", Must be ACK'ed immediately" : ", ACK can be delayed";
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_CCommandSummary
// DESCRIPTION: Custom description formatter for the dataframe's Control field summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_ControlSummary( LPPROPERTYINST io_pProperyInstance )
{
BYTE bControl = *reinterpret_cast<BYTE*>(io_pProperyInstance->lpData);
std::string strSummary = "Control: ";
if ( (bControl & PACKET_CONTROL_RETRY) == PACKET_CONTROL_RETRY )
{
strSummary += "Retry";
}
else
{
strSummary += "Original";
}
if ( (bControl & PACKET_CONTROL_CORRELATE) == PACKET_CONTROL_CORRELATE )
{
strSummary += ", Correlate / KeepAlive";
}
if ( (bControl & PACKET_CONTROL_END_STREAM) == PACKET_CONTROL_END_STREAM )
{
strSummary += ", Last packet in the stream";
}
if ( ( (bControl & PACKET_CONTROL_SACK_MASK1) == PACKET_CONTROL_SACK_MASK1 ) ||
( (bControl & PACKET_CONTROL_SACK_MASK2) == PACKET_CONTROL_SACK_MASK2 ) )
{
strSummary += "RCVD bitmask is nonzero";
}
if ( ( (bControl & PACKET_CONTROL_SEND_MASK1) == PACKET_CONTROL_SEND_MASK1 ) ||
( (bControl & PACKET_CONTROL_SEND_MASK2) == PACKET_CONTROL_SEND_MASK2 ) )
{
strSummary += ", DON'T CARE bitmask is nonzero";
}
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_ControlSummary
// DESCRIPTION: Custom description formatter for the Command Frame's SACK Flags field summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_SACKFlagsSummary( LPPROPERTYINST io_pProperyInstance )
{
BYTE bSACKFlags = *reinterpret_cast<BYTE*>(io_pProperyInstance->lpData);
std::string strSummary = "SACK Flags: ";
strSummary += ( (bSACKFlags & SACK_FLAGS_RESPONSE) == SACK_FLAGS_RESPONSE ) ? "Retry and Timestamp fields are valid" :
"Retry and/or Timestamp fields are invalid";
if ( ( (bSACKFlags & SACK_FLAGS_SACK_MASK1) == SACK_FLAGS_SACK_MASK1 ) ||
( (bSACKFlags & SACK_FLAGS_SACK_MASK2) == SACK_FLAGS_SACK_MASK2 ) )
{
strSummary += ", RCVD bitmask is nonzero";
}
else
{
strSummary += ", no RCVD bitmask";
}
if ( ( (bSACKFlags & SACK_FLAGS_SEND_MASK1) == SACK_FLAGS_SEND_MASK1 ) ||
( (bSACKFlags & SACK_FLAGS_SEND_MASK2) == SACK_FLAGS_SEND_MASK2 ) )
{
strSummary += ", DON'T CARE bitmask is nonzero";
}
else
{
strSummary += ", no DON'T CARE bitmask";
}
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_SACKFlagsSummary
struct SSACKBitmaskContext
{
BYTE byBase;
BitmaskPart Part;
BitmaskType Type;
BYTE byBit;
};
// DESCRIPTION: Custom description formatter for the Selective Acknowledgement Frame's RCVD bitmask's low/high DWORD summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_SACKBitmaskDWORDSummary( LPPROPERTYINST io_pProperyInstance )
{
DWORD dwBitmask = *reinterpret_cast<DWORD*>(io_pProperyInstance->lpPropertyInstEx->lpData);
SSACKBitmaskContext& rBitmaskContext = *reinterpret_cast<SSACKBitmaskContext*>(io_pProperyInstance->lpPropertyInstEx->Byte);
std::string strSummary = ( rBitmaskContext.Part == LOW ? "Low" : "High" );
strSummary += " DWORD of ";
strSummary += ( rBitmaskContext.Type == RCVD ? "RCVD" : "DON'T CARE" );
strSummary += " bitmask: ";
strSummary += ( ( rBitmaskContext.Type == RCVD ) ? InterpretRCVDBitmask(rBitmaskContext.Part, rBitmaskContext.byBase, &dwBitmask) :
InterpretDONTCAREBitmask(rBitmaskContext.Part, rBitmaskContext.byBase, &dwBitmask) );
strcpy(io_pProperyInstance->szPropertyText, strSummary.c_str());
} // FormatPropertyInstance_SACKBitmaskDWORDSummary
// DESCRIPTION: Custom description formatter for the bitmask's low/high DWORD summary
//
// ARGUMENTS: io_pProperyInstance - Data of the property's instance
//
// RETURNS: NOTHING
//
VOID WINAPIV FormatPropertyInstance_DWORDBitmaskEntry( LPPROPERTYINST io_pProperyInstance )
{
DWORD dwBitmask = *reinterpret_cast<DWORD*>(io_pProperyInstance->lpPropertyInstEx->lpData);
SSACKBitmaskContext& rBitmaskContext = *reinterpret_cast<SSACKBitmaskContext*>(io_pProperyInstance->lpPropertyInstEx->Byte);
BYTE byBase = rBitmaskContext.byBase;
BYTE byBit = rBitmaskContext.byBit;
switch ( rBitmaskContext.Type )
{
case RCVD:
{
// [i_bBase+1 .. i_bBase+1+LENGTH]
// RCVD bitmask doesn't include the base value, since receiver can't claim it didn't receive the next dataframe to be received (NRcv);
if ( rBitmaskContext.Part == HIGH )
{
// NOTE: +1 is needed to cross from MSB of the first DWORD TO LSB of the second
byBase += 8*sizeof(DWORD)+1; // shift to LSB of the second DWORD
}
else
{
++byBase;
}
byBase += byBit;
break;
}
case DONTCARE:
{
// [i_bBase-1-LENGTH .. i_bBase-1]
// DON'T CARE doesn't include the base value, since transmitter can't resend/refuse resending a dataframe which is about to be sent next (NSeq).
if ( rBitmaskContext.Part == HIGH )
{
byBase -= 8*sizeof(DWORD); // shift to MSB of the first DWORD
}
else
{
--byBase;
}
byBase -= byBit;
break;
}
default:
// TODO: ASSERT HERE (SHOULD NEVER HAPPEN)
break;
}
static DWORD arr_dwFlags[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000 };
char arr_cBuffer[100];
char arr_cTemplate[] = "................................ = %s %d (%d%c%d)";
arr_cTemplate[31-byBit] = ( (dwBitmask & arr_dwFlags[byBit]) ? '1' : '0' );
switch ( rBitmaskContext.Type )
{
case RCVD:
{
sprintf(arr_cBuffer, arr_cTemplate, ((dwBitmask & arr_dwFlags[byBit]) ? "Received" : "Did not receive"), byBase, rBitmaskContext.byBase, '+', byBit+1);
++byBase;
break;
}
case DONTCARE:
{
sprintf(arr_cBuffer, arr_cTemplate, ((dwBitmask & arr_dwFlags[byBit]) ? "Cancelling" : "Successfully transmitted"), byBase, rBitmaskContext.byBase, '-', byBit+1);
--byBase;
break;
}
}
strcpy(io_pProperyInstance->szPropertyText, arr_cBuffer);
} // FormatPropertyInstance_DWORDBitmaskEntry
//==================//
// Properties table //-----------------------------------------------------------------------------------------------
//==================//
PROPERTYINFO g_arr_TransportProperties[] =
{
// Transport packet summary property (TRANSPORT_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"DPlay Direct Network packet", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier
NULL, // labeled bit set
512, // description's maximum length
FormatPropertyInstance_TransportSummary // generic formatter
},
// DCommand field summary property (TRANSPORT_DCOMMAND_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Command field summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
512, // description's maximum length
FormatPropertyInstance_DCommandSummary // generic formatter
},
// DCommand field property (TRANSPORT_DCOMMAND)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Command field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_FLAGS, // data type qualifier.
&g_LabeledDCommandBitSet, // labeled bit set
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Control field summary property (TRANSPORT_CONTROL_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Control field summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
512, // description's maximum length
FormatPropertyInstance_ControlSummary // generic formatter
},
// Control field property (TRANSPORT_CONTROL)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Control", // label
"Control field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_FLAGS, // data type qualifier.
&g_LabeledControlBitSet, // labeled byte set
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Packet sequence number property (TRANSPORT_SEQNUM)
//
// INFO: This number is incremented for each _new_ packet sent. If an endpoint retransmits
// a packet, it uses the same sequence number it did the first time it sent it (base value for the DON'T CARE bitmask).
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Seq: Highest dataframe # sent (base value for the DON'T CARE bitmask)", // label
"Highest dataframe # sent field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Next receive number property (TRANSPORT_NEXTRECVNUM)
//
// INFO: Acknowledges every packet with a sequence number up to but not including this number (base value for the RCVD bitmask)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"NRcv: Next dataframe # to be received (base value for the RCVD bitmask)", // label
"Next dataframe # to be received field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// CCommand field property (TRANSPORT_CCOMMAND_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Command field summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
512, // description's maximum length
FormatPropertyInstance_CCommandSummary // generic formatter
},
// CCommand field property (TRANSPORT_CCOMMAND)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Command field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_FLAGS, // data type qualifier.
&g_LabeledCCommandBitSet, // labeled bit set
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Extended opcode field property (TRANSPORT_EXOPCODE)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Extended opcode", // label
"Extended opcode field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_LABELED_SET, // data type qualifier.
&g_LabeledExOpcodeByteSet, // labeled byte set
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Message ID field property (TRANSPORT_MSGID)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Message ID", // label
"Message ID field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Response ID field propery (TRANSPORT_RSPID)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Response ID", // label
"Response ID field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Protocol version field property (TRANSPORT_VERSION)
//
// INFO: Makes sure both endpoints use the same version of the protocol.
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Version", // label
"Version field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Session ID field property (TRANSPORT_SESSIONID)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Session ID", // label
"Session ID field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Time stamp field property (TRANSPORT_TIMESTAMP)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Time stamp", // label
"Time stamp field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// SACK flags field property (TRANSPORT_SACKFIELDS_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"SACK flags summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled byte set
512, // description's maximum length
FormatPropertyInstance_SACKFlagsSummary // generic formatter
},
// SACK flags field property (TRANSPORT_SACKFIELDS)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"SACK flags field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_FLAGS, // data type qualifier.
&g_LabeledSACKFlagsBitSet, // labeled byte set
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Retry field property (TRANSPORT_RETRY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Retry", // label
"Retry field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Next sequence number field property (TRANSPORT_NEXTSEQNUM)
//
// INFO: Sequence number of the next DFrame to be sent (base value for the DON'T CARE bitmask)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"NSeq: Next dataframe # to be sent (base value for the DON'T CARE bitmask)", // label
"Next dataframe # to be sent field", // status-bar comment
PROP_TYPE_BYTE, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // no data qualifiers
512, // description's maximum length
FormatPropertyInstance // generic formatter
},
// Low DWORD of the Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK1_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Low DWORD of the RCVD mask summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled byte set
512, // description's maximum length
FormatPropertyInstance_SACKBitmaskDWORDSummary // generic formatter
},
// Low DWORD of the Selective-ACK RCVD Mask property (TRANSPORT_RCVDMASK1)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Low DWORD of the RCVD mask", // label
"Low DWORD of the RCVD mask field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
3072, // description's maximum length
FormatPropertyInstance_DWORDBitmaskEntry // generic formatter
},
// High DWORD of the Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK2_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"High DWORD of the RCVD mask summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled byte set
512, // description's maximum length
FormatPropertyInstance_SACKBitmaskDWORDSummary // generic formatter
},
// High DWORD of Selective-ACK RCVD Mask property (TRANSPORT_RCVDMASK2)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"High DWORD of the RCVD mask", // label
"High DWORD of the RCVD mask field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
3072, // description's maximum length
FormatPropertyInstance_DWORDBitmaskEntry // generic formatter
},
// Low DWORD of the Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK1_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"Low DWORD of the DON'T CARE mask summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled byte set
512, // description's maximum length
FormatPropertyInstance_SACKBitmaskDWORDSummary // generic formatter
},
// Low DWORD of the Selective-ACK DON'T CARE Mask property (TRANSPORT_DONTCAREMASK1)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"Low DWORD of the DON'T CARE mask", // label
"Low DWORD of the DON'T CARE mask field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
3072, // description's maximum length
FormatPropertyInstance_DWORDBitmaskEntry // generic formatter
},
// High DWORD of the Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK2_SUMMARY)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"", // label
"High DWORD of the DON'T CARE mask summary", // status-bar comment
PROP_TYPE_SUMMARY, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled byte set
512, // description's maximum length
FormatPropertyInstance_SACKBitmaskDWORDSummary // generic formatter
},
// High DWORD of the Selective-ACK DON'T CARE Mask property (TRANSPORT_DONTCAREMASK2)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"High DWORD of the DON'T CARE mask", // label
"High DWORD of the DON'T CARE mask field", // status-bar comment
PROP_TYPE_DWORD, // data type
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
3072, // description's maximum length
FormatPropertyInstance_DWORDBitmaskEntry // generic formatter
},
// Compression Type property (VOICE_USERDATA)
{
0, // handle placeholder (MBZ)
0, // reserved (MBZ)
"User Data", // label
"User Data", // status-bar comment
PROP_TYPE_RAW_DATA, // data type (GUID)
PROP_QUAL_NONE, // data type qualifier.
NULL, // labeled bit set
64, // description's maximum length
FormatPropertyInstance // generic formatter
}
};
enum
{
nNUM_OF_TRANSPORT_PROPS = sizeof(g_arr_TransportProperties) / sizeof(PROPERTYINFO)
};
// Properties' indices
enum
{
TRANSPORT_SUMMARY = 0,
TRANSPORT_DCOMMAND_SUMMARY,
TRANSPORT_DCOMMAND,
TRANSPORT_CONTROL_SUMMARY,
TRANSPORT_CONTROL,
TRANSPORT_SEQNUM,
TRANSPORT_NEXTRECVNUM,
TRANSPORT_CCOMMAND_SUMMARY,
TRANSPORT_CCOMMAND,
TRANSPORT_EXOPCODE,
TRANSPORT_MSGID,
TRANSPORT_RSPID,
TRANSPORT_VERSION,
TRANSPORT_SESSIONID,
TRANSPORT_TIMESTAMP,
TRANSPORT_SACKFIELDS_SUMMARY,
TRANSPORT_SACKFIELDS,
TRANSPORT_RETRY,
TRANSPORT_NEXTSEQNUM,
TRANSPORT_RCVDMASK1_SUMMARY,
TRANSPORT_RCVDMASK1,
TRANSPORT_RCVDMASK2_SUMMARY,
TRANSPORT_RCVDMASK2,
TRANSPORT_DONTCAREMASK1_SUMMARY,
TRANSPORT_DONTCAREMASK1,
TRANSPORT_DONTCAREMASK2_SUMMARY,
TRANSPORT_DONTCAREMASK2,
TRANSPORT_USERDATA
};
} // anonymous namespace
// DESCRIPTION: Creates and fills-in a properties database for the protocol.
// Network Monitor uses this database to determine which properties the protocol supports.
//
// ARGUMENTS: i_hTransportProtocol - The handle of the protocol provided by the Network Monitor.
//
// RETURNS: NOTHING
//
DPLAYPARSER_API VOID BHAPI TransportRegister( HPROTOCOL i_hTransportProtocol )
{
CreatePropertyDatabase(i_hTransportProtocol, nNUM_OF_TRANSPORT_PROPS);
// Add the properties to the database
for( int nProp=0; nProp < nNUM_OF_TRANSPORT_PROPS; ++nProp )
{
AddProperty(i_hTransportProtocol, &g_arr_TransportProperties[nProp]);
}
} // TransportRegister
// DESCRIPTION: Frees the resources used to create the protocol property database.
//
// ARGUMENTS: i_hTransportProtocol - The handle of the protocol provided by the Network Monitor.
//
// RETURNS: NOTHING
//
DPLAYPARSER_API VOID WINAPI TransportDeregister( HPROTOCOL i_hProtocol )
{
DestroyPropertyDatabase(i_hProtocol);
} // TransportDeregister
namespace
{
// DESCRIPTION: Parses the Transport frame to find its size (in bytes) NOT including the user data
//
// ARGUMENTS: i_pbTransportFrame - Pointer to the start of the unclaimed data. Typically, the unclaimed data is located
// in the middle of a frame because a previous parser has claimed data before this parser.
//
// RETURNS: Size of the specified Transport frame (in bytes)
//
int TransportHeaderSize( BYTE* i_pbTransportFrame )
{
int arr_nNumOfBits[] = { /*00 = 0x0000*/ 0, /*01 = 0x0001*/ 1, /*02 = 0x0010*/ 1, /*03 = 0x0011*/ 2,
/*04 = 0x0100*/ 1, /*05 = 0x0101*/ 2, /*06 = 0x0110*/ 2, /*07 = 0x0111*/ 3,
/*08 = 0x1000*/ 1, /*09 = 0x1001*/ 2, /*10 = 0x1010*/ 2, /*11 = 0x1011*/ 3,
/*12 = 0x1100*/ 2, /*13 = 0x1101*/ 3, /*14 = 0x1110*/ 3, /*15 = 0x1111*/ 4 };
const DFRAME& rDFrame = *reinterpret_cast<DFRAME*>(i_pbTransportFrame);
if ( (rDFrame.bCommand & PACKET_COMMAND_DATA) == PACKET_COMMAND_DATA ) // DFrame
{
return sizeof(rDFrame) + sizeof(DWORD)*arr_nNumOfBits[rDFrame.bControl >> 4];
}
else
{
const CFRAME& rCFrame = *reinterpret_cast<CFRAME*>(i_pbTransportFrame);
if ( rCFrame.bExtOpcode == FRAME_EXOPCODE_SACK ) // SACK CFrame
{
const SFBIG8* pSFrame = reinterpret_cast<SFBIG8*>(i_pbTransportFrame);
ULONG ulMaskSize = sizeof(DWORD)*arr_nNumOfBits[(pSFrame->bFlags >> 1) & 0x0F];
// This is a Protocol version 1.0 frame
return sizeof(SACKFRAME8) + ulMaskSize;
}
else // Connection Control CFrame
{
return sizeof(rCFrame);
}
}
} // TransportHeaderSize
} // Anonymous namespace
// DESCRIPTION: Indicates whether a piece of data is recognized as the protocol that the parser detects.
//
// ARGUMENTS: i_hFrame - The handle to the frame that contains the data.
// i_pbMacFrame - The pointer to the first byte of the frame; the pointer provides a way to view
// the data that the other parsers recognize.
// i_pbTransportFrame - Pointer to the start of the unclaimed data. Typically, the unclaimed data is located
// in the middle of a frame because a previous parser has claimed data before this parser.
// i_dwMacType - MAC value of the first protocol in a frame. Typically, the i_dwMacType value is used
// when the parser must identify the first protocol in the frame. Can be one of the following:
// MAC_TYPE_ETHERNET = 802.3, MAC_TYPE_TOKENRING = 802.5, MAC_TYPE_FDDI ANSI = X3T9.5.
// i_dwBytesLeft - The remaining number of bytes from a location in the frame to the end of the frame.
// i_hPrevProtocol - Handle of the previous protocol.
// i_dwPrevProtOffset - Offset of the previous protocol (from the beginning of the frame).
// o_pdwProtocolStatus - Protocol status indicator. Must be one of the following: PROTOCOL_STATUS_RECOGNIZED,
// PROTOCOL_STATUS_NOT_RECOGNIZED, PROTOCOL_STATUS_CLAIMED, PROTOCOL_STATUS_NEXT_PROTOCOL.
// o_phNextProtocol - Placeholder for the handle of the next protocol. This parameter is set when the parser identifies
// the protocol that follows its own protocol.
// io_pdwptrInstData - On input, a pointer to the instance data from the previous protocol.
// On output, a pointer to the instance data for the current protocol.
//
// RETURNS: If the function is successful, the return value is a pointer to the first byte after the recognized parser data.
// If the parser claims all the remaining data, the return value is NULL. If the function is unsuccessful, the return
// value is the initial value of the i_pbTransportFrame parameter.
//
DPLAYPARSER_API BYTE* BHAPI TransportRecognizeFrame( HFRAME i_hFrame,
ULPBYTE i_upbMacFrame,
ULPBYTE i_upbTransportFrame,
DWORD i_dwMacType,
DWORD i_dwBytesLeft,
HPROTOCOL i_hPrevProtocol,
DWORD i_dwPrevProtOffset,
LPDWORD o_pdwProtocolStatus,
LPHPROTOCOL o_phNextProtocol,
PDWORD_PTR io_pdwptrInstData )
{
// Validate the amount of unclaimed data
enum
{
nMIN_TransportHeaderSize = min(min(sizeof(DFRAME), sizeof(CFRAME)), sizeof(SACKFRAME8))
};
// Validate the packet as DPlay Transport type
if ( i_dwBytesLeft < nMIN_TransportHeaderSize )
{
// Assume the unclaimed data is not recognizable
*o_pdwProtocolStatus = PROTOCOL_STATUS_NOT_RECOGNIZED;
return i_upbTransportFrame;
}
// Check if we are dealing with a DPlay Voice packet
enum
{
PACKET_COMMAND_SESSION = PACKET_COMMAND_DATA | PACKET_COMMAND_USER_1,
PACKET_COMMAND_VOICE = PACKET_COMMAND_DATA | PACKET_COMMAND_USER_1 | PACKET_COMMAND_USER_2
};
const DFRAME& rDFrame = *reinterpret_cast<DFRAME*>(i_upbTransportFrame);
*o_pdwProtocolStatus = PROTOCOL_STATUS_NEXT_PROTOCOL;
// Let upper protocol's parser know if the message is a non-initial fragment of a fragmented message
*io_pdwptrInstData = ((rDFrame.bCommand & PACKET_COMMAND_NEW_MSG) == PACKET_COMMAND_NEW_MSG);
if ( (rDFrame.bCommand & PACKET_COMMAND_VOICE) == PACKET_COMMAND_VOICE )
{
// Notify NetMon about the handoff protocol
*o_phNextProtocol = GetProtocolFromName("DPLAYVOICE");
}
else if ( (rDFrame.bCommand & PACKET_COMMAND_SESSION) == PACKET_COMMAND_SESSION )
{
// Notify NetMon about the handoff protocol
*o_phNextProtocol = GetProtocolFromName("DPLAYSESSION");
}
else
{
*o_pdwProtocolStatus = PROTOCOL_STATUS_RECOGNIZED;
*o_phNextProtocol = NULL;
}
return i_upbTransportFrame + TransportHeaderSize(i_upbTransportFrame);
} // TransportRecognizeFrame
//=======================================//
// Attaching properties helper functions //
//=======================================//
namespace
{
// DESCRIPTION: Maps the DWORD bitmask properties on a per-bit basis.
//
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
// i_nPropertyIndex - Index of the property in the global properties table.
// i_pdwBitmask - Pointer to the value to which the property is being attached.
// i_byBase - Base value from which the entry value is calculated.
// i_Part - LOW or HIGH part of the QWORD bitmask.
// i_Type - RCVD or DONTCARE type of the bitmask.
// i_byLevel - Level in the detail pane tree.
//
// RETURNS: NOTHING
//
VOID WINAPIV AttachBitmaskDWORDProperties( HFRAME i_hFrame, int i_nPropertyIndex, UNALIGNED DWORD* i_pdwBitmask, BYTE i_byBase,
BitmaskPart i_Part, BitmaskType i_Type, BYTE i_byLevel )
{
for ( BYTE byBit = 0; byBit < 32; ++byBit )
{
SSACKBitmaskContext BitmaskContext = { i_byBase, i_Part, i_Type, byBit };
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[i_nPropertyIndex].hProperty,
sizeof(*i_pdwBitmask), i_pdwBitmask,
sizeof(BitmaskContext), &BitmaskContext,
0, i_byLevel, 0);
}
} // AttachBitmaskDWORDProperties
// DESCRIPTION: Maps the Data-Frame properties that exist in a piece of recognized data to specific locations.
//
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
// i_pbDFrame - Pointer to the start of the recognized data.
//
// RETURNS: NOTHING
//
void AttachDFRAMEProperties( HFRAME i_hFrame,
BYTE* i_pbDFrame )
{
//=======================================//
// Processing the core dataframe fields //
//=======================================//
//
DFRAME& rDFrame = *reinterpret_cast<DFRAME*>(i_pbDFrame);
// DCommand summary
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_DCOMMAND_SUMMARY].hProperty,
sizeof(rDFrame.bCommand), &rDFrame.bCommand, 0, 1, 0);
// DCommand field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_DCOMMAND].hProperty,
sizeof(rDFrame.bCommand), &rDFrame.bCommand, 0, 2, 0);
// Control summary
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_CONTROL_SUMMARY].hProperty,
sizeof(rDFrame.bControl), &rDFrame.bControl, 0, 1, 0);
// Control field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_CONTROL].hProperty,
sizeof(rDFrame.bControl), &rDFrame.bControl, 0, 2, 0);
// Sequence number field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_SEQNUM].hProperty,
sizeof(rDFrame.bSeq), &rDFrame.bSeq, 0, 1, 0);
// Next receive number field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_NEXTRECVNUM].hProperty,
sizeof(rDFrame.bNRcv), &rDFrame.bNRcv, 0, 1, 0);
//==================================================//
// Processing the optional dataframe bitmask fields //
//==================================================//
//
UNALIGNED DFBIG& rDBigFrame = *reinterpret_cast<UNALIGNED DFBIG *>(i_pbDFrame);
int nBitMaskIndex = 0;
if ( (rDFrame.bControl & PACKET_CONTROL_SACK_MASK1) == PACKET_CONTROL_SACK_MASK1 )
{
SSACKBitmaskContext LowRCVDContext = { rDBigFrame.bNRcv, LOW, RCVD, NULL };
// Low DWORD of Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK1_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_RCVDMASK1_SUMMARY].hProperty,
sizeof(rDBigFrame.rgMask[nBitMaskIndex]), &rDBigFrame.rgMask[nBitMaskIndex],
sizeof(LowRCVDContext), &LowRCVDContext,
0, 1, 0);
// Low DWORD of Selective-ACK RCVD Mask field (TRANSPORT_RCVDMASK1)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK1, &rDBigFrame.rgMask[nBitMaskIndex], rDBigFrame.bNRcv, LOW, RCVD, 2);
++nBitMaskIndex;
}
if ( (rDFrame.bControl & PACKET_CONTROL_SACK_MASK2) == PACKET_CONTROL_SACK_MASK2 )
{
SSACKBitmaskContext HighRCVDContext = { rDBigFrame.bNRcv, HIGH, RCVD, NULL };
// High DWORD of Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK2_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_RCVDMASK2_SUMMARY].hProperty,
sizeof(rDBigFrame.rgMask[nBitMaskIndex]), &rDBigFrame.rgMask[nBitMaskIndex],
sizeof(HighRCVDContext), &HighRCVDContext,
0, 1, 0);
// High DWORD of Selective-ACK RCVD Mask field (TRANSPORT_RCVDMASK2)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK2, &rDBigFrame.rgMask[nBitMaskIndex], rDBigFrame.bNRcv, HIGH, RCVD, 2);
++nBitMaskIndex;
}
if ( (rDFrame.bControl & PACKET_CONTROL_SEND_MASK1) == PACKET_CONTROL_SEND_MASK1 )
{
SSACKBitmaskContext LowDONTCAREContext = { rDBigFrame.bSeq, LOW, DONTCARE, NULL };
// Low DWORD of Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK1_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_DONTCAREMASK1_SUMMARY].hProperty,
sizeof(rDBigFrame.rgMask[nBitMaskIndex]), &rDBigFrame.rgMask[nBitMaskIndex],
sizeof(LowDONTCAREContext), &LowDONTCAREContext,
0, 1, 0);
// Low DWORD of Selective-ACK RCVD Mask field (TRANSPORT_DONTCAREMASK1)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK1, &rDBigFrame.rgMask[nBitMaskIndex], rDBigFrame.bSeq, LOW, DONTCARE, 2);
++nBitMaskIndex;
}
if ( (rDFrame.bControl & PACKET_CONTROL_SEND_MASK2) == PACKET_CONTROL_SEND_MASK2 )
{
SSACKBitmaskContext HighDONTCAREContext = { rDBigFrame.bSeq, HIGH, DONTCARE, NULL };
// High DWORD of Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK2_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_DONTCAREMASK2_SUMMARY].hProperty,
sizeof(rDBigFrame.rgMask[nBitMaskIndex]), &rDBigFrame.rgMask[nBitMaskIndex],
sizeof(HighDONTCAREContext), &HighDONTCAREContext,
0, 1, 0);
// High DWORD of Selective-ACK RCVD Mask field (TRANSPORT_DONTCAREMASK2)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK2, &rDBigFrame.rgMask[nBitMaskIndex], rDBigFrame.bSeq, HIGH, DONTCARE, 2);
}
} // AttachDFRAMEProperties
// DESCRIPTION: Maps the Command-Frame properties that exist in a piece of recognized data to specific locations.
//
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
// i_pbCFrame - Pointer to the start of the recognized data.
//
// RETURNS: NOTHING
//
void AttachCFRAMEProperties( HFRAME i_hFrame,
BYTE* i_pbCFrame)
{
// Processing the core command frame fields
//
CFRAME& rCFrame = *reinterpret_cast<CFRAME*>(i_pbCFrame);
// CCommand summary
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_CCOMMAND_SUMMARY].hProperty,
sizeof(rCFrame.bCommand), &rCFrame.bCommand, 0, 1, 0);
// CCommand field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_CCOMMAND].hProperty,
sizeof(rCFrame.bCommand), &rCFrame.bCommand, 0, 2, 0);
// ExtOpcode field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_EXOPCODE].hProperty,
sizeof(rCFrame.bExtOpcode), &rCFrame.bExtOpcode, 0, 1, 0);
if ( rCFrame.bExtOpcode == FRAME_EXOPCODE_SACK )
{
//=======================================================//
// Processing the Selective Acknowledgement Command frame fields //
//=======================================================//
//
SFBIG8* pSFrame = reinterpret_cast<SFBIG8*>(i_pbCFrame);
// SACK flags summary
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_SACKFIELDS_SUMMARY].hProperty,
sizeof(pSFrame->bFlags), &pSFrame->bFlags, 0, 1, 0);
// SACK flags field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_SACKFIELDS].hProperty,
sizeof(pSFrame->bFlags), &pSFrame->bFlags, 0, 2, 0);
// Retry field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_RETRY].hProperty,
sizeof(pSFrame->bRetry), &pSFrame->bRetry, 0, 1, 0);
// Next sequence number field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_NEXTSEQNUM].hProperty,
sizeof(pSFrame->bNSeq), &pSFrame->bNSeq, 0, 1, 0);
// Next receive number field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_NEXTRECVNUM].hProperty,
sizeof(pSFrame->bNRcv), &pSFrame->bNRcv, 0, 1, 0);
UNALIGNED ULONG* pulMasks = 0;
// This is a Protocol version 1.0 frame
// Timestamp field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_TIMESTAMP].hProperty,
sizeof(pSFrame->tTimestamp), &pSFrame->tTimestamp, 0, 1, 0);
pulMasks = pSFrame->rgMask;
//================================================================================//
// Processing the optional Selective Acknowledgement Command frame bitmask fields //
//================================================================================//
//
int nBitMaskIndex = 0;
if ( (pSFrame->bFlags & SACK_FLAGS_SACK_MASK1) == SACK_FLAGS_SACK_MASK1 )
{
SSACKBitmaskContext LowRCVDContext = { pSFrame->bNRcv, LOW, RCVD, NULL };
// Low DWORD of Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK1_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_RCVDMASK1_SUMMARY].hProperty,
sizeof(pulMasks[nBitMaskIndex]), &pulMasks[nBitMaskIndex],
sizeof(LowRCVDContext), &LowRCVDContext,
0, 1, 0);
// Low DWORD of Selective-ACK RCVD Mask field (TRANSPORT_RCVDMASK1)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK1, &pulMasks[nBitMaskIndex], pSFrame->bNRcv, LOW, RCVD, 2);
++nBitMaskIndex;
}
if ( (pSFrame->bFlags & SACK_FLAGS_SACK_MASK2) == SACK_FLAGS_SACK_MASK2 )
{
SSACKBitmaskContext HighRCVDContext = { pSFrame->bNRcv, HIGH, RCVD, NULL };
// High DWORD of Selective-ACK RCVD Mask summary (TRANSPORT_RCVDMASK2_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_RCVDMASK2_SUMMARY].hProperty,
sizeof(pulMasks[nBitMaskIndex]), &pulMasks[nBitMaskIndex],
sizeof(HighRCVDContext), &HighRCVDContext,
0, 1, 0);
// High DWORD of Selective-ACK RCVD Mask field (TRANSPORT_RCVDMASK2)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK2, &pulMasks[nBitMaskIndex], pSFrame->bNRcv, HIGH, RCVD, 2);
++nBitMaskIndex;
}
if ( (pSFrame->bFlags & SACK_FLAGS_SEND_MASK1) == SACK_FLAGS_SEND_MASK1 )
{
SSACKBitmaskContext LowDONTCAREContext = { pSFrame->bNSeq, LOW, DONTCARE, NULL };
// Low DWORD of Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK1_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_DONTCAREMASK1_SUMMARY].hProperty,
sizeof(pulMasks[nBitMaskIndex]), &pulMasks[nBitMaskIndex],
sizeof(LowDONTCAREContext), &LowDONTCAREContext,
0, 1, 0);
// Low DWORD of Selective-ACK RCVD Mask field (TRANSPORT_DONTCAREMASK1)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK1, &pulMasks[nBitMaskIndex], pSFrame->bNSeq, LOW, DONTCARE, 2);
++nBitMaskIndex;
}
if ( (pSFrame->bFlags & SACK_FLAGS_SEND_MASK2) == SACK_FLAGS_SEND_MASK2 )
{
SSACKBitmaskContext HighDONTCAREContext = { pSFrame->bNSeq, HIGH, DONTCARE, NULL };
// High DWORD of Selective-ACK DON'T CARE Mask summary (TRANSPORT_DONTCAREMASK2_SUMMARY)
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_DONTCAREMASK2_SUMMARY].hProperty,
sizeof(pulMasks[nBitMaskIndex]), &pulMasks[nBitMaskIndex],
sizeof(HighDONTCAREContext), &HighDONTCAREContext,
0, 1, 0);
// High DWORD of Selective-ACK RCVD Mask field (TRANSPORT_DONTCAREMASK2)
AttachBitmaskDWORDProperties(i_hFrame, TRANSPORT_RCVDMASK2, &pulMasks[nBitMaskIndex], pSFrame->bNSeq, HIGH, DONTCARE, 2);
++nBitMaskIndex;
}
}
else
{
//========================================================//
// Processing the Connection Control Command frame fields //
//========================================================//
// Message ID field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_MSGID].hProperty,
sizeof(rCFrame.bMsgID), &rCFrame.bMsgID, 0, 1, 0);
// Response ID field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_RSPID].hProperty,
sizeof(rCFrame.bRspID), &rCFrame.bRspID, 0, 1, 0);
// Version number field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_VERSION].hProperty,
sizeof(rCFrame.dwVersion), &rCFrame.dwVersion, 0, 1, 0);
// Session ID field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_SESSIONID].hProperty,
sizeof(rCFrame.dwSessID), &rCFrame.dwSessID, 0, 1, 0);
// Timestamp field
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_TIMESTAMP].hProperty,
sizeof(rCFrame.tTimestamp), &rCFrame.tTimestamp, 0, 1, 0);
}
} // AttachCFRAMEProperties
// Platform independent memory accessor of big endian words
inline WORD ReadBigEndianWord( BYTE* i_pbData )
{
return (*i_pbData << 8) | *(i_pbData+1);
}
} // Anonymous namespace
// DESCRIPTION: Maps the properties that exist in a piece of recognized data to specific locations.
//
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
// i_pbMacFram - Pointer to the first byte in the frame.
// i_pbTransportFrame - Pointer to the start of the recognized data.
// i_dwMacType - MAC value of the first protocol in a frame. Typically, the i_dwMacType value is used
// when the parser must identify the first protocol in the frame. Can be one of the following:
// MAC_TYPE_ETHERNET = 802.3, MAC_TYPE_TOKENRING = 802.5, MAC_TYPE_FDDI ANSI = X3T9.5.
// i_dwBytesLeft - The remaining number of bytes in a frame (starting from the beginning of the recognized data).
// i_hPrevProtocol - Handle of the previous protocol.
// i_dwPrevProtOffset - Offset of the previous protocol (starting from the beginning of the frame).
// i_dwptrInstData - Pointer to the instance data that the previous protocol provides.
//
// RETURNS: Must return NULL
//
DPLAYPARSER_API BYTE* BHAPI TransportAttachProperties( HFRAME i_hFrame,
ULPBYTE i_upbMacFrame,
ULPBYTE i_upbTransportFrame,
DWORD i_dwMacType,
DWORD i_dwBytesLeft,
HPROTOCOL i_hPrevProtocol,
DWORD i_dwPrevProtOffset,
DWORD_PTR i_dwptrInstData )
{
// TODO: Use HelpID in AttachPropertyInstance
// Check if the packet is a KeepAlive
const size_t sztTransportHeaderSize = TransportHeaderSize(i_upbTransportFrame);
const DFRAME& rDFrame = *reinterpret_cast<DFRAME*>(i_upbTransportFrame);
size_t sztTransportFrameSize = i_dwptrInstData;
// If an empty dataframe and not the last packet in the stream, than it's a KeepAlive
BOOL bKeepAlive = ( (sztTransportHeaderSize == sztTransportFrameSize) &&
((rDFrame.bControl & PACKET_CONTROL_END_STREAM) != PACKET_CONTROL_END_STREAM) );
//===================//
// Attach Properties //
//===================//
//
// Transport summary line
AttachPropertyInstanceEx(i_hFrame, g_arr_TransportProperties[TRANSPORT_SUMMARY].hProperty,
sztTransportHeaderSize, i_upbTransportFrame,
sizeof(BOOL), &bKeepAlive,
0, 0, 0);
#if defined(PARSE_DPLAY_TRANSPORT)
if ( (rDFrame.bCommand & PACKET_COMMAND_DATA) == PACKET_COMMAND_DATA )
{
AttachDFRAMEProperties(i_hFrame, i_upbTransportFrame);
enum
{
USERDATA_BITMASK = ~(PACKET_COMMAND_USER_1 | PACKET_COMMAND_USER_2)
};
if ( (rDFrame.bCommand | USERDATA_BITMASK) == USERDATA_BITMASK )
{
// User data (TRANSPORT_USERDATA)
AttachPropertyInstance(i_hFrame, g_arr_TransportProperties[TRANSPORT_USERDATA].hProperty,
sztTransportFrameSize - sztTransportHeaderSize, i_upbTransportFrame + sztTransportHeaderSize, 0, 1, 0);
}
}
else
{
AttachCFRAMEProperties(i_hFrame, i_upbTransportFrame);
}
#endif // PARSE_DPLAY_TRANSPORT
return NULL;
} // TransportAttachProperties
// DESCRIPTION: Formats the data that is displayed in the details pane of the Network Monitor UI.
//
// ARGUMENTS: i_hFrame - Handle of the frame that is being parsed.
// i_pbMacFrame - Pointer to the first byte of a frame.
// i_pbCoreFrame - Pointer to the beginning of the protocol data in a frame.
// i_dwPropertyInsts - Number of PROPERTYINST structures provided by lpPropInst.
// i_pPropInst - Pointer to an array of PROPERTYINST structures.
//
// RETURNS: If the function is successful, the return value is a pointer to the first byte after the recognized data in a frame,
// or NULL if the recognized data is the last piece of data in a frame. If the function is unsuccessful, the return value
// is the initial value of i_pbTransportFrame.
//
DPLAYPARSER_API DWORD BHAPI TransportFormatProperties( HFRAME i_hFrame,
ULPBYTE i_upbMacFrame,
ULPBYTE i_upbTransportFrame,
DWORD i_dwPropertyInsts,
LPPROPERTYINST i_pPropInst )
{
// Loop through the property instances...
while( i_dwPropertyInsts-- > 0)
{
// ...and call the formatter for each
reinterpret_cast<FORMAT>(i_pPropInst->lpPropertyInfo->InstanceData)(i_pPropInst);
++i_pPropInst;
}
return NMERR_SUCCESS;
}
// DESCRIPTION: Notifies Network Monitor that Transport protocol parser exists.
//
// ARGUMENTS: NONE
//
// RETURNS: TRUE - success, FALSE - failure
//
bool CreateTransportProtocol( void )
{
// The entry points to the export functions that Network Monitor uses to operate the parser
ENTRYPOINTS TransportEntryPoints =
{
// TransportParser Entry Points
TransportRegister,
TransportDeregister,
TransportRecognizeFrame,
TransportAttachProperties,
TransportFormatProperties
};
// The first active instance of this parser needs to register with the kernel
g_hTransportProtocol = CreateProtocol("DPLAYTRANSPORT", &TransportEntryPoints, ENTRYPOINTS_SIZE);
return (g_hTransportProtocol ? TRUE : FALSE);
} // CreateTransportProtocol
// DESCRIPTION: Removes the Transport protocol parser from the Network Monitor's database of parsers
//
// ARGUMENTS: NONE
//
// RETURNS: NOTHING
//
void DestroyTransportProtocol( void )
{
DestroyProtocol(g_hTransportProtocol);
} // DestroyTransportProtocol