TDI Device Objects
Transports for Windows 2000 and later versions support Plug and Play and system power management by creating device objects to represent their respective bindings to underlying NICs. Each such transport registers itself with TDI during system startup as a network provider to make the PnP-aware transport available to potential clients when the underlying network hardware comes online.
Potential clients of these PnP-aware transports register their respective ClientPnPXxx callbacks with TDI to receive notifications of the availablility of active transport-to-NIC bindings and of transport-established network addresses on which these clients can subsequently send and receive data over the network while these network addresses remain valid.
As such a transport establishes a binding to an underlying NIC from the ProtocolBindAdapterfunction that the lowest module in the transport stack (or monolithic transport driver) registered with NDIS, the TDI transport driver creates a named device object to represent its binding to the underlying NDIS miniport driver. During system startup, such a PnP-aware transport registers each named device object it creates with TDI and sets up its per-binding state. The transport also registers any known network addresses on each such binding with TDI and sets up its per-registered-address state. When NDIS calls the ProtocolPnPEventfunction at the bottom of the transport stack with the PnP event code NetEventBindsComplete, such a transport then notifies TDI if it is ready to transfer data over the network on at least one such transport-to-NIC binding.
TDI gives each network client that has registered its ClientPnPXxx handlers the opportunity to bind itself to each such transport-created device object by calling ZwCreateFile from the client's registered ClientPnPBindingChange routine. TDI subsequently calls its registered ClientPnPAddNetAddress routine one or more times with each network address that the underlying transport has already registered for its device object. TDI also notifies these clients with calls to their registered ClientPnPBindingChange routines when any particular transport indicates it is ready to carry out network transfers and again when all startup-time transport-to-NIC bindings have been established.
At run time, these PnP-aware transports (or NDIS) continue to call TDI whenever a dynamic binding change occurs, whether because a NIC has been enabled/disabled or because the end user has initiated a binding change, and whenever such a transport makes or breaks a connection to a remote-node network address as follows:
If a new NIC is enabled, NDIS calls the ProtocolBindAdapter function at the bottom of each transport stack, thereby giving that transport an opportunity to bind itself to the new NIC, to create another device object to represent its new binding, and to register its new device object with TDI. As each such transport-created device object is registered, TDI calls the set of currently registered ClientPnPBindingChange routines and offers these clients the opportunity to open the new bindings.
After registering a new device object, the transport also registers any known network addresses on its new binding with TDI. TDI calls the set of registered ClientPnPAddNetAddress routines when transports register known network addresses on their new (or existing) bindings. These calls also give clients the opportunity to open a connection to such a registered address (and even to a binding). Whenever such a transport breaks a connection to a remote node, it calls TDI to deregister the corresponding network address.
Before an existing NIC is disabled, NDIS typically calls the ProtocolPnPEvent function at the bottom of the transport stack to ask whether it is safe to remove the NIC. The transport, in turn, notifies TDI of such a request to remove that NIC, and TDI notifies the clients with calls to their registered ClientPnPPowerChange routines. If no client objects to the NIC's removal, NDIS subsequently calls the ProtocolUnbindAdapter function at the bottom of the transport stack and the transport tears down its binding. In this process, the transport calls TDI to deregister all the network addresses it formerly registered on the binding, and it also calls TDI to deregister the device object that it created to represent that binding. In turn, TDI notifies clients of these unbinding operations by making calls to their registered ClientPnPDelAddress and ClientPnPBindingChange routines.
If the end user initiates a binding change in the network connections folder, NDIS calls TDI directly to notify registered network clients of the proposed binding change. If no client objects (and, therefore, the user is not prompted to cancel the binding-change operation), NDIS proceeds to call the appropriate ProtocolPnPEvent, ProtocolBindAdapter, or ProtocolUnbindAdapter functions at the bottom of the transport stacks.
In a similar manner, TDI notifies the clients of PnP-aware transports about proposed system power-state changes for underlying NICs. When the system power manager calls NDIS to power down (or up) a NIC, NDIS calls the ProtocolPnPEventfunction at the bottom of each transport stack that is currently bound to the NIC. Each such PnP-aware transport, in turn, notifies TDI of the proposed power-state change and TDI forwards the notification to the transport's clients for their approval or rejection.
Note The TDI feature is deprecated and will be removed in future versions of Microsoft Windows. Depending on how you use TDI, use either the Winsock Kernel (WSK) or Windows Filtering Platform (WFP). For more information about WFP and WSK, see Windows Filtering Platform and Winsock Kernel. For a Windows Core Networking blog entry about WSK and TDI, see Introduction to Winsock Kernel (WSK).