summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/st/connect.c')
-rw-r--r--private/ntos/tdi/st/connect.c1137
1 files changed, 1137 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/connect.c b/private/ntos/tdi/st/connect.c
new file mode 100644
index 000000000..8cb05b03b
--- /dev/null
+++ b/private/ntos/tdi/st/connect.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAccept
+ o TdiListen
+ o TdiConnect
+ o TdiDisconnect
+ o TdiAssociateAddress
+ o TdiDisassociateAddress
+ o OpenConnection
+ o CloseConnection
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiAccept(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAccept request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+ //
+ // Get the connection this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // This adds a connection reference if successful.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // just set the connection flags to allow reads and writes to proceed.
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // Turn off the stopping flag for this connection.
+ //
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+
+ if (connection->AddressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_WAIT_ACCEPT) != 0) {
+
+ //
+ // We previously completed a listen, now the user is
+ // coming back with an accept, Set this flag to allow
+ // the connection to proceed.
+ //
+
+ connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (connection->Provider, OpenConnections);
+
+ //
+ // Set this flag to enable disconnect indications; once
+ // the client has accepted he expects those.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_ACCEPT;
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Pended listen completed", connection);
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } else {
+
+ //
+ // This accept is being called at some point before
+ // the link is up; directly from the connection handler
+ // or at some point slightly later.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ }
+
+ StDereferenceConnection ("Temp TdiAccept", connection);
+
+ return STATUS_SUCCESS;
+
+} /* StTdiAccept */
+
+
+NTSTATUS
+StTdiAssociateAddress(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and the address for
+ the user.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PFILE_OBJECT fileObject;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS oldAddress;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
+ PDEVICE_CONTEXT deviceContext;
+
+ KIRQL oldirql, oldirql2;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ connection = irpSp->FileObject->FsContext;
+ status = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ //
+ // Make sure this connection is ready to be associated.
+ //
+
+ oldAddress = (PTP_ADDRESS)NULL;
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+
+ //
+ // The connection is already associated with
+ // an active connection...bad!
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ return STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // See if there is an old association hanging around...
+ // this happens if the connection has been disassociated,
+ // but not closed.
+ //
+
+ if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
+
+ //
+ // Save this; since it is non-null this address
+ // will be dereferenced after the connection
+ // spinlock is released.
+ //
+
+ oldAddress = connection->AddressFile->Address;
+
+ //
+ // Remove the old association.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RemoveEntryList (&connection->AddressList);
+ RemoveEntryList (&connection->AddressFileList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ //
+ // If we removed an old association, dereference the
+ // address.
+ //
+
+ if (oldAddress != (PTP_ADDRESS)NULL) {
+
+ StDereferenceAddress("Removed old association", oldAddress);
+
+ }
+
+
+ deviceContext = connection->Provider;
+
+ parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
+
+ //
+ // get a pointer to the address File Object, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ status = ObReferenceObjectByHandle (
+ parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *) &fileObject,
+ NULL);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // we might have one of our address objects; verify that.
+ //
+
+ addressFile = fileObject->FsContext;
+
+ if (NT_SUCCESS (StVerifyAddressObject (addressFile))) {
+
+ //
+ // have an address and connection object. Add the connection to the
+ // address object database. Also add the connection to the address
+ // file object db (used primarily for cleaning up). Reference the
+ // address to account for one more reason for it staying open.
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+ if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ StReferenceAddress (
+ "Connection associated",
+ addressFile->Address);
+
+ InsertTailList (
+ &addressFile->Address->ConnectionDatabase,
+ &connection->AddressList);
+
+ InsertTailList (
+ &addressFile->ConnectionDatabase,
+ &connection->AddressFileList);
+
+ connection->AddressFile = addressFile;
+ connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
+
+ if (addressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // The connection is closing, stop the
+ // association.
+ //
+
+ status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ StDereferenceAddress ("Temp associate", addressFile->Address);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ //
+ // Note that we don't keep a reference to this file object around.
+ // That's because the IO subsystem manages the object for us; we simply
+ // want to keep the association. We only use this association when the
+ // IO subsystem has asked us to close one of the file object, and then
+ // we simply remove the association.
+ //
+
+ ObDereferenceObject (fileObject);
+
+ } else {
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ return status;
+
+} /* TdiAssociateAddress */
+
+
+NTSTATUS
+StTdiDisassociateAddress(
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection and the address
+ for the user. If the connection has not been stopped, it will be stopped
+ here.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTP_CONNECTION connection;
+ NTSTATUS status;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // and now we disassociate the address. This only removes
+ // the appropriate reference for the connection, the
+ // actually disassociation will be done later.
+ //
+ // The DISASSOCIATED flag is used to make sure that
+ // only one person removes this reference.
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ StDereferenceConnection ("Temp use in Associate", connection);
+
+ return STATUS_SUCCESS;
+
+} /* TdiDisassociateAddress */
+
+
+NTSTATUS
+StTdiConnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PSTRING GeneralBroadcastSourceRoute = NULL; // BUGBUG: define this later.
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ PTA_NETBIOS_ADDRESS RemoteAddress;
+ ULONG RemoteAddressLength;
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no connect request should take more
+ // than 15 seconds if there is someone out there. We'll assume that's
+ // what the user wanted if they specify -1 as the timer length.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Check that the remote is a Netbios address.
+ //
+
+ RemoteAddress = (PTA_NETBIOS_ADDRESS)
+ (parameters->RequestConnectionInformation->RemoteAddress);
+
+ if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) {
+
+ StDereferenceConnection ("Not Netbios", connection);
+ return STATUS_BAD_NETWORK_PATH; // don't even try to find it.
+
+ }
+
+ //
+ // copy the called address someplace we can use it.
+ //
+
+ RemoteAddressLength = parameters->RequestConnectionInformation->RemoteAddressLength;
+
+ if (RemoteAddressLength > sizeof(TA_NETBIOS_ADDRESS)) {
+ RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
+ }
+
+ RtlCopyMemory(
+ connection->CalledAddress.NetbiosName,
+ RemoteAddress->Address[0].Address[0].NetbiosName,
+ 16);
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ StDereferenceConnection ("Throw away", connection);
+ return status; // return with failure.
+ } else {
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ StReferenceConnection("For connect request", connection);
+
+ tpRequest->Owner = ConnectionType;
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock (cancelirql);
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temporary Use 1", connection);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+
+ connection->Flags |= CONNECTION_FLAGS_CONNECTOR; // we're the initiator.
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+ }
+
+ status = StSendConnect (
+ connection);
+
+ if (!NT_SUCCESS(status)) { // can't send the name request
+ StStopConnection (connection, status);
+ StDereferenceConnection("Temporary Use 2", connection);
+
+ //
+ // Note that this return status isn't really a lie. We are waiting
+ // for the connection to run down.
+ //
+
+ return STATUS_PENDING;
+ }
+
+
+ StDereferenceConnection("Temporary Use 3", connection);
+
+ return STATUS_PENDING; // things are started.
+
+} /* TdiConnect */
+
+
+NTSTATUS
+StTdiDisconnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiDisconnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // if the connection is currently stopping, there's no reason to blow
+ // it away...
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection ("Ignoring disconnect", connection); // release our lookup reference.
+ return connection->Status;
+
+ } else {
+ connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_PRE_ACCEPT |
+ CONNECTION_FLAGS2_WAIT_ACCEPT);
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+
+ //
+ // Set this flag so the disconnect IRP is completed.
+ //
+ // BUGBUG: If the connection goes down before we can
+ // call StStopConnection with STATUS_LOCAL_DISCONNECT,
+ // the disconnect IRP won't get completed.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ connection->DisconnectIrp = Irp;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // fix up the timeout if required; no disconnect request should take very
+ // long. However, the user can cause the timeout to not happen if they
+ // desire that.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no disconnect request should take more
+ // than 15 seconds. We'll assume that's what the user wanted if they
+ // specify -1 as the timer.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Now the reason for the disconnect
+ //
+
+ if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
+ connection->Flags |= CONNECTION_FLAGS_DESTROY;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
+ connection->Flags |= CONNECTION_FLAGS_ABORT;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
+ connection->Flags |= CONNECTION_FLAGS_ORDREL;
+ }
+
+ //
+ // This will get passed to IoCompleteRequest during TdiDestroyConnection
+ //
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
+ StDereferenceConnection ("Disconnecting", connection); // release our lookup reference.
+
+ //
+ // This request will be completed by TdiDestroyConnection once
+ // the connection reference count drops to 0.
+ //
+
+ return STATUS_PENDING;
+} /* TdiDisconnect */
+
+
+NTSTATUS
+StTdiListen(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiListen request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_LISTEN parameters;
+
+ //
+ // validate this connection
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout, // timeout value (can be 0).
+ &tpRequest);
+
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+
+ StDereferenceConnection ("For create", connection);
+ return status; // return with failure.
+ }
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ tpRequest->Owner = ConnectionType;
+
+ StReferenceConnection("For listen request", connection);
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temp create", connection);
+ return STATUS_PENDING;
+
+ } else {
+
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+ connection->Flags |= CONNECTION_FLAGS_LISTENER | // we're the passive one.
+ CONNECTION_FLAGS_WAIT_LISTEN; // waiting for a connect
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ //
+ // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
+ // indicate that when the listen completes we do not have to
+ // wait for a TDI_ACCEPT to continue.
+ //
+
+ if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
+ connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ //
+ // Wait for an incoming NAME_QUERY frame. The remainder of the
+ // connectionless protocol to set up a connection is processed
+ // in the NAME_QUERY frame handler.
+ //
+
+ StDereferenceConnection("Temp create", connection);
+
+ return STATUS_PENDING; // things are started.
+} /* TdiListen */
+
+
+NTSTATUS
+StOpenConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PFILE_FULL_EA_INFORMATION ea;
+
+ UNREFERENCED_PARAMETER (Irp);
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful StCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ status = StCreateConnection (DeviceContext, &connection);
+ if (!NT_SUCCESS (status)) {
+ return status; // sorry, we couldn't make one.
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ IrpSp->FileObject->FsContext = (PVOID)connection;
+ IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
+ connection->FileObject = IrpSp->FileObject;
+
+ return status;
+
+} /* StOpenConnection */
+
+
+NTSTATUS
+StCloseConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection. There may be actions in
+ progress on this connection, so we note the closing IRP, mark the
+ connection as closing, and complete it somewhere down the road (when all
+ references have been removed).
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+ UNREFERENCED_PARAMETER (Irp);
+
+ //
+ // is the file object a connection?
+ //
+
+ connection = IrpSp->FileObject->FsContext;
+
+
+ //
+ // We duplicate the code from VerifyConnectionObject,
+ // although we don't actually call that since it does
+ // a reference, which we don't want (to avoid bouncing
+ // the reference count up from 0 if this is a dead
+ // link).
+ //
+
+ try {
+
+ if ((connection->Size == sizeof (TP_CONNECTION)) &&
+ (connection->Type == ST_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // We recognize it; is it closing already?
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection("Temp Close", connection);
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
+
+ //
+ // if there is activity on the connection, tear it down.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ }
+
+ //
+ // If the connection is still associated, disassociate it.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+
+ //
+ // Save this to complete the IRP later.
+ //
+
+ connection->CloseIrp = Irp;
+
+ //
+ // make it impossible to use this connection from the file object
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+ connection->FileObject = NULL;
+
+ //
+ // dereference for the creation. Note that this dereference
+ // here won't have any effect until the regular reference count
+ // hits zero.
+ //
+
+ StDereferenceConnectionSpecial (" Closing Connection", connection);
+
+ return STATUS_PENDING;
+
+} /* StCloseConnection */
+