When a kernel-mode client makes a TDI_LISTEN request, it asks the underlying TDI transport driver to listen for an offer to make an endpoint-to-endpoint connection from a remote node.
The transport calls IoGetCurrentIrpStackLocation with the given Irpto 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 listen request. The transport sets this member before it completes the IRP, possibly to one of the following:
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 connection endpoint. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this connection.
This connection endpoint was previously associated with a local-node address when the client made a successful TDI_ASSOCIATE_ADDRESS request to the transport.
Pointer to a TDI_REQUEST_KERNEL_LISTEN structure, equivalent to the TDI_REQUEST_KERNEL structure.
A client can set the RequestFlags member with TDI_QUERY_ACCEPT, directing the transport to make a delayed-connection acceptance: that is, to complete this listen request to the client when an appropriate connection offer, as specified by RequestConnectionInformation, comes in from the remote node so the client can determine whether to accept the connection by issuing a TDI_ACCEPT request or to reject the remote-node connection offer with a TDI_DISCONNECT request.
Otherwise, when RequestFlags is zero, the underlying transport should accept any appropriate incoming connection offer immediately. If TDI_QUERY_ACCEPT is set but the transport does not support delayed-connection acceptances, the transport fails this listen request.
The client supplies information in the TDI_CONNECTION_INFORMATION-type buffer at RequestConnectionInformation that the transport subsequently uses to determine whether to accept a connection offer from a remote node, as follows:
Pointer to a buffer of client-supplied data for the transport to transmit to the remote node that requests a connection. This member is NULL if the transport supports delayed-connection acceptances and the client set RequestFlags with TDI_QUERY_ACCEPT.
Matches the value set in the RequestFlags member of the TDI_REQUEST_KERNEL_LISTEN structure.
Should be set to sizeof(ULONG); irrelevant if TDI_QUERY_ACCEPT is not set in RequestFlags.
Pointer to a buffer specifying the remote-node address for which the local-node client listens in anticipation of a connection offer. This specification can be a partial address if the underlying transport defines the conventions and syntax for specifying partial addresses. This member also can be NULL, indicating that the client will accept an endpoint-to-endpoint connection offer from any remote node.
Specifies the size in bytes of the buffer at RemoteAddress. Zero indicates that a connection offer from any remote node is acceptable to this client.
The client-supplied buffer at ReturnConnectionInformation in the TDI_REQUEST_KERNEL structure is also formatted as a TDI_CONNECTION_INFORMATION structure. The transport returns information about the connection offer from the remote node in this buffer on completion of this listen request.
Depending on whether TDI_QUERY_ACCEPT is set in the RequestFlags, the transport completes the listen request either by accepting an offered remote-node connection on behalf of its local-node client or by deferring acceptance or rejection of such an offer to that client.
To initiate a listen request successfully, the local-node client must have its transport address already associated with an idle connection endpoint. That is, the transport has previously satisfied a TDI_ASSOCIATE_ADDRESS request for the file object at IrpSp->FileObject that represents the connection. Part of the context that each transport maintains at FsContext or FsContext2 for a connection endpoint is a pointer to the file object that represents the associated address, which the transport sets up when it makes the association.
After issuing a successful TDI_ASSOCIATE_ADDRESS request, a client can then issue any number of TDI_LISTEN requests, which the transport driver should process in FIFO order until the client accepts an offered connection.
The transport can process requests coming in from all its clients in any driver-determined order.
If a client registered its ClientEvent(Chained)Receive and/or ClientEvent(Chained)ReceiveExpedited handlers on the address associated with the connection endpoint before making its TDI_LISTEN request, receives can come in for that client as soon as the transport accepts the connection from a remote node, even before the transport has completed the client's listen request. Such a client must be prepared for an endpoint-to-endpoint connection to be established as soon as it makes a listen request, and the transport must be prepared to indicate receives to that client concurrently with completion of the listen request.
In general, a TDI transport driver cannot call a registered ClientEventConnect handler as long as a listen request is pending on the client's open file object that represents the associated local-node address. However, the driver can call ClientEventConnect when such a listen is pending if the transport determines that the remote-address acceptance criteria supplied at IrpSp->Parameters.RequestConnectionInformation will prevent the listen operation from being completed.
Client-supplied remote-node addressing information acts as a filter that the transport applies before checking the RequestFlagsfor a pending listen request. When an incoming connection offer comes from a remote-node address that does not match the address specified in the listen IRP, the transport cannot complete the listen for its client. When an incoming connection offer from a remote node satisfies the given address-acceptance criteria, the transport can satisfy the client's listen request in either of the following ways:
If TDI_QUERY_ACCEPT is not set in the RequestFlags or if the driver does not support delayed-connection acceptance, the transport sends an acceptance to the remote node, sets up the buffer at IrpSp->Parameters.ReturnConectionInformation with appropriate data, as well as setting the status block of the IRP, and returns control.
If TDI_QUERY_ACCEPT is set in the RequestFlags, the transport sets up the buffer at IrpSp->Parameters.ReturnConectionInformation and sets the status block of the IRP, sets up a time-out interval for waiting for the client's acceptance or rejection of the offered connection, and returns control. The local-node client must either accept or reject the offered connection within the time-out interval; otherwise, the transport must send a rejection to the remote node.
TDI drivers vary in how they handle partial addresses. Because the syntax of a transport address is TDI-driver-specific, the mechanism for specifying a partial address is also specific to each transport driver.
In addition to supporting partial-address specifications on listens, TDI transports can support quality-of-service (QoS) specifications by their clients. For example, a transport might allow its clients to specify QoS using a variable-length counted string with TDI-driver-specific syntax and semantics.
TdiBuildListenis the macro a client uses to fill in this IRP.
ClientEventConnect, ClientEventChainedReceive, ClientEventChainedReceiveExpedited, ClientEventReceive, ClientEventReceiveExpedited, TDI_ACCEPT, TDI_ASSOCIATE_ADDRESS, TdiBuildListen, TDI_CONNECTION_INFORMATION, TDI_DISCONNECT, TdiDispatchInternalDeviceControl, TDI_REQUEST_KERNEL, TDI_SET_EVENT_HANDLER