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. IRP members relevant to this request include the following:
STATUS_SUCCESS
STATUS_PENDING
STATUS_INVALID_CONNECTION
STATUS_INVALID_PARAMETER
STATUS_DEVICE_NOT_READY
The client already established an endpoint-to-endpoint connection with a
remote-node peer on this connection endpoint.
struct _TDI_REQUEST_KERNEL_SEND { ULONG SendLength; ULONG SendFlags; } TDI_REQUEST_KERNEL_SEND, *PTDI_REQUEST_KERNEL_SEND;
The transport uses the members of this structure as follows:
When a client calls TdiBuildSend to 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:
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.
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:
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 indication(s).
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 SendLength 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.
TdiBuildSend is the macro a client uses to fill in the IRP.
ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildSend, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE