mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1137 lines
30 KiB
1137 lines
30 KiB
/*++
|
|
|
|
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 */
|
|
|