This documentation is archived and is not being maintained.


When a kernel-mode client makes a TDI_RECEIVE request, it asks the underlying TDI transport driver to indicate a normal or expedited TSDU on an established endpoint-to-endpoint connection.


The transport calls IoGetCurrentIrpStackLocation with the given Irpto get a pointer to its own I/O stack location in the IRP, shown in the following list as IrpSp. The pointer to the IRP is shown in the following list as Irp. IRP members relevant to this request include the following:


Specifies the final status of the receive request. The transport sets this member before it completes the IRP, possibly to one of the following:


Specifies the number of bytes of received data the transport is returning in the client-supplied buffer.


Specifies IRP_MJ_INTERNAL_DEVICE_CONTROL. The transport can ignore this member if it exports a TdiDispatchInternalDeviceControl routine that handles only TDI_XXX requests.


Specifies TDI_RECEIVE.


Pointer to an open file object representing the connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.

This client already established an endpoint-to-endpoint connection with a remote-node peer on this connection endpoint.


Pointer to a TDI_REQUEST_KERNEL_RECEIVE structure, defined as follows:

    ULONG ReceiveLength;
    ULONG ReceiveFlags;

The transport uses the members of this structure as follows:


Specifies the size in bytes of the client-supplied buffer mapped at Irp->MdlAddress.


Specifies the type of receive this client is requesting, as described later (see Comments).


Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer in which the transport returns the received data.


When a client calls TdiBuildReceiveto set up this IRP, it can specify the type of receive it wants. The transport finds this information at IrpSp->Parameters in the ReceiveFlags member. On input, ReceiveFlags can be zero or set with any combination (ORed) of the following flags:


The transport should return a normal TSDU to this client.


The transport should return an expedited TSDU to this client.


The transport should return any available received data that it has buffered internally at once, even if it is only a partial TSDU, to this client.

If ReceiveFlags is zero or set with both (ORed) TDI_RECEIVE_NORMAL and TDI_RECEIVE_EXPEDITED on input, either normal or expedited data is acceptable to the client. If only one of these flags is set, the transport should return only the type of TSDU requested. If TDI_RECEIVE_PEEK is set, the transport should return any received data it has buffered internally and retain the data in its internal buffer awaiting a subsequent receive request for the remainder of the TSDU from this client. Some transports, such as TCP/IP and SPX/IPX, do not buffer data internally. However, transport clients, such as Windows Sockets applications, get buffering support for nonbuffering transports from the system AFD driver.

Typically, a transport receives normal data until it fills the receive buffer or it receives an end-of-record indication from the remote node. However, if the transport is receiving normal data and expedited data arrives, the transport must preempt its normal receive operation, completing the IRP for the normal receive immediately with any normal data it has already transferred into the client's buffer. Then, the transport must satisfy the client's receive requests for the expedited data. When the transport has indicated all the expedited data to the client, the transport resumes indicating normal receives when the next receive request is submitted by that client.

If the client has registered any ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, and/or ClientEventChainedReceiveExpedited handlers for receives on the given connection endpoint, the transport stops indicating receives to the ClientEvent(Chained)Receive(Expedited) routines until the transport has satisfied the receive IRP.

When it calls ClientEventReceive or ClientEventReceiveExpedited, the transport supplies information about the type of receive event it is indicating, which the client can use to set up the ReceiveFlags for a subsequent TDI_RECEIVE request if it is not given the full TSDU. The transport supplies this information to its client by setting the ReceiveFlagsparameter to ClientEventReceive(Expedited) with one or more (ORed) of the following flags:


The transport is receiving a normal TSDU from the remote node.


The transport is receiving an expedited TSDU from the remote node.


If this flag is set, the transport already has a full TSDU available for receipt by the client. When this flag is set, ClientEventReceive is expected to copy the full net packet into an internal buffer and return control without postprocessing the received data, deferring any necessary postprocessing until later.

If this flag remains clear, it is equivalent to setting the (obsolete, but possibly still set by legacy transports) TDI_RECEIVE_PARTIAL flag to indicate that only the initial part of a TSDU is currently available from the transport.


