Network miniports (!ndiskd.*)¶
The !ndiskd commands show what NDIS knows about the guest’s network adapters: each miniport’s state and link, the miniport driver behind it, the filter drivers stacked on it, the protocols bound to it, the OID requests nobody has completed, and the NET_BUFFER_LISTs that carry its frames. They help you when you develop a miniport, filter, or protocol driver, such as NetKVM, the virtio-win driver for virtio-net devices, and an adapter does not come up, stops passing traffic, or does not finish a pause, a reset, or an OID request.
The commands have the names of the commands in WinDbg’s ndiskd extension. They read ndis.sys’s own structures (_NDIS_MINIPORT_BLOCK, _NDIS_M_DRIVER_BLOCK, _NDIS_FILTER_BLOCK, _NDIS_FILTER_DRIVER_BLOCK, _NDIS_PROTOCOL_BLOCK, _NDIS_OPEN_BLOCK, _NDIS_OID_REQUEST, _NET_BUFFER_LIST) with the types in the public PDB of ndis.sys, so they need that PDB, which ntoseye downloads like any other. They read only guest memory, so they work on every backend and in crash dumps.
Miniports¶
!ndiskd.miniports walks ndis.sys’s global list of miniports and shows one line for each miniport:
Miniport Driver State Media Power IfIndex Name
ffffc88844dc5000 VMSNPXY Running Connected 10 Gbps D0 20 Hyper-V Virtual Ethernet Adapter
ffffc8884977f1a0 vmsmp Running Connected 10 Gbps D0 16 Hyper-V Virtual Switch Extension Adapter
ffffc88843a491a0 e1i68x64 Running Connected 1 Gbps D0 6 Intel(R) 82574L Gigabit Network Connection #2
Column |
Meaning |
|---|---|
Miniport |
The address of the miniport’s |
Driver |
The service name of the miniport driver. |
State |
The miniport state: |
Media |
The media connect state, and for a connected adapter, the link speed that the miniport reported. When the receive speed differs from the transmit speed, both show. |
Power |
The device power state of the adapter. |
IfIndex |
The interface index, which |
Name |
The friendly name of the adapter. |
The list includes virtual miniports, such as Hyper-V’s adapters, which have no device of their own.
One miniport¶
!ndiskd.miniport <miniport> shows one miniport. Without an address, it lists the miniports as !ndiskd.miniports does.
miniport ffffc88843a491a0 Intel(R) 82574L Gigabit Network Connection #2
device name \DEVICE\{1C0BA63B-C03E-46A8-9486-643BBA448622}
instance ID PCI\VEN_8086&DEV_10D3&SUBSYS_00008086&REV_00\4&12829b10&0&0014
NDIS version 6.50
driver ffffc888439f2800 e1i68x64 (e1i68x64.sys) v12.19
DRIVER_OBJECT ffffc888439f1b60
adapter context ffffc88843b9d000 (dt e1i68x64!<adapter type> ffffc88843b9d000)
device objects FDO ffffc88843a49050 PDO ffffc888430f5060
state Running
PnP state Started
power D0
media Connected, Full duplex, medium 802_3, physical 802_3
link speed 1 Gbps transmit, 1 Gbps receive
interface IfIndex 6, NetLuid 0x6008006000000, UP
references 12
resets internal 0, miniport 0, last status 0x00000000
pending OID -
pending return NBLs 0
flags 0x2c450218, PnP flags 0x210021
filters (3, top first)
Filter State Driver Context Name
ffffc8884407f300 Running wfplwfs.sys ffffc888440809f0 Intel(R) 82574L Gigabit Network Connection #2-WFP 802.3 MAC Layer LightWeight Filter-0000
ffffc8884407d410 Running pacer.sys ffffc8884403e490 Intel(R) 82574L Gigabit Network Connection #2-QoS Packet Scheduler-0000
ffffc8884407b7d0 Running wfplwfs.sys ffffc8884407d010 Intel(R) 82574L Gigabit Network Connection #2-WFP Native MAC Layer LightWeight Filter-0000
protocol bindings (5, NumOpens 5)
Open Protocol Protocol block Context
ffffc8884711e460 LLTDIO ffffc888471daa90 ffffc888470a55d0
ffffc8884711f010 RSPNDR ffffc888471dba20 ffffc888471dc620
ffffc88845136460 MSLLDP ffffc88845e5ea70 ffffc88845b16790
ffffc888440e98a0 TCPIP ffffc8884330fb80 ffffc888440e8010
ffffc888440848a0 TCPIP6 ffffc88843336620 ffffc88844083010
The first part identifies the adapter:
Driver is the miniport driver’s
_NDIS_M_DRIVER_BLOCK, which!ndiskd.minidrivershows, with the driver’s service, image, and version.Adapter context is the context that your driver passed to
NdisMSetMiniportAttributes, theMiniportAdapterContextthat NDIS gives back to each of your handlers. To see it with your own types, add your driver’s private PDB to the symbol path (see Symbols and source) and run thedtcommand that the line suggests with the name of your adapter structure, for exampledt netkvm!_PARANDIS_ADAPTER <address>for NetKVM.Device objects are the FDO that NDIS created for the adapter and the PDO under it, which you can give to
!devstack. A virtual miniport has neither.
The second part shows the state of the adapter:
State is the NDIS miniport state. A miniport that stays in
Pausinghas not completed its pause: a miniport completes a pause only after it has completed its outstanding sends and the receive NET_BUFFER_LISTs that it indicated have come back to it. A miniport that stays inRestartingorInitializinghas not completed its restart or initialization.PnP state and Power are the PnP state of the device as NDIS tracks it and its device power state.
Resets shows the miniport block’s reset counters,
InternalResetCountandMiniportResetCount, andResetStatus, the NTSTATUS of the last reset.Pending OID is the OID request that NDIS passed to the miniport and that the miniport has not completed yet, with its type, its OID by its
ntddndis.hname, and its buffer. NDIS passes a miniport one OID request at a time, apart from direct OID requests, so a request that stays pending holds up the requests behind it.Pending return NBLs is the miniport block’s
PendingReturnNBLCount, received NET_BUFFER_LISTs whose return to the miniport is pending.Flags are the raw
FlagsandPnPFlagsof the miniport block.
Filters lists the filter modules on the adapter from the top of the stack down, as NDIS links them, with each filter’s state, driver image, and module context (the context that the filter driver passed to NdisFSetAttributes). A filter with an OID request that it has not completed shows the request below the list. ntoseye checks that each filter’s link to the filter above it leads back, and that the walk ends at the miniport’s lowest filter. If a check fails, the list stops there with the reason.
Protocol bindings lists the protocols that opened the adapter, with each protocol’s _NDIS_PROTOCOL_BLOCK and its binding context.
If you give an address that is not on NDIS’s list of miniports, the command shows it only when it has the NDIS object header of a miniport block, for example a miniport that NDIS is removing, and it notes that it is not on the list. Otherwise it says that the address is not a miniport.
Miniport drivers¶
!ndiskd.minidriver lists the miniport drivers that registered with NDIS:
Driver block Service Image NDIS Version Miniports
ffffc888439f2800 e1i68x64 e1i68x64.sys 6.50 12.19 1
ffffc888439388b0 vmsmp vmswitch.sys 6.83 19.0 1
ffffc8884332b620 VMSNPXY VmsProxyHNic.sys 6.81 1.1 1
ffffc8884332c630 VMSNPXY VmsProxyHNic.sys 6.83 1.1 0
NDIS is the NDIS version that the driver registered with, and Version is the driver’s own version from its miniport characteristics. With the address of a driver block, the command shows the driver and its miniports:
driver block ffffc888439f2800
service e1i68x64
image e1i68x64.sys (module e1i68x64)
DRIVER_OBJECT ffffc888439f1b60
NDIS version 6.50
driver version 12.19
miniports (1)
Miniport Driver State Media Power IfIndex Name
ffffc88843a491a0 e1i68x64 Running Connected 1 Gbps D0 6 Intel(R) 82574L Gigabit Network Connection #2
The module is the loaded image that the driver’s code is in, the name that its PDB’s types go by in dt.
Filter modules and filter drivers¶
!ndiskd.filter without an address lists every filter module, on every miniport, from ndis.sys’s global list of filters:
Filter State Driver Miniport Name
ffffa08e68eb3550 Running wfplwfs.sys ffffa08e6898d1a0 Intel(R) 82574L Gigabit Network Connection #2-WFP 802.3 MAC Layer LightWeight Filter-0000
ffffa08e68eaf010 Running pacer.sys ffffa08e6898d1a0 Intel(R) 82574L Gigabit Network Connection #2-QoS Packet Scheduler-0000
ffffa08e68f1f4e0 Running wfplwfs.sys ffffa08e6898d1a0 Intel(R) 82574L Gigabit Network Connection #2-WFP Native MAC Layer LightWeight Filter-0000
With the address of a filter module, it shows the module:
filter ffffa08e68eaf010 Intel(R) 82574L Gigabit Network Connection #2-QoS Packet Scheduler-0000
filter driver ffffa08e686cac40 QoS Packet Scheduler (pacer.sys)
miniport ffffa08e6898d1a0 Intel(R) 82574L Gigabit Network Connection #2
module context ffffa08e68ac3ce0 (dt pacer!<context type> ffffa08e68ac3ce0)
stack higher ffffa08e68eb3550, lower ffffa08e68f1f4e0
state Running
link Connected, 1 Gbps transmit, 1 Gbps receive
IfIndex 26
references 1
dropped 0 receive NBLs, 0 send NBLs, 0 status indications
pending OID -
flags 0x10
Module context is the context that your filter driver passed to
NdisFSetAttributes, theFilterModuleContextthat NDIS gives back to each of your handlers. Read it with your driver’s private PDB anddt.Stack names the filter modules above and below this one on the miniport’s stack. The bottom module’s lower neighbor is the miniport itself.
Link is the link state that the filter last saw indicated from below, which can differ from the miniport’s own while an indication is on its way up.
Dropped counts the NBLs and status indications that NDIS dropped because the filter module was not running. A count that grows while the filter should be running points at a pause or restart that did not finish.
!ndiskd.filterdriver lists the filter drivers that registered with NDIS, with the friendly name, service, and image of each and how many filter modules it has. With the address of a filter driver block, it shows the driver’s unique name (the GUID in its INF), DRIVER_OBJECT, the module its code is in, its driver context, and its filter modules, one for each miniport it is attached to.
Protocols¶
!ndiskd.protocol lists the protocol drivers, such as TCPIP and TCPIP6, with the number of miniports each has bound to. With the address of a protocol block, it shows the protocol and its bindings:
protocol block ffffa08e6830fa40 TCPIP
image tcpip.sys
NDIS version 6.89
driver version 0.0
driver context fffff806264a7dd0
BindAdapterHandlerEx fffff806263824f0 tcpip!FlBindAdapter
flags 0x0
bindings (2)
Open Miniport Context Name
ffffa08e6c6638a0 ffffa08e6f0a5000 ffffa08e6cefb010 Hyper-V Virtual Ethernet Adapter
ffffa08e68f1c8a0 ffffa08e6898d1a0 ffffa08e68f6b850 Intel(R) 82574L Gigabit Network Connection #2
Each binding is an _NDIS_OPEN_BLOCK, with the miniport that the protocol opened and the protocol’s own binding context.
!ndiskd.protocol, !ndiskd.filter, and !ndiskd.filterdriver accept an address that is not on NDIS’s list only when it has the NDIS object header of that kind of block, as !ndiskd.miniport does.
Pending OID requests¶
!ndiskd.oid reads the pending OID request of every miniport and every filter module. For each one that has not completed, it shows whether a miniport or a filter module owns it, the owner’s address and name, and the request as !ndiskd.miniport shows it: the _NDIS_OID_REQUEST, its type, the OID by its ntddndis.h name, and its buffer. When nothing is pending, it says how many it checked:
no pending OID requests on 3 miniports and 7 filter modules
NDIS passes each miniport and filter one OID request at a time, apart from direct OID requests, so a request that stays in this list holds up the ones behind it, and a pause or a reset of that adapter waits for it.
NET_BUFFER_LISTs¶
!ndiskd.nbl decodes a _NET_BUFFER_LIST, for example the one in rdx at a breakpoint on ndis!NdisMIndicateReceiveNetBufferLists or on your driver’s send handler:
NBL ffffa08e68bc69f0
next -
parent -
source ffffa08e6898d1a0 miniport Intel(R) 82574L Gigabit Network Connection #2
pool ffffa08e68bc3a00
context -
flags 0x200010c, NblFlags 0x0
status 0x00000000 (STATUS_SUCCESS)
child references 0
NET_BUFFERs (1)
NET_BUFFER Length Offset Current MDL MDL offset MDL chain
ffffa08e68bc6b70 0xdb 0x0 ffffa08e68b8a250 0x0 ffffa08e68b8a250
Source is the NBL’s SourceHandle with what it is: a miniport, a filter module, or a protocol’s binding, which ntoseye tells apart by the NDIS object header at the handle. NblFlags shows the NDIS_NBL_FLAGS_* bits by name, such as IS_IPV4 and IS_TCP. Each NET_BUFFER shows its data length, its offset from the start of its MDL chain (the bytes before it are backfill), and the MDL and offset where its data starts.
-chain lists every NBL on the Next chain from the address, with its NET_BUFFERs, bytes, status, and source. -data dumps each NET_BUFFER’s data by offset into the frame, up to 64 KiB of it:
data of NET_BUFFER ffffa08e68bc6b70 (0xdb bytes)
0000 52 54 00 a5 ee 27 52 55 0a 00 02 02 08 00 45 00 RT...'RU......E.
0010 00 cd 18 6d 00 00 40 11 49 a2 0a 00 02 03 0a 00 ...m..@.I.......
ntoseye reads the data through each MDL’s PFNs, so a buffer that is not mapped into system space reads too.
From Python¶
dbg.inspect has one method for each command, and each method returns the decoded fields as typed records:
ndis_miniports()andndis_miniport(address)for!ndiskd.miniportsand!ndiskd.miniportndis_minidrivers()andndis_minidriver(address)for!ndiskd.minidriverndis_filters()andndis_filter(address)for!ndiskd.filterndis_filter_drivers()andndis_filter_driver(address)for!ndiskd.filterdriverndis_protocols()andndis_protocol(address)for!ndiskd.protocolndis_oids()for!ndiskd.oidndis_nbl(address)andndis_nbl_chain(address)for!ndiskd.nbland its-chain; withdata=True, as-datadoes, each NET_BUFFER innet_buffersholds its data asbytesindata, or why it is not readable indata_error
for miniport in dbg.inspect.ndis_miniports().miniports:
detail = dbg.inspect.ndis_miniport(miniport.address)
print(miniport.friendly_name, miniport.media_connect, [f.name for f in detail.filters])