VOID
TdiBuildSend (
IN PIRP Irp,
IN PDEVICE_OBJECT DevObj,
IN PFILE_OBJECT FileObj,
IN PVOID CompRoutine,
IN PVOID Contxt,
IN PMDL MdlAddr,
IN ULONG InFlags,
IN ULONG SendLen
);
TdiBuildSend sets up an internal device control IRP for a TDI_SEND request to the underlying transport in which the local-node client has already opened a file object representing a connection endpoint and established an endpoint-to-endpoint connection with a remote-node peer.
The caller previously made a successful request, set up with TdiBuildAssociateAddress,
to the transport to set up an association between this connection endpoint and
a local-node address. When the association was established, the caller also
established an endpoint-to-endpoint connection with a remote-node peer by
issuing a successful request set up with TdiBuildConnect or TdiBuildListen,
the latter possibly followed by a successful request set up with TdiBuildAccept.
TdiBuildSend sets IRP_MJ_INTERNAL_DEVICE_CONTROL as the MajorFunction and TDI_SEND as the MinorFunction codes in the transport's I/O stack location of the given IRP.
In each send request set up with TdiBuildSend, the caller provides a buffer containing the TSDU to be sent to its remote-node peer, or part of a TSDU if the underlying transports support message-mode transfers. A client can send any amount of data up to the maximum size the TDI driver allows. To obtain the transport-specific maximum size for sends, the client can make a TDI_QUERY_PROVIDER_INFO request, set up with TdiBuildQueryInformation.
After the caller of TdiBuildSend passes the send IRP to the underlying transport with IoCallDriver, the client-supplied buffer at MdlAddress is inaccessible to that client until the send operation is completed. The client must not attempt to modify or use its send buffer until the IRP is returned to the client's IoCompletion routine or the client is certain (through protocol semantics) that its underlying transport has completed send operations for the data in that buffer.
The local-node transport can queue several send requests internally, but it always transmits them in FIFO order. If the transport supports expedited sends, it queues incoming expedited-send requests in FIFO order ahead of any normal sends it is currently holding. The transport is responsible for completing incoming sends in a timely manner, with either a success or error status. The transport can complete a send with a time-out error based on a driver-determined estimate of a reasonable time-out interval for current network conditions.
Each local-node client's send request on an endpoint-to-endpoint connection corresponds to one of the following:
If the underlying transport supports message-mode sends, its client can send a TSDU in pieces as a sequence of send requests, each except the last specifying the TDI_SEND_PARTIAL flag. When this flag is clear, a message-mode transport considers such a sequence of partial sends to be at an end. In this transfer scenario, the transport on the remote node notifies the receiving client of partial TSDUs by leaving the TDI_RECEIVE_ENTIRE_MESSAGE flag clear in the corresponding receive indications until it indicates the last receive in such a sequence.
The caller of TdiBuildSend can request a nonblocking send by setting the TDI_SEND_NON_BLOCKING flag if the underlying transport has internal buffers into which it copies its clients' send data. Depending on the amount of internal buffer space available, the underlying transport handles such a send request as follows:
The client of such a transport registers a ClientEventSendPossible handler, which the transport will call when it again has internal buffer space available for the rejected send.
When its send is completed with STATUS_SUCCESS, the client of such a transport can determine how much data the transport has buffered for transmission by checking the IoStatus.Information member of the completed IRP. If necessary, the client's IoCompletion routine can resubmit another send request for the remaining data to be sent.
Some transports allow their clients to issue zero-length send requests. For such a transport, a zero-length send actually forces protocol flow, as long as the TDI_SEND_PARTIAL flag is clear. The client of such a transport can issue such a zero-length send as a message that satisfies a receive request. Transports that do not support this feature return an error when a client issues a zero-length send request.
A TDI client also can send a normal TSDU on an endpoint-to-endpoint connection with a call to ZwWriteFile. Because this routine does not allow the specification of TDI_SEND_XXX flags, client-supplied data given to ZwWriteFile is transmitted by the underlying transport as if it were packaged as a TdiBuildSend request with both TDI_SEND_PARTIAL and TDI_SEND_EXPEDITED clear in the SendFlags. The transport assumes that all the data in the buffer at MdlAddr should be sent, and the caller's ByteOffset and Key arguments to ZwWriteFile are ignored.
ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildAccept, TdiBuildAssociateAddress, TdiBuildConnect, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildReceive, TdiBuildSetEventHandler, TDI_SEND