TDI Kernel-Mode Client Interactions
The following figure shows how TDI clients make I/O requests to their underlying TDI transports and how transports make callbacks to their clients.
A TDI client interacts with its underlying transport driver as follows:
- Creating TDI File Objects
A client calls ZwCreateFile to create or open a file object that represents a transport address, a connection endpoint, or a control channel. This call causes the I/O manager to allocate an IRP, to marshal the client-supplied parameters into the IRP, and to pass the IRP to the underlying transport driver's TdiDispatchCreate routine. When the transport driver has set up all the state it maintains for the newly created file object, it calls IoCompleteRequest (or TdiCompleteRequest) with the IRP and STATUS_SUCCESS. ZwCreateFile then returns to the TDI client with a handle to the file object.
Each client process's call to ZwCreateFile creates a separate file object, even if two clients have specified the same transport address in their calls to ZwCreateFile.
A successful call to ZwCreateFile opens a transport address, a connection endpoint, or a control channel, depending on the EaXxx parameters the client passes in its call.
- Submitting Requests
After the appropriate file objects have been created, the client can submit requests that reference those objects. For example, after it opens a file object that represents a particular transport address, the client can submit an address-information query or "send datagram from this address" request.
Such a client uses standard I/O system mechanisms and conventions to submit all such requests:
The client prepares an IRP with an IRP_MJ_XXX opcode that identifies what operation the client wants the transport driver to perform. The client supplies all appropriate parameters for the given IRP_MJ_XXX, and, optionally, sets up its own IoCompletion routine that will be called when the request is completed by the transport.
The Windows Driver Kit (WDK) includes a set of TdiBuildXxx macros (in tdikrnl.h) that can be linked into client code and used to prepare IRPs for TDI-defined IOCTL requests, as well as the TdiBuildInternalDeviceControl function to allocate such an IRP.
When the IRP has been set up, the client calls IoCallDriver with pointers to the IRP, to the file object that represents the address, connection endpoint, or control channel, and to the transport driver's device object. The I/O manager passes the IRP directly to the appropriate TdiDispatch(Xxx) routine of the transport driver.
When the transport driver has completed the requested operation, it calls TdiCompleteRequest or IoCompleteRequest. The I/O manager then calls the client-supplied IoCompletion routine if the client supplied one for the IRP.
- Handling Event Notifications
If a client has preregistered its entry points for one or more event handlers, the transport driver calls each such routine when the corresponding network event occurs. For example, if the client has registered a ClientEventReceive handler on an address associated with an endpoint-to-endpoint connection, the transport calls this handler when data sent by the remote-node peer process is received on the local node.
- Deleting TDI Objects
The client calls ZwClose to delete a file object when the address, connection endpoint, or control channel is no longer needed by the client. The close request is forwarded to the transport's TdiDispatchCleanup and, subsequently, TdiDispatchClose routines.
For more information about the kernel-mode support routines mentioned here, see Summary of Kernel-Mode Support Routines. For detailed information about the TdiXxx functions, TdiBuildXxx macros, and ClientEventXxx routines mentioned here, see TdiBuildXxx Macros and Functionsand TDI Client Event and PnP Notification Handlers.