windows-nt/Source/XPSP1/NT/net/nwlink/kdext/nbext.c
2020-09-26 16:20:57 +08:00

1349 lines
30 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
nbext.c
Abstract:
This file contains kernel debugger extensions for examining the
NB structure.
Author:
Munil Shah (munils) 18-May-1995
Environment:
User Mode
--*/
#include "precomp.h"
#pragma hdrstop
#include "isn.h"
#include "isnnb.h"
#include "zwapi.h"
#include "config.h"
#include "nbitypes.h"
PCHAR HandlerNames[] = { "Connection", "Disconnect", "Error", "Receive", "ReceiveDatagram", "ExpeditedData" };
INT NumArgsRead = 0;
//
// Local function prototypes
//
VOID
DumpAddrFile(
ULONG AddrFileToDump
);
VOID
DumpAddrObj(
ULONG AddrObjToDump
);
VOID
DumpConn(
ULONG ConnToDump,
BOOLEAN Full
);
VOID
Dumpdevice(
ULONG deviceToDump,
BOOLEAN Full
);
VOID
DumpSPacketList(
ULONG _objAddr,
ULONG MaxCount,
BOOLEAN Full
);
///////////////////////////////////////////////////////////////////////
// ADDRESS_FILE
//////////////////////////////////////////////////////////////////////
#define _obj addrfile
#define _objAddr AddrFileToDump
#define _objType ADDRESS_FILE
//
// Exported functions
//
DECLARE_API( nbaddrfile )
/*++
Routine Description:
Dumps the most important fields of the specified ADDRESS_FILE object
Arguments:
args - Address of args string
Return Value:
None
--*/
{
ULONG addrFileToDump = 0;
if (!*args) {
dprintf("No address_file object specified\n");
}
else {
NumArgsRead = sscanf(args, "%lx", &addrFileToDump);
if (NumArgsRead) {
DumpAddrFile(addrFileToDump);
}
else {
dprintf("Bad argument for address_file object <%s>\n", args);
}
}
return;
}
//
// Local functions
//
VOID
DumpAddrFile(
ULONG AddrFileToDump
)
/*++
Routine Description:
Dumps the fields of the specified ADDRESS_FILE object
Arguments:
AddrFileToDump - The ADDRESS_FILE object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
ADDRESS_FILE addrfile;
ULONG result;
UCHAR i;
if (!ReadMemory(
AddrFileToDump,
&addrfile,
sizeof(addrfile),
&result
)
)
{
dprintf("%08lx: Could not read address object\n", AddrFileToDump);
return;
}
if (addrfile.Type != NB_ADDRESSFILE_SIGNATURE) {
dprintf("Signature does not match, probably not an address object\n");
return;
}
dprintf("NBI AddressFile:\n");
PrintStart
PrintXUChar(State);
PrintXULong(ReferenceCount);
PrintPtr(FileObject);
PrintPtr(Address);
PrintPtr(OpenRequest);
PrintPtr(CloseRequest);
PrintLL(Linkage);
PrintLL(ConnectionDatabase);
PrintLL(ReceiveDatagramQueue);
PrintEnd
for ( i= TDI_EVENT_CONNECT; i < TDI_EVENT_SEND_POSSIBLE ; i++ ) {
dprintf(" %sHandler = %lx, Registered = %s, Context = %lx\n",
HandlerNames[i], addrfile.Handlers[i], PRINTBOOL(addrfile.RegisteredHandler[i]),addrfile.HandlerContexts[i] );
}
return;
}
///////////////////////////////////////////////////////////////////////
// ADDRESS
//////////////////////////////////////////////////////////////////////
#undef _obj
#undef _objAddr
#undef _objType
#define _obj addrobj
#define _objAddr AddrObjToDump
#define _objType ADDRESS
DECLARE_API( nbaddr )
/*++
Routine Description:
Dumps the most important fields of the specified ADDRESS object
Arguments:
args - Address of args string
Return Value:
None
--*/
{
ULONG addrobjToDump = 0;
if (!*args) {
dprintf("No address object specified\n");
}
else {
NumArgsRead = sscanf(args, "%lx", &addrobjToDump);
if (NumArgsRead) {
DumpAddrObj(addrobjToDump);
}
else {
dprintf("Bad argument for address object <%s>\n", args);
}
}
return;
}
//
// Local functions
//
VOID
PrintNetbiosName(
PUCHAR Name
)
/*++
Routine Description:
Prints out a Netbios name.
Arguments:
Name - The array containing the name to print.
Return Value:
None
--*/
{
ULONG i;
for (i=0; i<16; i++) {
dprintf("%c", Name[i]);
}
return;
}
VOID
DumpAddrObj(
ULONG AddrObjToDump
)
/*++
Routine Description:
Dumps the fields of the specified ADDRESS object
Arguments:
AddrObjToDump - The address object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
ADDRESS addrobj;
ULONG result;
NBI_NETBIOS_ADDRESS nbaddr;
if (!ReadMemory(
AddrObjToDump,
&addrobj,
sizeof(addrobj),
&result
)
)
{
dprintf("%08lx: Could not read address object\n", AddrObjToDump);
return;
}
if (addrobj.Type != NB_ADDRESS_SIGNATURE) {
dprintf("Signature does not match, probably not an address object\n");
return;
}
dprintf("NB Address:\n");
PrintStart
PrintXULong(State);
PrintXULong(Flags);
PrintULong(ReferenceCount);
PrintLL(Linkage);
PrintEnd
// Print the netbiosname info.
PrintFieldName("NetbiosName");
PrintNetbiosName(addrobj.NetbiosAddress.NetbiosName); dprintf("\n");
dprintf(" %25s = 0x%8x %25s = %10s\n", "NetbiosNameType",addrobj.NetbiosAddress.NetbiosNameType,"Broadcast",PRINTBOOL(addrobj.NetbiosAddress.Broadcast));
PrintStart
PrintLL(AddressFileDatabase);
PrintAddr(RegistrationTimer);
PrintXULong(RegistrationCount);
PrintPtr(SecurityDescriptor);
PrintEnd
return;
}
///////////////////////////////////////////////////////////////////////
// CONNECTION_FILE
//////////////////////////////////////////////////////////////////////
#undef _obj
#undef _objAddr
#undef _objType
#define _obj conn
#define _objAddr ConnToDump
#define _objType CONNECTION
DECLARE_API( nbconn )
/*++
Routine Description:
Dumps the most important fields of the specified CONNECTION object
Arguments:
args - Address
Return Value:
None
--*/
{
ULONG connToDump = 0;
if (!*args) {
dprintf("No conn specified\n");
}
else {
NumArgsRead = sscanf(args, "%lx", &connToDump);
if (NumArgsRead) {
DumpConn(connToDump, FALSE);
}
else {
dprintf("Bad argument for conn object <%s>\n", args);
}
}
return;
}
DECLARE_API( nbconnfull )
/*++
Routine Description:
Dumps all of the fields of the specified CONNECTION object
Arguments:
args - Address
Return Value:
None
--*/
{
ULONG connToDump = 0;
if (!*args) {
dprintf("No conn specified\n");
}
else {
NumArgsRead = sscanf(args, "%lx", &connToDump);
if (NumArgsRead) {
DumpConn(connToDump, TRUE);
}
else {
dprintf("Bad argument for conn object <%s>\n", args);
}
}
return;
}
//
// Local functions
//
VOID
printSendPtr(
PSEND_POINTER SendPtr,
PSEND_POINTER UnAckedPtr
)
{
dprintf(" CurrentSend UnackedSend\n");
dprintf(" MessageOffset 0x%-8lx 0x%-8lx\n", SendPtr->MessageOffset,UnAckedPtr->MessageOffset);
dprintf(" Request 0x%-8lx 0x%-8lx\n", SendPtr->Request,UnAckedPtr->Request);
dprintf(" Buffer 0x%-8lx 0x%-8lx\n", SendPtr->Buffer,UnAckedPtr->Buffer);
dprintf(" BufferOffset 0x%-8lx 0x%-8lx\n", SendPtr->BufferOffset,UnAckedPtr->BufferOffset);
dprintf(" SendSequence 0x%-8x 0x%-8x\n", SendPtr->SendSequence,UnAckedPtr->SendSequence);
}
VOID
printRcvPtr(
PRECEIVE_POINTER CurrentPtr,
PRECEIVE_POINTER PreviousPtr
)
{
dprintf(" CurrentReceive PreviousReceive\n");
dprintf(" MessageOffset 0x%-8lx 0x%-8lx\n", CurrentPtr->MessageOffset,PreviousPtr->MessageOffset);
dprintf(" Offset 0x%-8lx 0x%-8lx\n", CurrentPtr->Offset,PreviousPtr->Offset);
dprintf(" Buffer 0x%-8lx 0x%-8lx\n", CurrentPtr->Buffer,PreviousPtr->Buffer);
dprintf(" BufferOffset 0x%-8lx 0x%-8lx\n", CurrentPtr->BufferOffset,PreviousPtr->BufferOffset);
}
VOID
DumpConn(
ULONG ConnToDump,
BOOLEAN Full
)
/*++
Routine Description:
Dumps the fields of the specified CONNECTION object
Arguments:
ConnToDump - The conn object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
CONNECTION conn;
ULONG result;
if (!ReadMemory(
ConnToDump,
&conn,
sizeof(conn),
&result
)
)
{
dprintf("%08lx: Could not read conn\n", ConnToDump);
return;
}
if (conn.Type != NB_CONNECTION_SIGNATURE) {
dprintf("Signature does not match, probably not a conn\n");
return;
}
dprintf("NBI Connection General:\n");
PrintStart
PrintXULong(State);
PrintXULong(SubState);
PrintXULong(ReceiveState);
PrintXULong(ReferenceCount);
PrintXUShort(LocalConnectionId);
PrintXUShort(RemoteConnectionId);
PrintAddr(LocalTarget);
PrintAddr(RemoteHeader);
PrintPtr(Context);
PrintPtr(AddressFile);
PrintXULong(AddressFileLinked);
PrintPtr(NextConnection);
PrintEnd
dprintf(" RemoteName = ");PrintNetbiosName((PUCHAR)conn.RemoteName);dprintf("\n");
dprintf("\n\nConnection Send Info:\n");
PrintStart
PrintIrpQ(SendQueue);
PrintXUShort(SendWindowSequenceLimit);
PrintXUShort(SendWindowSize);
PrintEnd
printSendPtr( &conn.CurrentSend, &conn.UnAckedSend );
if( Full ) {
PrintStart
PrintXUShort(MaxSendWindowSize);
PrintBool(RetransmitThisWindow);
PrintBool(SendWindowIncrease);
PrintBool(ResponseTimeout);
PrintBool(SendBufferInUse);
PrintPtr(FirstMessageRequest);
PrintPtr(LastMessageRequest);
PrintXULong(MaximumPacketSize);
PrintXULong(CurrentMessageLength);
PrintEnd
}
dprintf("\n\nConnection Receive Info:\n");
PrintStart
PrintIrpQ(ReceiveQueue);
PrintXUShort(ReceiveSequence);
PrintXUShort(ReceiveWindowSize);
PrintXUShort(LocalRcvSequenceMax);
PrintXUShort(RemoteRcvSequenceMax);
PrintPtr(ReceiveRequest);
PrintXULong(ReceiveLength);
PrintEnd
printRcvPtr( &conn.CurrentReceive, &conn.PreviousReceive );
if( Full ) {
PrintStart
PrintXULong(ReceiveUnaccepted);
PrintXULong(CurrentIndicateOffset);
PrintBool(NoPiggybackHeuristic);
PrintBool(PiggybackAckTimeout);
PrintBool(CurrentReceiveNoPiggyback);
PrintBool(DataAckPending);
PrintEnd
}
if( Full ) {
PrintStart
PrintPtr(ListenRequest);
PrintPtr(AcceptRequest);
PrintPtr(ClosePending);
PrintPtr(DisassociatePending);
PrintPtr(DisconnectWaitRequest);
PrintPtr(DisconnectRequest);
PrintPtr(ConnectRequest);
PrintEnd
PrintStart
PrintLL(PacketizeLinkage);
PrintBool(OnPacketizeQueue);
PrintLL(WaitPacketLinkage);
PrintBool(OnWaitPacketQueue);
PrintLL(DataAckLinkage);
PrintBool(OnDataAckQueue);
PrintBool(IgnoreNextDosProbe);
PrintXULong(NdisSendsInProgress);
PrintLL(NdisSendQueue);
PrintPtr(NdisSendReference);
PrintXULong(Retries);
PrintXULong(Status);
PrintBool(FindRouteInProgress);
PrintXULong(CanBeDestroyed);
PrintBool(OnShortList);
PrintLL(ShortList);
PrintLL(LongList);
PrintBool(OnLongList);
PrintXULong(BaseRetransmitTimeout);
PrintXULong(CurrentRetransmitTimeout);
PrintXULong(WatchdogTimeout);
PrintXULong(Retransmit);
PrintXULong(Watchdog);
PrintEnd
PrintStart
PrintAddr(ConnectionInfo);
PrintAddr(Timer);
PrintAddr(FindRouteRequest);
PrintPtr(NextConnection);
PrintAddr(SessionInitAckData);
PrintXULong(SessionInitAckDataLength);
PrintAddr(SendPacket);
PrintAddr(SendPacketHeader);
PrintBool(SendPacketInUse);
PrintAddr(LineInfo);
#ifdef RSRC_TIMEOUT_DBG
PrintXULong(FirstMessageRequestTime.HighPart);
PrintXULong(FirstMessageRequestTime.LowPart);
#endif RSRC_TIMEOUT_DBG
}
return;
}
///////////////////////////////////////////////////////////////////////
// DEVICE
//////////////////////////////////////////////////////////////////////
#undef _obj
#undef _objAddr
#undef _objType
#define _obj device
#define _objAddr deviceToDump
#define _objType DEVICE
//
// Exported functions
//
DECLARE_API( nbdev )
/*++
Routine Description:
Dumps the most important fields of the specified DEVICE_CONTEXT object
Arguments:
args - Address
Return Value:
None
--*/
{
ULONG deviceToDump = 0;
ULONG pDevice = 0;
ULONG result;
if (!*args) {
pDevice = GetExpression( "nwlnknb!NbiDevice" );
if ( !pDevice ) {
dprintf("Could not get NbiDevice, Try !reload\n");
return;
} else {
if (!ReadMemory(pDevice,
&deviceToDump,
sizeof(deviceToDump),
&result
)
)
{
dprintf("%08lx: Could not read device address\n", pDevice);
return;
}
}
}
else {
NumArgsRead = sscanf(args, "%lx", &deviceToDump);
if (0 == NumArgsRead) {
dprintf("Bad argument for NbiDevice <%s>\n", args);
return;
}
}
Dumpdevice(deviceToDump, FALSE);
return;
}
DECLARE_API( nbdevfull )
/*++
Routine Description:
Dumps all of the fields of the specified DEVICE_CONTEXT object
Arguments:
args - Address
Return Value:
None
--*/
{
ULONG deviceToDump = 0;
ULONG pDevice = 0;
ULONG result;
if (!*args) {
pDevice = GetExpression( "nwlnknb!NbiDevice" );
if ( !pDevice ) {
dprintf("Could not get NbiDevice, Try !reload\n");
return;
} else {
if (!ReadMemory(pDevice,
&deviceToDump,
sizeof(deviceToDump),
&result
)
)
{
dprintf("%08lx: Could not read device address\n", pDevice);
return;
}
}
}
else {
NumArgsRead = sscanf(args, "%lx", &deviceToDump);
if (0 == NumArgsRead) {
dprintf("Bad argument for NbiDevice <%s>\n", args);
return;
}
}
Dumpdevice(deviceToDump, TRUE);
return;
}
//
// Local functions
//
VOID
Dumpdevice(
ULONG deviceToDump,
BOOLEAN Full
)
/*++
Routine Description:
Dumps the fields of the specified DEVICE_CONTEXT structure
Arguments:
deviceToDump - The device context object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
DEVICE device;
ULONG result;
if (!ReadMemory(
deviceToDump,
&device,
sizeof(device),
&result
)
)
{
dprintf("%08lx: Could not read device context\n", deviceToDump);
return;
}
if (device.Type != NB_DEVICE_SIGNATURE) {
dprintf("Signature does not match, probably not a device object %lx\n",deviceToDump);
return;
}
dprintf("Device General Info:\n");
PrintStart
PrintXUChar(State);
PrintXULong(ReferenceCount);
PrintXUShort(MaximumNicId);
PrintXULong(MemoryUsage);
PrintXULong(MemoryLimit);
PrintXULong(AddressCount);
PrintXULong(AllocatedSendPackets);
PrintXULong(AllocatedReceivePackets);
PrintXULong(AllocatedReceiveBuffers);
PrintXULong(MaxReceiveBuffers);
PrintLL(AddressDatabase);
PrintL(SendPacketList);
PrintL(ReceivePacketList);
PrintLL(GlobalReceiveBufferList);
PrintLL(GlobalSendPacketList);
PrintLL(GlobalReceivePacketList);
PrintLL(GlobalReceiveBufferList);
PrintLL(SendPoolList);
PrintLL(ReceivePoolList);
PrintLL(ReceiveBufferPoolList);
PrintLL(ReceiveCompletionQueue);
PrintLL(WaitPacketConnections);
PrintLL(PacketizeConnections);
PrintLL(WaitingConnects);
PrintLL(WaitingDatagrams);
PrintLL(WaitingAdapterStatus);
PrintLL(WaitingNetbiosFindName);
PrintLL(ActiveAdapterStatus);
PrintLL(ReceiveDatagrams);
PrintLL(ConnectIndicationInProgress);
PrintLL(ListenQueue);
PrintLL(WaitingFindNames);
if ( Full ) {
PrintStart
PrintBool(UnloadWaiting);
PrintBool(DataAckQueueChanged);
PrintBool(ShortListActive);
PrintBool(DataAckActive);
PrintBool(TimersInitialized);
PrintBool(ProcessingShortTimer);
PrintAddr(ShortTimerStart);
PrintAddr(ShortTimer);
PrintXULong(ShortAbsoluteTime);
PrintAddr(LongTimer);
PrintXULong(LongAbsoluteTime);
PrintLL(ShortList);
PrintLL(LongList);
PrintAddr(TimerLock);
PrintEnd
}
if ( Full ) {
PrintStart
PrintXUShort(FindNameTime);
PrintBool(FindNameTimerActive);
PrintAddr(FindNameTimer);
PrintXULong(FindNameTimeout);
PrintXULong(FindNamePacketCount);
PrintLL(WaitingFindNames);
PrintEnd
PrintStart
PrintXULong(AckDelayTime );
PrintXULong(AckWindow );
PrintXULong(AckWindowThreshold );
PrintXULong(EnablePiggyBackAck );
PrintXULong(Extensions );
PrintXULong(RcvWindowMax );
PrintXULong(BroadcastCount );
PrintXULong(BroadcastTimeout );
PrintXULong(ConnectionCount );
PrintXULong(ConnectionTimeout );
PrintXULong(InitPackets );
PrintXULong(MaxPackets );
PrintXULong(InitialRetransmissionTime);
PrintXULong(Internet );
PrintXULong(KeepAliveCount );
PrintXULong(KeepAliveTimeout );
PrintXULong(RetransmitMax );
PrintXULong(RouterMtu);
PrintEnd
}
PrintPtr(NameCache);
PrintXUShort(CacheTimeStamp);
PrintAddr(Bind);
PrintAddr( ConnectionHash);
PrintAddr( ConnectionlessHeader );
PrintAddr( UnloadEvent );
PrintAddr(Information);
PrintAddr(Statistics);
PrintEnd
return;
}
//////////////Send Packet////////////
#undef _obj
#undef _objAddr
#undef _objType
#define _obj spacket
#define _objAddr spacketToDump
#define _objType NB_SEND_RESERVED
//
// Exported functions
//
DECLARE_API( nbspacketlist )
/*++
Routine Description:
Arguments:
args - Address
Return Value:
None
--*/
{
DEVICE NbiDevice;
DEVICE *pDevice;
PNB_SEND_RESERVED pFirstPacket;
ULONG result;
char szPacketCount[MAX_LIST_VARIABLE_NAME_LENGTH + 1];
ULONG MaxCount = 0; // default value means dump all packets!
if ((!*args) || (*args && *args == '-'))
{
//
// No initial packet has been defined, so set the initial packet
// from the global pool list
//
if (!(pDevice = (DEVICE *) GetExpression("nwlnknb!NbiDevice")))
{
dprintf("Could not get NbiDevice, Try !reload\n");
return;
}
if (!ReadMemory((ULONG) pDevice, &pDevice, sizeof(DEVICE *), &result))
{
dprintf("%08lx: Could not read device address\n", pDevice);
return;
}
if (!ReadMemory((ULONG) pDevice, &NbiDevice, sizeof(DEVICE), &result))
{
dprintf("%08lx: Could not read device information\n", pDevice);
return;
}
//
// Now, compute the address of the first packet from the GlobalSendPacketList field
//
if (NbiDevice.GlobalSendPacketList.Flink == &pDevice->GlobalSendPacketList)
{
dprintf("%08lx: Device GlobalSendPacketList @%08lx is empty\n", &pDevice->GlobalSendPacketList);
return;
}
pFirstPacket = CONTAINING_RECORD (NbiDevice.GlobalSendPacketList.Flink, NB_SEND_RESERVED, GlobalLinkage);
}
else
{
//
// Read in the address for the first packet
//
NumArgsRead = sscanf(args, "%lx", &pFirstPacket);
if (0 == NumArgsRead) {
dprintf("Bad argument for FirstPacket <%s>\n", args);
return;
}
}
if (ReadArgsForTraverse (args, szPacketCount))
{
NumArgsRead = sscanf(szPacketCount, "%lx", &MaxCount);
if (0 == NumArgsRead) {
dprintf("Bad argument for PacketCount <%s>\n", szPacketCount);
return;
}
}
DumpSPacketList((ULONG) pFirstPacket, MaxCount, FALSE);
return;
}
//
// Local functions
//
ULONG
DumpSPacket(
ULONG _objAddr,
BOOLEAN Full
)
{
_objType _obj;
ULONG result;
ULONG next;
if (!ReadMemory(
_objAddr,
&_obj,
sizeof(_obj),
&result
)
)
{
dprintf("%08lx: Could not read spacket\n", spacketToDump);
return 0;
}
dprintf( "%s @ %08lx\n", "Send Packet", _objAddr );
PrintStartStruct();
PrintBool(SendInProgress);
PrintXUChar(Type);
PrintBool(OwnedByConnection);
PrintPtr(Header);
switch(_obj.Type) {
case SEND_TYPE_DATAGRAM:
PrintPtr(u.SR_DG.DatagramRequest);
PrintPtr(u.SR_DG.AddressFile);
PrintPtr(u.SR_DG.Cache);
break;
case SEND_TYPE_NAME_FRAME:
PrintPtr(u.SR_NF.Address);
PrintPtr(u.SR_NF.Request);
PrintPtr(u.SR_NF.AddressFile);
break;
case SEND_TYPE_FIND_NAME:
PrintAddr(u.SR_FN.NetbiosName);
break;
case SEND_TYPE_SESSION_NO_DATA:
PrintPtr(u.SR_CO.Connection);
break;
case SEND_TYPE_SESSION_DATA:
PrintPtr(u.SR_CO.Connection);
PrintPtr(u.SR_CO.Request);
break;
case SEND_TYPE_SESSION_INIT:
break;
case SEND_TYPE_STATUS_QUERY:
case SEND_TYPE_STATUS_RESPONSE:
break;
}
PrintEndStruct();
return( (ULONG) CONTAINING_RECORD( _obj.GlobalLinkage.Flink, _objType, GlobalLinkage));
}
VOID
DumpSPacketList(
ULONG pFirstPacket,
ULONG MaxCount,
BOOLEAN Full
)
/*++
Routine Description:
Dumps the fields of the specified DEVICE_CONTEXT structure
Arguments:
deviceToDump - The device context object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
ULONG nextSPacket;
ULONG count = 0;
nextSPacket = pFirstPacket;
do
{
nextSPacket = DumpSPacket( nextSPacket, Full );
if (++count == MaxCount)
{
break;
}
} while( nextSPacket && (nextSPacket != pFirstPacket ));
dprintf("\nDumped %d Packets (%s)\n", count, (MaxCount ? "MaxCount specified" : "all packets"));
return;
}
///////////////////////////////////////////////////////////////////////
// CACHE
//////////////////////////////////////////////////////////////////////
VOID
DumpLocalAddresses(
PLIST_ENTRY pHead
)
/*++
Routine Description:
Dumps the fields of the specified DEVICE_CONTEXT structure
Arguments:
deviceToDump - The device context object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
PLIST_ENTRY pEntry;
ADDRESS *pAddress;
ADDRESS Address;
ULONG Result;
ULONG Count = 0;
dprintf("\nDumping Local Address Names:\n");
dprintf("----------------------------\n");
if (!ReadMemory ((ULONG) pHead, &pEntry, sizeof(PLIST_ENTRY), &Result))
{
dprintf("%p: Could not read pHead info\n", pHead);
return;
}
dprintf("RefC <Address> => <Name > | State |NTFlag| Flags | BCast\n");
dprintf("-------------------------------------------------------------------------------\n");
while (pEntry != pHead)
{
pAddress = CONTAINING_RECORD (pEntry, ADDRESS, Linkage);
if (!ReadMemory((ULONG) pAddress, &Address, sizeof(ADDRESS), &Result))
{
dprintf("%p: Could not read Address information\n", pAddress);
return;
}
Count++;
pEntry = Address.Linkage.Flink;
dprintf("[%d]\t<%p> => ", Address.ReferenceCount, pAddress);
dprintf("<%-15.15s:%2x> | %8x | %2x | %8x | %s\n",
Address.NetbiosAddress.NetbiosName,
Address.NetbiosAddress.NetbiosName[15],
Address.State,
Address.NameTypeFlag,
Address.Flags,
(Address.NetbiosAddress.Broadcast ? "Y" : "N"));
}
dprintf("\nDumped %d Addresses\n", Count);
return;
}
VOID
DumpRemoteCache(
NETBIOS_CACHE_TABLE *pNameCacheTable,
USHORT CacheTimeStamp
)
/*++
Routine Description:
Dumps the fields of the specified DEVICE_CONTEXT structure
Arguments:
deviceToDump - The device context object to display
Full - Display a partial listing if 0, full listing otherwise.
Return Value:
None
--*/
{
NETBIOS_CACHE_TABLE NameCacheTable;
NETBIOS_CACHE CacheEntry;
NETBIOS_CACHE *pCacheEntry;
PLIST_ENTRY pHead, pEntry;
ULONG HashIndex;
ULONG Result;
ULONG Count = 0;
if (!ReadMemory ((ULONG) pNameCacheTable, &NameCacheTable, sizeof(NETBIOS_CACHE_TABLE), &Result))
{
dprintf("%p: Could not read Remote Name Cache\n", pNameCacheTable);
return;
}
dprintf("Dumping Remote Names (%3d entries, %3d buckets), TimeStamp = %4d, AgeLimit = %4d:\n",
NameCacheTable.CurrentEntries, NameCacheTable.MaxHashIndex, CacheTimeStamp, (600000 / LONG_TIMER_DELTA));
dprintf("-----------------------------------------------------------------------------------\n");
dprintf("[Bkt#] <Address> => <Name > | TimeSt | NetsU | NetsA | RefC | U | FailedOnDownWan\n");
dprintf("------------------------------------------------------------------------------------------------\n");
for (HashIndex = 0; HashIndex < NameCacheTable.MaxHashIndex; HashIndex++)
{
pHead = &pNameCacheTable->Bucket[HashIndex];
if (!ReadMemory ((ULONG) pHead, &pEntry, sizeof(PLIST_ENTRY), &Result))
{
dprintf("%p: Could not Entry ptr\n", pHead);
return;
}
while (pEntry != pHead)
{
pCacheEntry = CONTAINING_RECORD (pEntry, NETBIOS_CACHE, Linkage);
if (!ReadMemory((ULONG) pCacheEntry, &CacheEntry, sizeof(NETBIOS_CACHE), &Result))
{
dprintf("%p: Could not read Remote Name information\n", pCacheEntry);
return;
}
Count++;
pEntry = CacheEntry.Linkage.Flink;
dprintf("[%d]\t<%p> => ", HashIndex, pCacheEntry);
dprintf("<%-15.15s:%2x> | %4d | %4d | %4d | %2d | %s | %s\n",
CacheEntry.NetbiosName,
CacheEntry.NetbiosName[15],
CacheEntry.TimeStamp,
CacheEntry.NetworksUsed,
CacheEntry.NetworksAllocated,
CacheEntry.ReferenceCount,
(CacheEntry.Unique ? "U" : "G"),
(CacheEntry.FailedOnDownWan ? "Y" : "N"));
}
}
dprintf("\nDumped %d Remote names\n", Count);
return;
}
//
// Exported function
//
DECLARE_API( nbcache )
/*++
Routine Description:
Dumps the most important fields of the specified ADDRESS_FILE object
Arguments:
args - Address of args string
Return Value:
None
--*/
{
DEVICE *pDevice;
ULONG Result;
NETBIOS_CACHE_TABLE *pNameCache;
USHORT CacheTimeStamp;
if (!*args)
{
//
// No initial packet has been defined, so set the initial packet
// from the global pool list
//
if (!(pDevice = (DEVICE *) GetExpression("nwlnknb!NbiDevice")))
{
dprintf("Could not get NbiDevice, Try !reload\n");
return;
}
if (!ReadMemory ((ULONG) pDevice, &pDevice, sizeof(DEVICE *), &Result))
{
dprintf("%p: Could not read device address\n", pDevice);
return;
}
}
else
{
NumArgsRead = sscanf(args, "%p", &pDevice);
if (0 == NumArgsRead) {
dprintf("Bad argument for NbiDevice <%s>\n", args);
return;
}
}
DumpLocalAddresses (&pDevice->AddressDatabase);
dprintf ("\n\n");
if (!ReadMemory ((ULONG) &pDevice->NameCache, &pNameCache, sizeof(NETBIOS_CACHE_TABLE *), &Result))
{
dprintf("%p: Could not read NameCache ptr from Device\n", &pDevice->NameCache);
return;
}
if (!ReadMemory ((ULONG) &pDevice->CacheTimeStamp, &CacheTimeStamp, sizeof(USHORT), &Result))
{
dprintf("%p: Could not read CacheTimeStamp value from Device\n", &pDevice->CacheTimeStamp);
return;
}
DumpRemoteCache (pNameCache, CacheTimeStamp);
return;
}