Share via


When a kernel-mode client makes a TDI_SEND request, it asks the underlying TDI transport driver to transmit a normal or expedited TSDU on a specified connection endpoint to its remote-node peer.


The transport calls IoGetCurrentIrpStackLocation with the given Irp to 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 send-datagram request. The transport sets this member before it completes the IRP, possibly to one of the following:






Specifies the number of bytes of client-supplied data the driver transferred from the client-supplied buffer mapped at Irp->MdlAddress.


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




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


Pointer to a TDI_REQUEST_KERNEL_SEND structure, defined as follows:

    ULONG SendLength;
    ULONG SendFlags;

The transport uses the members of this structure as follows:

  • SendLength
    Specifies the number of bytes of data to be sent in the buffer mapped at Irp->MdlAddress.

  • SendFlags
    Specifies the type of TSDU the client expects to be sent as none (zero), one, or a combination (ORed) of TDI_SEND_XXX flags (see Comments).


Pointer to an MDL, possibly the initial MDL in a chain, mapping a client-supplied buffer containing the data to be sent.


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

    The given data should be sent ahead of any normal send requests the transport is currently holding queued for transmission on this endpoint-to-endpoint connection. If the transport does not support expedited transfers, it can ignore this flag.

    The given data is not a complete message-mode TSDU. The client will send the remaining data for the TSDU later. This flag is irrelevant to stream-mode transports.

    If this flag is clear in a send submitted to a message-mode transport, the driver inserts an end-of-record mark in the line flow after sending all data supplied in the client's buffer.

    The caller is giving a hint to the underlying transport that it does not expect a response to this send from its remote-node peer. This flag should disable piggybacking of the TSDU acknowledgment by the remote-node transport.

    If the underlying transport currently has no internal buffer space available for the given data, it should just complete the IRP with STATUS_DEVICE_NOT_READY. If the transport has some buffer space available, it should copy as much data as it can from the client-supplied buffer, set the IoStatus.Information member to the number of bytes it copied, and complete the IRP with STATUS_SUCCESS.

    This flag is irrelevant to transports that do not buffer sends internally.

Each local-node client send request is associated with exactly one of the following:

  • A receive request issued by the remote-node client to its underlying transport

  • A remote-node transport's call to its client's registered ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, or ClientEventChainedReceiveExpedited handler

The local-node TDI transport driver can queue any number of send requests on a particular connection, but it must process them in FIFO order, unless the client issues an expedited send. Each expedited send request must be queued and transmitted ahead of any normal send requests the transport is holding queued, and each expedited send also must be transmitted in FIFO order for the client.

The transport must complete each send IRP in a timely manner, whether with a success or error status. The driver should determine a reasonable time-out based on its knowledge of underlying network conditions.

Depending on the underlying transport, clients can send stream-mode or message-mode TSDUs, the latter with one or more send requests. For stream-mode transports, the client does not delimit messages and the TDI_SEND_PARTIAL flag is irrelevant. For message-mode transports, the client can send a TSDU as a sequence of send requests, each specifying the TDI_SEND_PARTIAL flag. If this flag is clear in a submitted send request, a message-mode transport considers the data to be the end of such a sequence or a complete TSDU. The remote-node TDI transport notifies the receiving client of partial TSDUs through receive indicators passed in the corresponding receive indications.

In its send request, the sending client provides a buffer containing the TSDU. The client can provide a buffer of any size up to the transport-determined limit. The transport is given ownership of this client-supplied buffer until it completes the send. The transport fails any send request for which a client specifies a SendFlags larger than the transport supports.

Clients can determine their underlying transports' send-size limits by submitting TDI_QUERY_PROVIDER_INFO-type queries.

If the transport buffers client-supplied send data internally, the client can request a nonblocking send by setting the TDI_SEND_NON_BLOCKING flag. When such a transport is given a send request with this flag set, it completes the IRP with STATUS_DEVICE_NOT_READY if it cannot copy the given data into its internal buffer space. Such a transport returns STATUS_SUCCESS if it buffers only a part of the given TSDU internally, but it must set IoStatus.Information in such an IRP to the number of bytes it buffered internally so its client can submit a subsequent send for the remaining data in the original send request.

Any client that submits nonblocking send requests usually registers a ClientEventSendPossible handler. The underlying transport calls this handler after it has rejected a send request with STATUS_DEVICE_NOT_READY as soon as that transport has internal buffer space available for holding send data.

A transport also can support zero-length send requests. A zero-length send in which the TDI_SEND_PARTIAL flag is clear actually forces protocol flow. The client of such a transport can issue zero-length send to satisfy a receive request. If the driver does not support zero-length sends, it should return an error when its clients submit zero-length send requests.

TdiBuildSendis the macro a client uses to fill in the IRP.

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, ClientEventSendPossible, TdiBuildSend, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE



TdiKrnl.h (include TdiKrnl.h)



Send comments about this topic to Microsoft