windows-nt/Source/XPSP1/NT/net/dlc/driver/llctrace.c
2020-09-26 16:20:57 +08:00

514 lines
13 KiB
C

/*++
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