TDI_SEND

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.

IRP

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:

IoStatus.Status

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

STATUS_SUCCESS
STATUS_PENDING
STATUS_INVALID_CONNECTION
STATUS_INVALID_PARAMETER
STATUS_DEVICE_NOT_READY

IoStatus.Information

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

IrpSp->MajorFunction

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

IrpSp->MinorFunction

Specifies TDI_SEND.

IrpSp->FileObject

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

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

IrpSp->Parameters

Points to a TDI_REQUEST_KERNEL_SEND structure, defined as follows:

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:

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

MdlAddress

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

Comments

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:

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. If the transport does not support expedited transfers, it can ignore this flag.

TDI_SEND_PARTIAL

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.

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. This flag should disable piggybacking of the TSDU acknowledgment by the remote-node transport.

TDI_SEND_NON_BLOCKING

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

See Also

ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, ClientEventSendPossible, TdiBuildSend, TdiDispatchInternalDeviceControl, TDI_QUERY_INFORMATION, TDI_RECEIVE