When a kernel-mode client makes a TDI_DISCONNECT request, it asks the underlying TDI transport driver to make a disconnect indication to the remote node, to acknowledge a disconnect indication from the remote node for an established endpoint-to-endpoint connection, or to reject an offered connection by a remote-node peer.
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 disconnect 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.
Pointer to a TDI_REQUEST_KERNEL_DISCONNECT structure, equivalent to the TDI_REQUEST_KERNEL structure.
Some transport drivers simply terminate all activity on the given connection immediately. Others use the client-supplied value of the RequestFlags member to support controlled disconnects. For such a transport, RequestFlags can be set to either of the following:
Specifies that the transport should close the connection immediately without completing its pending operations on the connection. This is the default behavior expected of all transports, including transports that do not support controlled disconnects. In effect, this value for RequestFlags directs the transport to do the same things as if RequestFlags were zero: the transport should refuse any incoming requests for the connection, stop all activity at the specified connection endpoint, and cancel any outstanding requests it is holding queued internally for the connection.
When a preceding disconnect request made with TDI_DISCONNECT_RELEASE remains pending on the connection, the client can issue another disconnect request with TDI_DISCONNECT_ABORT, thereby forcing the underlying transport to close the connection immediately.
Specifies that the transport should initiate a controlled disconnect or confirms a controlled disconnect that was initiated from the remote node, as described later (see Comments).
The transport can use client-supplied information in the buffer at RequestConnectionInformation to supply disconnection data, possibly supplemented with transport-provided status information, to the transport on the remote node. This buffer is formatted as a TDI_CONNECTION_INFORMATION structure.
The transport can return disconnect data and any status information supplied by the transport on the remote node in the client-supplied buffer at ReturnConnectionInformation. This buffer is formatted as a TDI_CONNECTION_INFORMATION structure. The contents of this buffer remain valid only until the client reuses the connection in a subsequent TDI_LISTEN or TDI_CONNECT request.
The TDI_DISCONNECT_WAIT flag is unused.
Pointer to a LARGE_INTEGER variable specifying the time-out interval for the disconnect operation or is NULL. An explicit time out is specified as the negative of the number of 100-nanosecond units, relative to the current system time, for the time-out interval. If this member is NULL, the transport must choose an appropriate time-out value, usually something less than one second.
During a disconnect operation, the underlying transport driver usually refuses any incoming requests for an established connection and stops all activity at the specified connection endpoint, unless the transport supports controlled disconnects. That is, the completion of a client's disconnect request usually implies cessation of all activity, including receive indications, on the given connection.
By default, TDI_DISCONNECT requests the disconnection of an endpoint-to-endpoint connection that is not a controlled-disconnect operation: the transport need not complete outstanding I/O requests on the connection before it completes the disconnect request and returns control. For such a disconnect operation, the transport typically cancels all outstanding requests on the given connection, and the corresponding remote-node transport need not have its client confirm the disconnection before the local-node transport can complete its client's disconnect request and return control.
Clients on an endpoint-to-endpoint connection can request a controlled disconnect if their underlying TDI transports support this. If so, the client that initiates the disconnect operation with a TDI_DISCONNECT request causes both transports to coordinate their operations so the remote-node peer is informed that its endpoint-to-endpoint connection is closing. In these circumstances, the remote-node client must confirm the disconnect before the underlying transport can return from the initiating (local-node) client's disconnect request.
The following summarizes the sequence of operations for a controlled disconnect:
The local-node client initiates a disconnection by making a disconnect request with TDI_DISCONNECT_RELEASE set in RequestFlags. Subsequently, this client can no longer send data on the connection, but it can continue to receive data from its remote-node peer. When such a local-node client makes its disconnect request, the underlying transport transmits the data for any pending send requests it is currently holding and completes these requests back to its client, but it notifies the remote-node transport that a disconnect is occurring.
The transport on the remote node performs the usual operations for any pending receive requests made by its client. Then, the remote-node transport notifies its client of the pending disconnect, either by calling ClientEventDisconnect if the remote-node client has registered this handler or by returning an error code on an outstanding request made by its client. After such a notification, the remote-node client can no longer receive data on the connection, but it can continue to send data until it makes a TDI_DISCONNECT request with TDI_DISCONNECT_RELEASE set in the RequestFlags.
When the remote-node client has finished sending data, it makes a disconnect request to its underlying transport with TDI_DISCONNECT_RELEASE set in RequestFlags. The transport completes all outstanding sends on the connection normally before completing its client's disconnect request. When the transport completes this disconnect request, the connection is closed from the point of view of its remote-node client. However, the connection endpoint is still valid and that client can reuse it later.
The remote-node transport notifies the local-node transport to confirm disconnect completion on the remote node. At this point, the original disconnect request is completed by the local-node transport and the connection is closed from the point of view of the local-node client that initiated the staged disconnection. However, the connection endpoint is still valid and the client can reuse it.
If the underlying transport supports delayed-connection acceptances, its clients also can submit TDI_DISCONNECT requests to reject incoming connection offers from remote nodes. Such a client is responding to a completed TDI_LISTEN request in which the client set the TDI_QUERY_ACCEPT flag or to a offer relayed by the transport to that client's registered ClientEventConnect handler.
TdiBuildDisconnectis the macro a client uses to fill in this IRP.