The transport has received only the lookahead buffer for an indication from the underlying NIC driver, so it sets BytesAvailable to something less than BytesIndicated when the transport calls ClientEventReceive(Expedited) with these parameters. The client should copy the BytesAvailable into an internal buffer (see TdiCopyLookaheadData) and, then, submit one or more receive requests to obtain the remaining data in the TSDU.


The transport has buffered some receive data internally, but not yet the full TSDU. The client handles such an indication in a similar manner to one in which TDI_RECEIVE_COPY_LOOKAHEAD is set.


The transport received a TSDU that was truncated.


The transport received a TSDU that is fragmented.


The transport received the TSDU at IRQL = DISPATCH_LEVEL. This flag restricts the set of support routines that the client can call in processing the receive indication. For example, the client cannot call TdiBuildInternalDeviceControlIrp, which can be called only at IRQL = PASSIVE_LEVEL, in the context of this receive indication.

When the transport ORs TDI_RECEIVE_ENTIRE_MESSAGE with TDI_RECEIVE_NORMAL and calls the ClientEventChainedReceive handler, the client is given direct read-only access to a full TSDU in the underlying NIC's receive buffers until that client calls TdiReturnChainedReceiveswith the input TsduDescriptor. For such an indication, the client has no need to issue a TDI_RECEIVE request. In effect, such a transport forwards receive indications from the underlying NDIS miniport driver directly to its client with only the minimal overhead of setting up the parameters to ClientEventChainedReceive, as follows:

  • The transport uses the NDIS_PACKET-type descriptor input to the ProtocolReceivePacket function at the bottom of the transport stack as the TsduDescriptor passed to ClientEventChainedReceive. For each client to which the transport forwards the receive indication, the transport augments the value to be returned by ProtocolReceivePacket by one.

  • The transport retrieves the buffer containing the indicated data from the packet descriptor supplied by the underlying NDIS miniport driver, possibly by calling NdisGetFirstBufferFromPacket(Safe). The transport uses the pointer to this NDIS_BUFFER-type (equivalent to the MDL type) chain as the Tsdu for ClientEventChainedReceive.

  • From the full range of receive data indicated by the underlying NDIS miniport driver, the transport selects the subrange of interest to its client. The driver uses this subrange as the StartingOffset and ReceiveLength for ClientEventChainedReceive.

In a similar manner, such a TDI transport gives ClientEventChainedReceiveExpedited direct read-only access to a full TSDU when TDI_RECEIVE_ENTIRE_MESSAGE is ORed with TDI_RECEIVE_EXPEDITED in the input ReceiveFlags.

For a TSDU indicated to a ClientEventChainedReceive(Expedited) handler, the client retains control of all miniport driver-allocated resources for the receive indication until it calls TdiReturnChainedReceiveswith the TsduDescriptor. As each client that received the indication calls TdiReturnChainedReceives, the NDIS library decrements the counter it maintains for the packet descriptor, which was set originally to the value returned by the ProtocolReceivePacketfunction at the bottom of the transport stack. When all clients that received the indication have called TdiReturnChainedReceives, NDIS returns control of all resources specified by that packet descriptor to the NDIS miniport driver that allocated these resources.

When such a transport is called at its ProtocolReceivefunction with a full-packet indication made by the underlying NDIS miniport driver, the TDI transport must not call a registered ClientEventChainedReceive or ClientEventChainedReceiveExpedited handler with the indication. Instead, it should copy the indicated data for its client into a transport-allocated buffer and call the ClientEventReceive(Expedited) handler. An NDIS call to the ProtocolReceivefunction at the bottom of the transport stack implies that the underlying miniport driver expects all higher level network drivers to copy the receive data it is indicating and to return its packet descriptor (and all the miniport driver's resources that it describes) as quickly as possible because the miniport driver is short on NIC receive buffer space.

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).

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, NdisGetFirstBufferFromPacket, NdisGetFirstBufferFromPacketSafe, NDIS_PACKET, ProtocolReceive, ProtocolReceivePacket, TdiBuildReceive, TdiCopyLookaheadData, TdiDispatchInternalDeviceControl, TdiReturnChainedReceives



TdiKrnl.h (include TdiKrnl.h)



Send comments about this topic to Microsoft