TdiBuildSend

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.

Parameters

Irp

Points to a client-supplied IRP, either originating in a higher level network component or allocated with TdiBuildInternalDeviceControlIrp.

DevObj

Points to the device object created by the next lower TDI transport driver.

FileObj

Points to a file object representing a connection endpoint.

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.

CompRoutine

Specifies the entry point of a client-supplied IoCompletion routine or NULL. The I/O Manager calls this routine when the given IRP is completed, unless the client sets this parameter to NULL.

Contxt

Points to a client-determined context. This client-supplied pointer is passed in to the IoCompletion routine when it is called with the completed IRP. Contxt should be NULL if CompRoutine is NULL.

MdlAddr

Points to an MDL, possibly the initial MDL in a chain of MDLs, mapping a client-supplied buffer from which the transport is to transfer the data to be sent.

InFlags

Specifies how the data should be transmitted. If this parameter is zero, the transport should send the given data as a normal TSDU. Otherwise, this parameter can be one or a combination (Ored) of the following flags:

TDI_SEND_EXPEDITED

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, assuming the underlying transport supports expedited transfers.

TDI_SEND_PARTIAL

The given data is terminated by an end-of-record but is not a complete message-mode TSDU. The client will send the additional data later. This flag is irrelevant to clients of stream-mode transports.

TDI_SEND_NO_RESPONSE_EXPECTED

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. A client uses this flag to disable piggybacking of the TSDU acknowledgment by the remote-node transport, assuming both transports support this optimization. Otherwise, its underlying transport might time out, waiting for a piggybacked acknowledgment of the send from the remote node.

TDI_SEND_NON_BLOCKING

If the underlying transport currently has no internal buffer space available for the given data, it should fail this send request with STATUS_DEVICE_NOT_READY, rather than blocking until it can buffer the given data internally. The transport should call the ClientEventSendPossible handler when it again has internal buffer space available for sends. This flag is irrelevant to clients of transports that do no internal buffering.

SendLen

Specifies the size in bytes of the buffer mapped at MdlAddr. The maximum for this parameter depends on the underlying transport. Whether zero is valid also depends on the underlying transport. (See Comments.)

Comments

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:

·One receive request issued by the remote-node client to its underlying TDI transport

·One call to the remote-node client's registered ClientEventReceive, ClientEventReceiveExpedited, ClientEventChainedReceive, or ClientEventChainedReceiveExpedited handler by its underlying TDI transport

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:

·If it currently has sufficient internal buffer space, the transport copies the data from the client-supplied buffer and completes the send IRP with STATUS_SUCCESS.

·If it currently has insufficient buffer space for the given SendLength, the transport copies as much data as possible from the client's buffer and returns STATUS_SUCCESS.

·If the driver currently has no internal buffer space, the transport completes the send IRP with STATUS_DEVICE_NOT_READY.

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.

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildAccept, TdiBuildAssociateAddress, TdiBuildConnect, TdiBuildInternalDeviceControlIrp, TdiBuildListen, TdiBuildReceive, TdiBuildSetEventHandler, TDI_SEND