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.
1733 lines
50 KiB
1733 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1989, 1990, 1991 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
|
|
|
|
Author:
|
|
|
|
David Beaver (dbeaver) 1 July 1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef notdef // RASAUTODIAL
|
|
#include <acd.h>
|
|
#include <acdapi.h>
|
|
#endif // RASAUTODIAL
|
|
|
|
#ifdef notdef // RASAUTODIAL
|
|
extern BOOLEAN fAcdLoadedG;
|
|
extern ACD_DRIVER AcdDriverG;
|
|
|
|
//
|
|
// Imported functions.
|
|
//
|
|
VOID
|
|
NbfRetryPreTdiConnect(
|
|
IN BOOLEAN fSuccess,
|
|
IN PVOID *pArgs
|
|
);
|
|
|
|
BOOLEAN
|
|
NbfAttemptAutoDial(
|
|
IN PTP_CONNECTION Connection,
|
|
IN ULONG ulFlags,
|
|
IN ACD_CONNECT_CALLBACK pProc,
|
|
IN PVOID pArg
|
|
);
|
|
|
|
VOID
|
|
NbfCancelPreTdiConnect(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
);
|
|
#endif // RASAUTODIAL
|
|
|
|
NTSTATUS
|
|
NbfTdiConnectCommon(
|
|
IN PIRP Irp
|
|
);
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiAccept(
|
|
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;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("NbfTdiAccept: Entered.\n");
|
|
}
|
|
|
|
//
|
|
// Get the connection this is associated with; if there is none, get out.
|
|
// This adds a connection reference of type BY_ID if successful.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
//
|
|
// This adds a connection reference of type BY_ID if successful.
|
|
//
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|
|
|
//
|
|
// just set the connection flags to allow reads and writes to proceed.
|
|
//
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
//
|
|
// Turn off the stopping flag for this connection.
|
|
//
|
|
|
|
connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
|
|
connection->Status = STATUS_PENDING;
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
|
|
|
|
|
|
if (connection->AddressFile->ConnectIndicationInProgress) {
|
|
connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
|
|
}
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_WAITING_SC) != 0) {
|
|
|
|
//
|
|
// We previously completed a listen, now the user is
|
|
// coming back with an accept, Set this flag to allow
|
|
// the connection to proceed.
|
|
//
|
|
// If the connection has gone down in the
|
|
// meantime, we have just reenabled it.
|
|
//
|
|
|
|
ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
|
|
connection->Flags |= CONNECTION_FLAGS_READY;
|
|
RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
|
|
|
|
INCREMENT_COUNTER (connection->Provider, OpenConnections);
|
|
|
|
//
|
|
// Set this flag to enable disconnect indications; once
|
|
// the client has accepted he expects those.
|
|
//
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
NbfSendSessionConfirm (connection);
|
|
|
|
} 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. We don't set
|
|
// FLAGS2_REQ_COMPLETED now because the reference
|
|
// count is not high enough; we set it when we get
|
|
// the session initialize.
|
|
//
|
|
// If the connection goes down in the meantime,
|
|
// we won't indicate the disconnect.
|
|
//
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
}
|
|
|
|
NbfDereferenceConnection ("Temp TdiAccept", connection, CREF_BY_ID);
|
|
|
|
KeLowerIrql (oldirql);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} /* NbfTdiAccept */
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiAssociateAddress(
|
|
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;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("TdiAssociateAddress: Entered.\n");
|
|
}
|
|
|
|
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
|
|
//
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure this connection is ready to be associated.
|
|
//
|
|
|
|
oldAddress = (PTP_ADDRESS)NULL;
|
|
|
|
try {
|
|
|
|
ACQUIRE_C_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_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
|
|
NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
|
|
|
|
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) {
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("NbfTdiAssociateAddress: removing association.\n");
|
|
}
|
|
|
|
//
|
|
// 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_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DbgPrint ("NBF: Got exception 1 in NbfTdiAssociateAddress\n");
|
|
DbgBreakPoint();
|
|
|
|
RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
|
|
NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
|
|
//
|
|
// If we removed an old association, dereference the
|
|
// address.
|
|
//
|
|
|
|
if (oldAddress != (PTP_ADDRESS)NULL) {
|
|
|
|
NbfDereferenceAddress("Removed old association", oldAddress, AREF_CONNECTION);
|
|
|
|
}
|
|
|
|
|
|
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,
|
|
*IoFileObjectType,
|
|
Irp->RequestorMode,
|
|
(PVOID *) &fileObject,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (fileObject->DeviceObject == &deviceContext->DeviceObject) {
|
|
|
|
//
|
|
// we might have one of our address objects; verify that.
|
|
//
|
|
|
|
addressFile = fileObject->FsContext;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint3 ("NbfTdiAssociateAddress: Connection %lx Irp %lx AddressFile %lx \n",
|
|
connection, Irp, addressFile);
|
|
}
|
|
|
|
if ((fileObject->FsContext2 == (PVOID) TDI_TRANSPORT_ADDRESS_FILE) &&
|
|
(NT_SUCCESS (NbfVerifyAddressObject (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) {
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint2 ("NbfTdiAssociateAddress: Valid Address %lx %lx\n",
|
|
addressFile->Address, addressFile);
|
|
}
|
|
|
|
try {
|
|
|
|
ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
|
|
|
|
NbfReferenceAddress (
|
|
"Connection associated",
|
|
addressFile->Address,
|
|
AREF_CONNECTION);
|
|
|
|
#if DBG
|
|
if (!(IsListEmpty(&connection->AddressList))) {
|
|
DbgPrint ("NBF: C %lx, new A %lx, in use\n",
|
|
connection, addressFile->Address);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
InsertTailList (
|
|
&addressFile->Address->ConnectionDatabase,
|
|
&connection->AddressList);
|
|
|
|
#if DBG
|
|
if (!(IsListEmpty(&connection->AddressFileList))) {
|
|
DbgPrint ("NBF: C %lx, new AF %lx, in use\n",
|
|
connection, addressFile);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
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_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DbgPrint ("NBF: Got exception 2 in NbfTdiAssociateAddress\n");
|
|
DbgBreakPoint();
|
|
|
|
RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
|
|
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_HANDLE; //should this be more informative?
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
|
|
|
|
NbfDereferenceAddress ("Temp associate", addressFile->Address, AREF_VERIFY);
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
}
|
|
} 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;
|
|
}
|
|
|
|
NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
|
|
|
|
return status;
|
|
|
|
} /* TdiAssociateAddress */
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiDisassociateAddress(
|
|
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;
|
|
// PDEVICE_CONTEXT DeviceContext;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("TdiDisassociateAddress: Entered.\n");
|
|
}
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
//
|
|
// If successful this adds a reference of type BY_ID.
|
|
//
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
|
|
} else {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
}
|
|
|
|
//
|
|
// 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_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
|
|
((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
|
|
connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
} else {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
}
|
|
|
|
KeLowerIrql (oldirql);
|
|
|
|
NbfDereferenceConnection ("Temp use in Associate", connection, CREF_BY_ID);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} /* TdiDisassociateAddress */
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiConnect(
|
|
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;
|
|
KIRQL oldirql;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PTDI_REQUEST_KERNEL parameters;
|
|
TDI_ADDRESS_NETBIOS * RemoteAddress;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("NbfTdiConnect: Entered.\n");
|
|
}
|
|
|
|
//
|
|
// is the file object a connection?
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
//
|
|
// If successful this adds a reference of type BY_ID.
|
|
//
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
|
|
|
|
//
|
|
// Check that the remote is a Netbios address.
|
|
//
|
|
|
|
if (!NbfValidateTdiAddress(
|
|
parameters->RequestConnectionInformation->RemoteAddress,
|
|
parameters->RequestConnectionInformation->RemoteAddressLength)) {
|
|
|
|
NbfDereferenceConnection ("Invalid Address", connection, CREF_BY_ID);
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
RemoteAddress = NbfParseTdiAddress((PTRANSPORT_ADDRESS)(parameters->RequestConnectionInformation->RemoteAddress), FALSE);
|
|
|
|
if (RemoteAddress == NULL) {
|
|
|
|
NbfDereferenceConnection ("Not Netbios", connection, CREF_BY_ID);
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
|
|
}
|
|
|
|
//
|
|
// copy the called address someplace we can use it.
|
|
//
|
|
|
|
connection->CalledAddress.NetbiosNameType =
|
|
RemoteAddress->NetbiosNameType;
|
|
|
|
RtlCopyMemory(
|
|
connection->CalledAddress.NetbiosName,
|
|
RemoteAddress->NetbiosName,
|
|
16);
|
|
|
|
#ifdef notdef // RASAUTODIAL
|
|
if (fAcdLoadedG) {
|
|
KIRQL adirql;
|
|
BOOLEAN fEnabled;
|
|
|
|
//
|
|
// See if the automatic connection driver knows
|
|
// about this address before we search the
|
|
// network. If it does, we return STATUS_PENDING,
|
|
// and we will come back here via NbfRetryTdiConnect().
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
|
|
fEnabled = AcdDriverG.fEnabled;
|
|
RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
|
|
if (fEnabled && NbfAttemptAutoDial(
|
|
connection,
|
|
ACD_NOTIFICATION_PRECONNECT,
|
|
NbfRetryPreTdiConnect,
|
|
Irp))
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&connection->SpinLock, &oldirql);
|
|
connection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECT;
|
|
connection->Status = STATUS_PENDING;
|
|
RELEASE_SPIN_LOCK(&connection->SpinLock, oldirql);
|
|
NbfDereferenceConnection ("Automatic connection", connection, CREF_BY_ID);
|
|
//
|
|
// Set a special cancel routine on the irp
|
|
// in case we get cancelled during the
|
|
// automatic connection.
|
|
//
|
|
IoSetCancelRoutine(Irp, NbfCancelPreTdiConnect);
|
|
return STATUS_PENDING;
|
|
}
|
|
}
|
|
#endif // RASAUTODIAL
|
|
|
|
return NbfTdiConnectCommon(Irp);
|
|
} // NbfTdiConnect
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiConnectCommon(
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the TdiConnect request for the transport provider.
|
|
Note: the caller needs to call NbfVerifyConnectionObject(pConnection)
|
|
before calling this routine.
|
|
|
|
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 parameters;
|
|
TDI_ADDRESS_NETBIOS * RemoteAddress;
|
|
ULONG NameQueryTimeout;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("NbfTdiConnectCommon: Entered.\n");
|
|
}
|
|
|
|
//
|
|
// is the file object a connection?
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
connection = irpSp->FileObject->FsContext;
|
|
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)) {
|
|
|
|
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
|
NbfPrint1 ("TdiConnect: Modifying user timeout to %lx seconds.\n",
|
|
TDI_TIMEOUT_CONNECT);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need a request object to keep track of this TDI request.
|
|
// Attach this request to the new connection object.
|
|
//
|
|
|
|
status = NbfCreateRequest (
|
|
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.
|
|
NbfDereferenceConnection ("Throw away", connection, CREF_BY_ID);
|
|
return status; // return with failure.
|
|
} else {
|
|
|
|
// Reference the connection since NbfDestroyRequest derefs it.
|
|
|
|
NbfReferenceConnection("For connect request", connection, CREF_REQUEST);
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|
|
|
tpRequest->Owner = ConnectionType;
|
|
IoAcquireCancelSpinLock (&cancelirql);
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
IoReleaseCancelSpinLock (cancelirql);
|
|
NbfCompleteRequest (
|
|
tpRequest,
|
|
connection->Status,
|
|
0);
|
|
KeLowerIrql (oldirql);
|
|
NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
|
|
return STATUS_PENDING;
|
|
} else {
|
|
InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
|
|
|
|
//
|
|
// Initialize this now, we cut these down on an async medium
|
|
// that is disconnected.
|
|
//
|
|
|
|
connection->Retries = (USHORT)connection->Provider->NameQueryRetries;
|
|
NameQueryTimeout = connection->Provider->NameQueryTimeout;
|
|
|
|
if (connection->Provider->MacInfo.MediumAsync) {
|
|
|
|
//
|
|
// If we are on an async medium, then we need to send out
|
|
// a committed NAME_QUERY frame right from the start, since
|
|
// the FIND_NAME frames are not forwarded by the gateway.
|
|
//
|
|
|
|
connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
|
|
CONNECTION_FLAGS2_WAIT_NR); // wait for NAME_RECOGNIZED.
|
|
|
|
//
|
|
// Because we may call NbfTdiConnect twice
|
|
// via an automatic connection, check to see
|
|
// if an LSN has already been assigned.
|
|
//
|
|
if (!(connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN)) {
|
|
connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
|
|
|
|
if (NbfAssignGroupLsn(connection) != STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Could not find an empty LSN; have to fail.
|
|
//
|
|
RemoveEntryList(&tpRequest->Linkage);
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
IoReleaseCancelSpinLock (cancelirql);
|
|
NbfCompleteRequest (
|
|
tpRequest,
|
|
connection->Status,
|
|
0);
|
|
KeLowerIrql (oldirql);
|
|
NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
}
|
|
|
|
if (!connection->Provider->MediumSpeedAccurate) {
|
|
|
|
//
|
|
// The link is not up, so we cut our timeouts down.
|
|
// We still send one frame so that loopback works.
|
|
//
|
|
|
|
connection->Retries = 1;
|
|
NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Normal connection, we send out a FIND_NAME first.
|
|
//
|
|
|
|
connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
|
|
CONNECTION_FLAGS2_WAIT_NR_FN); // wait for NAME_RECOGNIZED.
|
|
|
|
}
|
|
|
|
connection->Flags2 &= ~(CONNECTION_FLAGS2_STOPPING |
|
|
CONNECTION_FLAGS2_INDICATING);
|
|
connection->Status = STATUS_PENDING;
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
//
|
|
// Check if the IRP has been cancelled.
|
|
//
|
|
|
|
if (Irp->Cancel) {
|
|
Irp->CancelIrql = cancelirql;
|
|
NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
|
|
KeLowerIrql (oldirql);
|
|
NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
IoSetCancelRoutine(Irp, NbfCancelConnection);
|
|
IoReleaseCancelSpinLock(cancelirql);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// On "easily disconnected" networks, quick reregister
|
|
// (one ADD_NAME_QUERY) the address if NEED_REREGISTER
|
|
// is set (happens when we get a five-second period
|
|
// with no multicast activity). If we are currently
|
|
// quick reregistering, wait for it to complete.
|
|
//
|
|
|
|
if (connection->Provider->EasilyDisconnected) {
|
|
|
|
PTP_ADDRESS Address;
|
|
LARGE_INTEGER Timeout;
|
|
|
|
//
|
|
// If the address needs (or is) reregistering, then do wait,
|
|
// setting a flag so the connect will be resumed when the
|
|
// reregistration times out.
|
|
//
|
|
|
|
Address = connection->AddressFile->Address;
|
|
|
|
ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
|
|
|
|
if ((Address->Flags &
|
|
(ADDRESS_FLAGS_NEED_REREGISTER | ADDRESS_FLAGS_QUICK_REREGISTER)) != 0) {
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_W_ADDRESS;
|
|
|
|
if (Address->Flags & ADDRESS_FLAGS_NEED_REREGISTER) {
|
|
|
|
Address->Flags &= ~ADDRESS_FLAGS_NEED_REREGISTER;
|
|
Address->Flags |= ADDRESS_FLAGS_QUICK_REREGISTER;
|
|
|
|
NbfReferenceAddress ("start registration", Address, AREF_TIMER);
|
|
RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
|
|
|
|
//
|
|
// Now start reregistration process by starting up a retransmission timer
|
|
// and begin sending ADD_NAME_QUERY NetBIOS frames.
|
|
//
|
|
|
|
Address->Retries = 1;
|
|
Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
|
|
Timeout.HighPart = -1;
|
|
KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
|
|
|
|
(VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
|
|
|
|
} else {
|
|
|
|
RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
|
|
|
|
}
|
|
KeLowerIrql (oldirql);
|
|
|
|
NbfDereferenceConnection("Temporary Use 4", connection, CREF_BY_ID);
|
|
|
|
return STATUS_PENDING; // things are started.
|
|
|
|
} else {
|
|
|
|
RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Send the NAME_QUERY frame as a FIND.NAME to get a NAME_RECOGNIZED
|
|
// frame back. The first time we send this frame, we are just looking
|
|
// for the data link information to decide whether we already have
|
|
// a link with the remote NetBIOS name. If we do, we can reuse it.
|
|
// If we don't, then we make one first, and then use it. A consequence
|
|
// of this is that we really engage in an extra non-committal NQ/NR
|
|
// exchange up front to locate the remote guy, and then commit to an actual
|
|
// LSN with a second NQ/NR sequence to establish the transport connection
|
|
//
|
|
|
|
NbfSendNameQuery (
|
|
connection,
|
|
TRUE);
|
|
|
|
//
|
|
// Start the connection timer (do this at the end, so that
|
|
// if we get delayed in this routine the connection won't
|
|
// get into an unexpected state).
|
|
//
|
|
|
|
NbfStartConnectionTimer (
|
|
connection,
|
|
ConnectionEstablishmentTimeout,
|
|
NameQueryTimeout);
|
|
|
|
KeLowerIrql (oldirql);
|
|
|
|
NbfDereferenceConnection("Temporary Use 3", connection, CREF_BY_ID);
|
|
|
|
return STATUS_PENDING; // things are started.
|
|
|
|
} /* TdiConnect */
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiDisconnect(
|
|
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;
|
|
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("TdiDisconnect: Entered.\n");
|
|
}
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
//
|
|
// If successful this adds a reference of type BY_ID.
|
|
//
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
#if DBG
|
|
if (NbfDisconnectDebug) {
|
|
STRING remoteName;
|
|
STRING localName;
|
|
remoteName.Length = NETBIOS_NAME_LENGTH - 1;
|
|
remoteName.Buffer = connection->RemoteName;
|
|
localName.Length = NETBIOS_NAME_LENGTH - 1;
|
|
localName.Buffer = connection->AddressFile->Address->NetworkName->NetbiosName;
|
|
NbfPrint2( "TdiDisconnect entered for connection to %S from %S\n",
|
|
&remoteName, &localName );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// if the connection is currently stopping, there's no reason to blow
|
|
// it away...
|
|
//
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
|
|
#if 0
|
|
NbfPrint2 ("TdiDisconnect: ignoring disconnect %lx, connection stopping (%lx)\n",
|
|
connection, connection->Status);
|
|
#endif
|
|
|
|
//
|
|
// In case a connect indication is in progress.
|
|
//
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
|
|
|
|
//
|
|
// If possible, queue the disconnect. This flag is cleared
|
|
// when the indication is about to be done.
|
|
//
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) &&
|
|
(connection->Flags2 & CONNECTION_FLAGS2_LDISC) == 0) {
|
|
#if DBG
|
|
DbgPrint ("NBF: Queueing disconnect irp %lx\n", Irp);
|
|
#endif
|
|
connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = connection->Status;
|
|
}
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
KeLowerIrql (oldirql);
|
|
NbfDereferenceConnection ("Ignoring disconnect", connection, CREF_BY_ID); // release our lookup reference.
|
|
return status;
|
|
|
|
}
|
|
|
|
connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
|
|
CONNECTION_FLAGS2_PRE_ACCEPT |
|
|
CONNECTION_FLAGS2_WAITING_SC);
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
|
|
connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
|
|
|
|
//
|
|
// Set this flag so the disconnect IRP is completed.
|
|
//
|
|
// If the connection goes down before we can
|
|
// call NbfStopConnection with STATUS_LOCAL_DISCONNECT,
|
|
// the disconnect IRP won't get completed.
|
|
//
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
|
|
|
|
// connection->DisconnectIrp = Irp;
|
|
|
|
//
|
|
// 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)) {
|
|
|
|
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
|
NbfPrint1 ("TdiDisconnect: Modifying user timeout to %lx seconds.\n",
|
|
TDI_TIMEOUT_CONNECT);
|
|
}
|
|
|
|
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->Flags2 |= CONNECTION_FLAGS2_DESTROY;
|
|
} else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
|
|
connection->Flags2 |= CONNECTION_FLAGS2_ABORT;
|
|
} else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
|
|
connection->Flags2 |= CONNECTION_FLAGS2_ORDREL;
|
|
}
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
|
|
NbfPrint1 ("TdiDisconnect calling NbfStopConnection %lx\n", connection);
|
|
}
|
|
|
|
//
|
|
// This will get passed to IoCompleteRequest during TdiDestroyConnection
|
|
//
|
|
|
|
NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
|
|
|
|
KeLowerIrql (oldirql);
|
|
|
|
NbfDereferenceConnection ("Disconnecting", connection, CREF_BY_ID); // release our lookup reference.
|
|
|
|
//
|
|
// This request will be completed by TdiDestroyConnection once
|
|
// the connection reference count drops to 0.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
} /* TdiDisconnect */
|
|
|
|
|
|
NTSTATUS
|
|
NbfTdiListen(
|
|
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;
|
|
PTDI_CONNECTION_INFORMATION ListenInformation;
|
|
TDI_ADDRESS_NETBIOS * ListenAddress;
|
|
PVOID RequestBuffer2;
|
|
ULONG RequestBuffer2Length;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("TdiListen: Entered.\n");
|
|
}
|
|
|
|
//
|
|
// validate this connection
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_CONNECTION_FILE) {
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection = irpSp->FileObject->FsContext;
|
|
|
|
//
|
|
// If successful this adds a reference of type BY_ID.
|
|
//
|
|
|
|
status = NbfVerifyConnectionObject (connection);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
|
|
|
|
//
|
|
// Record the remote address if there is one.
|
|
//
|
|
|
|
ListenInformation = parameters->RequestConnectionInformation;
|
|
|
|
if ((ListenInformation != NULL) &&
|
|
(ListenInformation->RemoteAddress != NULL)) {
|
|
|
|
if ((NbfValidateTdiAddress(
|
|
ListenInformation->RemoteAddress,
|
|
ListenInformation->RemoteAddressLength)) &&
|
|
((ListenAddress = NbfParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) != NULL)) {
|
|
|
|
RequestBuffer2 = (PVOID)ListenAddress->NetbiosName,
|
|
RequestBuffer2Length = NETBIOS_NAME_LENGTH;
|
|
|
|
} else {
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("TdiListen: Create Request Failed, bad address.\n");
|
|
}
|
|
|
|
NbfDereferenceConnection ("Bad address", connection, CREF_BY_ID);
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
}
|
|
|
|
} else {
|
|
|
|
RequestBuffer2 = NULL;
|
|
RequestBuffer2Length = 0;
|
|
}
|
|
|
|
//
|
|
// We need a request object to keep track of this TDI request.
|
|
// Attach this request to the new connection object.
|
|
//
|
|
|
|
status = NbfCreateRequest (
|
|
Irp, // IRP for this request.
|
|
connection, // context.
|
|
REQUEST_FLAGS_CONNECTION, // partial flags.
|
|
RequestBuffer2,
|
|
RequestBuffer2Length,
|
|
timeout, // timeout value (can be 0).
|
|
&tpRequest);
|
|
|
|
|
|
if (!NT_SUCCESS (status)) { // couldn't make the request.
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint1 ("TdiListen: Create Request Failed, reason: %lx.\n", status);
|
|
}
|
|
|
|
NbfDereferenceConnection ("For create", connection, CREF_BY_ID);
|
|
return status; // return with failure.
|
|
}
|
|
|
|
// Reference the connection since NbfDestroyRequest derefs it.
|
|
|
|
IoAcquireCancelSpinLock (&cancelirql);
|
|
ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql);
|
|
tpRequest->Owner = ConnectionType;
|
|
|
|
NbfReferenceConnection("For listen request", connection, CREF_REQUEST);
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
|
|
|
|
RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
|
|
IoReleaseCancelSpinLock(cancelirql);
|
|
|
|
NbfCompleteRequest (
|
|
tpRequest,
|
|
connection->Status,
|
|
0);
|
|
NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
|
|
return STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
|
|
connection->Flags2 |= (CONNECTION_FLAGS2_LISTENER | // we're the passive one.
|
|
CONNECTION_FLAGS2_WAIT_NQ); // wait for NAME_QUERY.
|
|
connection->Flags2 &= ~(CONNECTION_FLAGS2_INDICATING |
|
|
CONNECTION_FLAGS2_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_C_SPIN_LOCK (&connection->SpinLock,oldirql);
|
|
|
|
//
|
|
// Check if the IRP has been cancelled.
|
|
//
|
|
|
|
if (Irp->Cancel) {
|
|
Irp->CancelIrql = cancelirql;
|
|
NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
|
|
NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
IoSetCancelRoutine(Irp, NbfCancelConnection);
|
|
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.
|
|
//
|
|
|
|
NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
|
|
|
|
return STATUS_PENDING; // things are started.
|
|
} /* TdiListen */
|
|
|
|
|
|
NTSTATUS
|
|
NbfOpenConnection (
|
|
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);
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint0 ("NbfOpenConnection: Entered.\n");
|
|
}
|
|
|
|
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
|
|
|
|
|
// Make sure we have a connection context specified in the EA info
|
|
ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (ea->EaValueLength < sizeof(PVOID)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Then, try to make a connection object to represent this pending
|
|
// connection. Then fill in the relevant fields.
|
|
// In addition to the creation, if successful NbfCreateConnection
|
|
// will create a second reference which is removed once the request
|
|
// references the connection, or if the function exits before that.
|
|
|
|
status = NbfCreateConnection (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
|
|
//
|
|
|
|
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;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT) {
|
|
NbfPrint1 ("NBFOpenConnection: Opened Connection %lx.\n",
|
|
connection);
|
|
}
|
|
|
|
return status;
|
|
|
|
} /* NbfOpenConnection */
|
|
|
|
#if DBG
|
|
VOID
|
|
ConnectionCloseTimeout(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
|
|
{
|
|
PTP_CONNECTION Connection;
|
|
|
|
Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
|
|
|
|
Connection = (PTP_CONNECTION)DeferredContext;
|
|
|
|
DbgPrint ("NBF: Close of connection %lxpending for 2 minutes\n",
|
|
Connection);
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NbfCloseConnection (
|
|
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;
|
|
|
|
IF_NBFDBG (NBF_DEBUG_CONNECT | NBF_DEBUG_PNP) {
|
|
NbfPrint1 ("NbfCloseConnection CO %lx:\n",connection);
|
|
}
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|
|
|
//
|
|
// 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 == NBF_CONNECTION_SIGNATURE)) {
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
KeLowerIrql (oldirql);
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
KeLowerIrql (oldirql);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// We recognize it; is it closing already?
|
|
//
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
KeLowerIrql (oldirql);
|
|
#if DBG
|
|
NbfPrint1("Closing already-closing connection %lx\n", connection);
|
|
#endif
|
|
return STATUS_INVALID_CONNECTION;
|
|
}
|
|
|
|
connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
|
|
|
|
//
|
|
// if there is activity on the connection, tear it down.
|
|
//
|
|
|
|
if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
}
|
|
|
|
//
|
|
// 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_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
} else {
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
}
|
|
|
|
//
|
|
// Save this to complete the IRP later.
|
|
//
|
|
|
|
connection->CloseIrp = Irp;
|
|
|
|
#if 0
|
|
//
|
|
// make it impossible to use this connection from the file object
|
|
//
|
|
|
|
IrpSp->FileObject->FsContext = NULL;
|
|
IrpSp->FileObject->FsContext2 = NULL;
|
|
connection->FileObject = NULL;
|
|
#endif
|
|
|
|
#if DBG
|
|
{
|
|
LARGE_INTEGER Timeout;
|
|
BOOLEAN AlreadyInserted;
|
|
|
|
Timeout.LowPart = (ULONG)(-(120*SECONDS));
|
|
Timeout.HighPart = -1;
|
|
|
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
AlreadyInserted = KeCancelTimer (&connection->Timer);
|
|
|
|
KeInitializeDpc (
|
|
&connection->Dpc,
|
|
ConnectionCloseTimeout,
|
|
(PVOID)connection);
|
|
|
|
KeSetTimer (
|
|
&connection->Timer,
|
|
Timeout,
|
|
&connection->Dpc);
|
|
|
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|
|
|
if (AlreadyInserted) {
|
|
DbgPrint ("NBF: Cancelling connection timer for debug %lx\n", connection);
|
|
NbfDereferenceConnection ("debug", connection, CREF_TIMER);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
KeLowerIrql (oldirql);
|
|
|
|
//
|
|
// dereference for the creation. Note that this dereference
|
|
// here won't have any effect until the regular reference count
|
|
// hits zero.
|
|
//
|
|
|
|
NbfDereferenceConnectionSpecial (" Closing Connection", connection, CREF_SPECIAL_CREATION);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
} /* NbfCloseConnection */
|
|
|
|
|