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.
513 lines
14 KiB
513 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1991 ICL Data
|
|
|
|
Module Name:
|
|
|
|
llctrace.c
|
|
|
|
Abstract:
|
|
|
|
Module implements simple trace buffer management.
|
|
The application must povides a trace buffer and
|
|
read it by polling.
|
|
|
|
THIS MODULE HAS BEEN IMPLEMENTED ONLY FOR THE DATA LINK
|
|
EMULATION ENVIRONMENT ON USER LEVEL.
|
|
|
|
|
|
Author:
|
|
|
|
Antti Saarenheimo (o-anttis) 10-OCT-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <llc.h>
|
|
#ifndef max
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#ifdef TRACE_ENABLED
|
|
|
|
BOOLEAN TraceEnabled;
|
|
static PLLC_TRACE_HEADER pTraceBufferBase;
|
|
static PLLC_TRACE_HEADER pTraceBufferTop;
|
|
static PLLC_TRACE_HEADER pTraceBufferHead;
|
|
static NDIS_SPIN_LOCK TraceLock;
|
|
static ULONG TraceFlags;
|
|
|
|
|
|
UCHAR GetHexDigit(
|
|
UINT Ch
|
|
);
|
|
PUCHAR
|
|
GetHexString(
|
|
PUCHAR pDest,
|
|
UINT Length,
|
|
PUCHAR Buffer
|
|
);
|
|
DLC_STATUS
|
|
LlcTraceInitialize(
|
|
IN PVOID pUserTraceBuffer,
|
|
IN ULONG UserTraceBufferSize,
|
|
IN ULONG UserTraceFlags
|
|
)
|
|
{
|
|
//
|
|
// This small piece of code is not multiprocessors safe,
|
|
// but nobody will ever find it ...
|
|
//
|
|
if (TraceEnabled)
|
|
{
|
|
return DLC_STATUS_DUPLICATE_COMMAND;
|
|
}
|
|
if (UserTraceBufferSize < LLC_MIN_TRACE_BUFFER)
|
|
{
|
|
return DLC_STATUS_INVALID_BUFFER_LENGTH;
|
|
}
|
|
RtlZeroMemory( pUserTraceBuffer, (UINT)UserTraceBufferSize );
|
|
ALLOCATE_SPIN_LOCK( &TraceLock );
|
|
pTraceBufferBase = pTraceBufferHead = (PLLC_TRACE_HEADER)pUserTraceBuffer;
|
|
pTraceBufferHead->Event = LLC_TRACE_END_OF_DATA;
|
|
pTraceBufferTop =
|
|
&pTraceBufferBase[ UserTraceBufferSize / sizeof(LLC_TRACE_HEADER) ];
|
|
TraceFlags = UserTraceFlags;
|
|
TraceEnabled = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
LlcTraceClose(
|
|
VOID
|
|
)
|
|
{
|
|
if (TraceEnabled)
|
|
{
|
|
TraceEnabled = FALSE;
|
|
DEALLOCATE_SPIN_LOCK( &TraceLock );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
LlcTraceWrite(
|
|
IN UINT Event,
|
|
IN UCHAR AdapterNumber,
|
|
IN UINT DataBufferSize,
|
|
IN PVOID pDataBuffer
|
|
)
|
|
{
|
|
|
|
//if ((AdapterNumber & 0x7f) != 0)
|
|
// return;
|
|
|
|
if (TraceEnabled)
|
|
{
|
|
ACQUIRE_SPIN_LOCK( &TraceLock );
|
|
if ((ULONG)(&pTraceBufferHead[1]) >= (ULONG)pTraceBufferTop)
|
|
{
|
|
pTraceBufferHead = (PLLC_TRACE_HEADER)pTraceBufferBase;
|
|
}
|
|
pTraceBufferHead->Event = (USHORT)Event;
|
|
pTraceBufferHead->AdapterNumber = AdapterNumber;
|
|
pTraceBufferHead->TimerTick = AbsoluteTime;
|
|
pTraceBufferHead->DataLength = (UCHAR)
|
|
#ifdef min
|
|
min( TRACE_DATA_LENGTH, DataBufferSize );
|
|
#else
|
|
__min( TRACE_DATA_LENGTH, DataBufferSize );
|
|
#endif
|
|
memcpy(
|
|
pTraceBufferHead->Buffer,
|
|
pDataBuffer,
|
|
pTraceBufferHead->DataLength
|
|
);
|
|
pTraceBufferHead++;
|
|
pTraceBufferHead->Event = LLC_TRACE_END_OF_DATA;
|
|
RELEASE_SPIN_LOCK( &TraceLock );
|
|
}
|
|
}
|
|
|
|
#ifdef OS2_EMU_DLC
|
|
//
|
|
// Procedure makes the post mortem dump of the given number of last frames.
|
|
// The output should look very much like in Sniffer.
|
|
// This routine doesn't supprot source routing info, but its implementatin
|
|
// should not be a very big thing.
|
|
//
|
|
VOID
|
|
LlcTraceDump(
|
|
IN UINT LastEvents,
|
|
IN UINT AdapterNumber,
|
|
IN PUCHAR pRemoteNode
|
|
)
|
|
{
|
|
PUCHAR pDest, pSrc, pCommand, pDlcHeader, pDirection, pTmp;
|
|
UINT i;
|
|
UCHAR Buffer1[13], Buffer2[13];
|
|
UCHAR CmdResp, PollFinal;
|
|
LLC_HEADER LlcHeader;
|
|
BOOLEAN IsEthernet;
|
|
PLLC_TRACE_HEADER pTrace;
|
|
UCHAR DataBuffer[18];
|
|
USHORT EthernetType;
|
|
|
|
RtlZeroMemory( DataBuffer, sizeof( DataBuffer ));
|
|
LlcTraceWrite(
|
|
LLC_TRACE_RECEIVE_FRAME, AdapterNumber, sizeof(DataBuffer), DataBuffer );
|
|
|
|
if (!TraceEnabled)
|
|
return;
|
|
ACQUIRE_SPIN_LOCK( &TraceLock );
|
|
|
|
printf(
|
|
"# Time Adpt Local Node Remote Node Dsp Ssp Cmd Nr Ns\n");
|
|
//0---------1---------2---------3---------4---------5---------6---------7-----
|
|
//5 10 5 13 13 4 4 9 4 4
|
|
for (
|
|
pTrace = pTraceBufferHead, i = 0;
|
|
i < LastEvents;
|
|
i++)
|
|
{
|
|
EthernetType = 0;
|
|
if (pTrace != pTraceBufferBase)
|
|
{
|
|
pTrace--;
|
|
}
|
|
else
|
|
{
|
|
pTrace = pTraceBufferTop - 2;
|
|
}
|
|
|
|
if (pTrace->Event == LLC_TRACE_END_OF_DATA)
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
// The highest bit is set in the adapter number, if
|
|
// it's a token-ring adapter.
|
|
//
|
|
if (pTrace->AdapterNumber & 0x80)
|
|
{
|
|
IsEthernet = FALSE;
|
|
}
|
|
else
|
|
IsEthernet = TRUE;
|
|
|
|
pDlcHeader = &pTrace->Buffer[14];
|
|
if (IsEthernet)
|
|
{
|
|
pSrc = &pTrace->Buffer[6];
|
|
pDest = pTrace->Buffer;
|
|
|
|
//
|
|
// Discard all non ieee 802.2 frames, but support
|
|
// the SNA dix headers.
|
|
//
|
|
if (pTrace->Buffer[12] == 0x80 &&
|
|
pTrace->Buffer[13] == 0xd5)
|
|
{
|
|
pDlcHeader = &pTrace->Buffer[17];
|
|
}
|
|
else if (pTrace->Buffer[12] >= 64)
|
|
{
|
|
EthernetType = (USHORT)
|
|
(((USHORT)pTrace->Buffer[12] << 8) +
|
|
pTrace->Buffer[13]
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSrc = &pTrace->Buffer[8];
|
|
pDest = &pTrace->Buffer[2];
|
|
|
|
//
|
|
// Skip the source souting info
|
|
//
|
|
if (pTrace->Buffer[8] & 0x80)
|
|
pDlcHeader += pTrace->Buffer[14] & 0x1f;
|
|
|
|
//
|
|
// Discard all non ieee 802.2 frames
|
|
//
|
|
if (pTrace->Buffer[1] != 0x40)
|
|
continue;
|
|
}
|
|
memcpy( (PUCHAR)&LlcHeader, pDlcHeader, 4 );
|
|
|
|
if (AdapterNumber != -1 &&
|
|
AdapterNumber != ((UINT)pTrace->AdapterNumber & 0x7f))
|
|
continue;
|
|
|
|
if (pTrace->Event == LLC_TRACE_SEND_FRAME)
|
|
{
|
|
if (pRemoteNode != NULL && memcmp( pDest, pRemoteNode, 6))
|
|
continue;
|
|
pTmp = pDest;
|
|
pDest = pSrc;
|
|
pSrc = pTmp;
|
|
pDirection = "->";
|
|
}
|
|
else if (pTrace->Event == LLC_TRACE_RECEIVE_FRAME)
|
|
{
|
|
if (pRemoteNode != NULL && memcmp( pSrc, pRemoteNode, 6))
|
|
continue;
|
|
pDirection = "<-";
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
if (EthernetType != 0)
|
|
{
|
|
printf(
|
|
"%-4u %-9lu %3u %12s %2s %12s DIX type %x\n",
|
|
i,
|
|
pTrace->TimerTick,
|
|
pTrace->AdapterNumber & 0x7f,
|
|
GetHexString( pDest, 6, Buffer1 ),
|
|
pDirection,
|
|
GetHexString( pSrc, 6, Buffer2 ),
|
|
EthernetType
|
|
);
|
|
|
|
}
|
|
//
|
|
// Handle first I frames, they are the most common!
|
|
//
|
|
else if (!(LlcHeader.U.Command & LLC_NOT_I_FRAME))
|
|
{
|
|
PollFinal = ' ';
|
|
if (LlcHeader.I.Ssap & LLC_SSAP_RESPONSE)
|
|
{
|
|
CmdResp = 'r';
|
|
if (LlcHeader.I.Nr & LLC_I_S_POLL_FINAL)
|
|
{
|
|
PollFinal = 'f';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CmdResp = 'c';
|
|
if (LlcHeader.I.Nr & LLC_I_S_POLL_FINAL)
|
|
{
|
|
PollFinal = 'p';
|
|
}
|
|
}
|
|
pCommand = "I";
|
|
printf(
|
|
"%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c %-3u %-3u\n",
|
|
i,
|
|
pTrace->TimerTick,
|
|
pTrace->AdapterNumber & 0x7f,
|
|
GetHexString( pDest, 6, Buffer1 ),
|
|
pDirection,
|
|
GetHexString( pSrc, 6, Buffer2 ),
|
|
LlcHeader.U.Dsap,
|
|
LlcHeader.U.Ssap & 0xfe,
|
|
pCommand,
|
|
CmdResp,
|
|
PollFinal,
|
|
LlcHeader.I.Nr >> 1,
|
|
LlcHeader.I.Ns >> 1
|
|
);
|
|
}
|
|
else if (!(LlcHeader.S.Command & LLC_U_TYPE_BIT))
|
|
{
|
|
//
|
|
// Handle S (Supervisory) commands (RR, REJ, RNR)
|
|
//
|
|
switch (LlcHeader.S.Command)
|
|
{
|
|
case LLC_RR:
|
|
pCommand = "RR";
|
|
break;
|
|
case LLC_RNR:
|
|
pCommand = "RNR";
|
|
break;
|
|
case LLC_REJ:
|
|
pCommand = "REJ";
|
|
break;
|
|
default:
|
|
pCommand = "INV";
|
|
break;
|
|
};
|
|
//
|
|
// The valid frames has modulo: Va <= Nr <= Vs,
|
|
// Ie. the Receive sequence number should belong to
|
|
// a frame that has been sent but not acknowledged.
|
|
// The extra check in the beginning makes the most common
|
|
// code path faster: usually the other is waiting the next frame.
|
|
// (keep the rest code the same as in I path, even a very
|
|
// primitive optimizer will puts these code paths together)
|
|
//
|
|
PollFinal = ' ';
|
|
if (LlcHeader.S.Ssap & LLC_SSAP_RESPONSE)
|
|
{
|
|
CmdResp = 'r';
|
|
if (LlcHeader.S.Nr & LLC_I_S_POLL_FINAL)
|
|
{
|
|
PollFinal = 'f';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CmdResp = 'c';
|
|
if (LlcHeader.S.Nr & LLC_I_S_POLL_FINAL)
|
|
{
|
|
PollFinal = 'p';
|
|
}
|
|
}
|
|
printf(
|
|
"%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c %-3u\n",
|
|
i,
|
|
pTrace->TimerTick,
|
|
pTrace->AdapterNumber & 0x7f,
|
|
GetHexString( pDest, 6, Buffer1 ),
|
|
pDirection,
|
|
GetHexString( pSrc, 6, Buffer2 ),
|
|
LlcHeader.U.Dsap,
|
|
LlcHeader.U.Ssap & 0xfe,
|
|
pCommand,
|
|
CmdResp,
|
|
PollFinal,
|
|
LlcHeader.I.Nr >> 1
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Handle U (Unnumbered) command frames
|
|
// (FRMR, DM, UA, DISC, SABME, XID, TEST)
|
|
switch (LlcHeader.U.Command & ~LLC_U_POLL_FINAL)
|
|
{
|
|
case LLC_UI:
|
|
pCommand = "UI";
|
|
break;
|
|
case LLC_DISC:
|
|
pCommand = "DISC";
|
|
break;
|
|
case LLC_SABME:
|
|
pCommand = "SABME";
|
|
break;
|
|
case LLC_DM:
|
|
pCommand = "DM";
|
|
break;
|
|
case LLC_UA:
|
|
pCommand = "UA";
|
|
break;
|
|
case LLC_FRMR:
|
|
pCommand = "FRMR";
|
|
break;
|
|
case LLC_TEST:
|
|
pCommand = "TEST";
|
|
break;
|
|
case LLC_XID:
|
|
pCommand = "XID";
|
|
break;
|
|
default:
|
|
pCommand = "INV";
|
|
break;
|
|
};
|
|
//
|
|
// We set an uniform poll/final bit for procedure call
|
|
//
|
|
PollFinal = ' ';
|
|
if (LlcHeader.U.Command & LLC_U_POLL_FINAL)
|
|
{
|
|
if (LlcHeader.U.Ssap & 1)
|
|
{
|
|
PollFinal = 'f';
|
|
}
|
|
else
|
|
{
|
|
PollFinal = 'p';
|
|
}
|
|
}
|
|
if (LlcHeader.U.Ssap & 1)
|
|
{
|
|
CmdResp = 'r';
|
|
}
|
|
else
|
|
{
|
|
CmdResp = 'c';
|
|
}
|
|
printf(
|
|
"%-4u %-9lu %3u %12s %2s %12s %-2x %-2x %5s-%c%c\n",
|
|
i,
|
|
pTrace->TimerTick,
|
|
pTrace->AdapterNumber & 0x7f,
|
|
GetHexString( pDest, 6, Buffer1 ),
|
|
pDirection,
|
|
GetHexString( pSrc, 6, Buffer2 ),
|
|
LlcHeader.U.Dsap,
|
|
LlcHeader.U.Ssap & 0xfe,
|
|
pCommand,
|
|
CmdResp,
|
|
PollFinal
|
|
);
|
|
}
|
|
}
|
|
RELEASE_SPIN_LOCK( &TraceLock );
|
|
}
|
|
|
|
|
|
UCHAR GetHexDigit(
|
|
UINT Ch
|
|
)
|
|
{
|
|
if (Ch <= 9)
|
|
return (UCHAR)('0' + (UCHAR)Ch);
|
|
else
|
|
return (UCHAR)('A' + (UCHAR)Ch - 10);
|
|
}
|
|
|
|
PUCHAR
|
|
GetHexString(
|
|
PUCHAR pDest,
|
|
UINT Length,
|
|
PUCHAR Buffer
|
|
)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < (Length * 2); i += 2)
|
|
{
|
|
Buffer[i] = GetHexDigit( *pDest >> 4 );
|
|
Buffer[i+1] = GetHexDigit( *pDest & 0x0f );
|
|
pDest++;
|
|
}
|
|
Buffer[i] = 0;
|
|
return Buffer;
|
|
}
|
|
|
|
|
|
VOID
|
|
LlcTraceDumpAndReset(
|
|
IN UINT LastEvents,
|
|
IN UINT AdapterNumber,
|
|
IN PUCHAR pRemoteNode
|
|
)
|
|
{
|
|
LlcTraceDump( LastEvents, AdapterNumber, pRemoteNode );
|
|
ACQUIRE_SPIN_LOCK( &TraceLock );
|
|
if ((ULONG)(&pTraceBufferHead[1]) >= (ULONG)pTraceBufferTop)
|
|
{
|
|
pTraceBufferHead = (PLLC_TRACE_HEADER)pTraceBufferBase;
|
|
}
|
|
else
|
|
pTraceBufferHead++;
|
|
RELEASE_SPIN_LOCK( &TraceLock );
|
|
}
|
|
#endif
|
|
#endif // TRACE_ENABLED
|
|
|
|
|