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