640 lines
17 KiB
C
640 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
autodial.c
|
||
|
||
Abstract:
|
||
|
||
This file provides routines for interacting
|
||
with the automatic connection driver (acd.sys).
|
||
|
||
Author:
|
||
|
||
Anthony Discolo (adiscolo) 9-6-95
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "precomp.h" // procedure headings
|
||
|
||
#ifdef RASAUTODIAL
|
||
|
||
#ifndef VXD
|
||
#include <acd.h>
|
||
#include <acdapi.h>
|
||
#endif
|
||
|
||
//******************* Pageable Routine Declarations ****************
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma CTEMakePageable(INIT, NbtAcdBind)
|
||
#pragma CTEMakePageable(PAGE, NbtAcdUnbind)
|
||
#endif
|
||
//******************* Pageable Routine Declarations ****************
|
||
|
||
|
||
//
|
||
// Automatic connection global variables.
|
||
//
|
||
BOOLEAN fAcdLoadedG;
|
||
ACD_DRIVER AcdDriverG;
|
||
ULONG ulDriverIdG = 'Nbt ';
|
||
|
||
//
|
||
// Imported routines.
|
||
//
|
||
VOID
|
||
CleanUpPartialConnection(
|
||
IN NTSTATUS status,
|
||
IN tCONNECTELE *pConnEle,
|
||
IN tDGRAM_SEND_TRACKING *pTracker,
|
||
IN PIRP pClientIrp,
|
||
IN CTELockHandle irqlJointLock,
|
||
IN CTELockHandle irqlConnEle
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtConnectCommon(
|
||
IN TDI_REQUEST *pRequest,
|
||
IN PVOID pTimeout,
|
||
IN PTDI_CONNECTION_INFORMATION pCallInfo,
|
||
IN PIRP pIrp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbtpConnectCompletionRoutine(
|
||
PDEVICE_OBJECT pDeviceObject,
|
||
PIRP pIrp,
|
||
PVOID pCompletionContext
|
||
);
|
||
|
||
|
||
VOID
|
||
NbtRetryPreConnect(
|
||
IN BOOLEAN fSuccess,
|
||
IN PVOID *pArgs
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called indirectly by the automatic
|
||
connection driver to continue the connection process
|
||
after an automatic connection has been made.
|
||
|
||
Arguments:
|
||
|
||
fSuccess - TRUE if the connection attempt was successful.
|
||
|
||
pArgs - a pointer to the argument vector
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
tCONNECTELE *pConnEle = pArgs[0];
|
||
PVOID pTimeout = pArgs[1];
|
||
PTDI_CONNECTION_INFORMATION pCallInfo = pArgs[2];
|
||
PIRP pIrp = pArgs[3];
|
||
TDI_REQUEST request;
|
||
KIRQL irql;
|
||
CTELockHandle OldIrq;
|
||
tDEVICECONTEXT *pDeviceContext = pConnEle->pDeviceContext;
|
||
|
||
IF_DBG(NBT_DEBUG_NAME)
|
||
KdPrint(("Nbt.NbtRetryPreConnect: fSuccess=%d, pIrp=0x%x, pIrp->Cancel=%d, pConnEle=0x%x\n",
|
||
fSuccess, pIrp, pIrp->Cancel, pConnEle));
|
||
|
||
request.Handle.ConnectionContext = pConnEle;
|
||
status = NbtCancelCancelRoutine (pIrp);
|
||
if (status != STATUS_CANCELLED)
|
||
{
|
||
//
|
||
// We're done with the connection progress,
|
||
// so clear the fAutoConnecting flag. We
|
||
// set the fAutoConnected flag to prevent us
|
||
// from re-attempting another automatic
|
||
// connection on this connection.
|
||
//
|
||
CTESpinLock(pConnEle,OldIrq);
|
||
pConnEle->fAutoConnecting = FALSE;
|
||
pConnEle->fAutoConnected = TRUE;
|
||
CTESpinFree(pConnEle,OldIrq);
|
||
|
||
status = fSuccess ? NbtConnectCommon (&request, pTimeout, pCallInfo, pIrp) :
|
||
STATUS_BAD_NETWORK_PATH;
|
||
//
|
||
// We are responsible for completing
|
||
// the irp.
|
||
//
|
||
if (status != STATUS_PENDING)
|
||
{
|
||
//
|
||
// Clear out the Irp pointer in the Connection object so that we dont try to
|
||
// complete it again when we clean up the connection. Do this under the connection
|
||
// lock.
|
||
//
|
||
CTESpinLock(pConnEle,OldIrq);
|
||
pConnEle->pIrp = NULL;
|
||
CTESpinFree(pConnEle,OldIrq);
|
||
|
||
pIrp->IoStatus.Status = status;
|
||
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_AUTODIAL, FALSE);
|
||
}
|
||
} // NbtRetryPreConnect
|
||
|
||
|
||
|
||
BOOLEAN
|
||
NbtCancelAutoDialRequest(
|
||
IN PVOID pArg,
|
||
IN ULONG ulFlags,
|
||
IN ACD_CONNECT_CALLBACK pProc,
|
||
IN USHORT nArgs,
|
||
IN PVOID *pArgs
|
||
)
|
||
{
|
||
if (nArgs != 5)
|
||
return FALSE;
|
||
|
||
return (pArgs[4] == pArg);
|
||
} // NbtCancelAutoDialRequest
|
||
|
||
|
||
|
||
BOOLEAN
|
||
NbtCancelPreConnect(
|
||
IN PDEVICE_OBJECT pDeviceObject,
|
||
IN PIRP pIrp
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
tCONNECTELE *pConnEle;
|
||
KIRQL irql;
|
||
ACD_ADDR *pAddr;
|
||
BOOLEAN fCancelled;
|
||
CTELockHandle OldIrq;
|
||
|
||
UNREFERENCED_PARAMETER(pDeviceObject);
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
pConnEle = (tCONNECTELE *) pIrpSp->FileObject->FsContext;
|
||
if ((!pConnEle) ||
|
||
(!NBT_VERIFY_HANDLE2 (pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN)) ||
|
||
(!(pAddr = (ACD_ADDR *) NbtAllocMem(sizeof(ACD_ADDR),NBT_TAG('A')))))
|
||
{
|
||
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
||
ASSERTMSG ("Nbt.NbtCancelPreConnect: ERROR - Invalid Connection Handle\n", 0);
|
||
return FALSE;
|
||
}
|
||
|
||
IF_DBG(NBT_DEBUG_NAME)
|
||
KdPrint(("NbtCancelPreConnect: pIrp=0x%x, pConnEle=0x%x\n", pIrp, pConnEle));
|
||
//
|
||
// Get the address of the connection.
|
||
//
|
||
pAddr->fType = ACD_ADDR_NB;
|
||
RtlCopyMemory(&pAddr->cNetbios, pConnEle->RemoteName, 16);
|
||
//
|
||
// Cancel the autodial request.
|
||
//
|
||
fCancelled = (*AcdDriverG.lpfnCancelConnection) (ulDriverIdG, pAddr, NbtCancelAutoDialRequest, pIrp);
|
||
if (fCancelled)
|
||
{
|
||
IoSetCancelRoutine(pIrp, NULL);
|
||
}
|
||
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
||
|
||
CTEMemFree(pAddr);
|
||
|
||
//
|
||
// If the request could not be found
|
||
// in the driver, then it has already
|
||
// been completed, so we simply return.
|
||
//
|
||
if (!fCancelled)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, &irql);
|
||
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
||
pIrp->IoStatus.Information = 0;
|
||
|
||
NBT_DEREFERENCE_DEVICE (pConnEle->pDeviceContext, REF_DEV_AUTODIAL, FALSE);
|
||
|
||
//
|
||
// Clear out the Irp pointer in the Connection object so that we dont try to
|
||
// complete it again when we clean up the connection. Do this under the connection
|
||
// lock.
|
||
//
|
||
// This should not be needed since before we call NbtConnectCommon, the Cancel routine
|
||
// is NULLed out, so it cannot happen that the pIrp ptr in the connection is set to the
|
||
// Irp, and this cancel routine is called.
|
||
//
|
||
|
||
CTESpinLock(pConnEle,OldIrq);
|
||
pConnEle->pIrp = NULL;
|
||
CTESpinFree(pConnEle,OldIrq);
|
||
|
||
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
KeLowerIrql(irql);
|
||
|
||
return TRUE;
|
||
} // NbtCancelPreConnect
|
||
|
||
|
||
BOOLEAN
|
||
NbtCancelPostConnect(
|
||
IN PIRP pIrp
|
||
)
|
||
{
|
||
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
tCONNECTELE *pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
|
||
ACD_ADDR *pAddr;
|
||
BOOLEAN fCancelled;
|
||
|
||
if ((!pConnEle) ||
|
||
(!NBT_VERIFY_HANDLE2 (pConnEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN)) ||
|
||
(!(pAddr = (ACD_ADDR *) NbtAllocMem(sizeof(ACD_ADDR),NBT_TAG('A')))))
|
||
{
|
||
ASSERTMSG ("Nbt.NbtCancelPostConnect: ERROR - Invalid Connection Handle\n", 0);
|
||
return FALSE;
|
||
}
|
||
|
||
IF_DBG(NBT_DEBUG_NAME)
|
||
KdPrint(("Nbt.NbtCancelPostConnect: pIrp=0x%x, pConnEle=0x%x\n", pIrp, pConnEle));
|
||
//
|
||
// Get the address of the connection.
|
||
//
|
||
pAddr->fType = ACD_ADDR_NB;
|
||
RtlCopyMemory(&pAddr->cNetbios, pConnEle->RemoteName, 15);
|
||
|
||
//
|
||
// Cancel the autodial request.
|
||
//
|
||
fCancelled = (*AcdDriverG.lpfnCancelConnection) (ulDriverIdG, pAddr, NbtCancelAutoDialRequest, pIrp);
|
||
if (fCancelled)
|
||
{
|
||
NBT_DEREFERENCE_DEVICE (pConnEle->pDeviceContext, REF_DEV_AUTODIAL, FALSE);
|
||
}
|
||
|
||
CTEMemFree(pAddr);
|
||
return (fCancelled);
|
||
} // NbtCancelPostConnect
|
||
|
||
|
||
|
||
BOOLEAN
|
||
NbtAttemptAutoDial(
|
||
IN tCONNECTELE *pConnEle,
|
||
IN PVOID pTimeout,
|
||
IN PTDI_CONNECTION_INFORMATION pCallInfo,
|
||
IN PIRP pIrp,
|
||
IN ULONG ulFlags,
|
||
IN ACD_CONNECT_CALLBACK pProc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call the automatic connection driver to attempt an
|
||
automatic connection. The first five parameters are
|
||
used in the call to NbtConnect after the connection
|
||
completes successfully.
|
||
|
||
Arguments:
|
||
|
||
...
|
||
|
||
ulFlags - automatic connection flags
|
||
|
||
pProc - callback procedure when the automatic connection completes
|
||
|
||
Return Value:
|
||
|
||
TRUE if the automatic connection was started successfully,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
BOOLEAN fSuccess;
|
||
ACD_ADDR *pAddr = NULL;
|
||
KIRQL irql;
|
||
PVOID pArgs[4];
|
||
PCHAR pName;
|
||
ULONG ulcbName;
|
||
LONG lNameType;
|
||
TDI_ADDRESS_NETBT_INTERNAL TdiAddr;
|
||
PIO_STACK_LOCATION pIrpSp;
|
||
|
||
ASSERT(pCallInfo);
|
||
|
||
//
|
||
// If this connection has already been through the
|
||
// automatic connection process, don't do it again.
|
||
//
|
||
if ((pConnEle->fAutoConnected)) {
|
||
return FALSE;
|
||
}
|
||
|
||
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
if (pIrpSp->CompletionRoutine != NbtpConnectCompletionRoutine) {
|
||
status = GetNetBiosNameFromTransportAddress((PTRANSPORT_ADDRESS) pCallInfo->RemoteAddress,
|
||
pCallInfo->RemoteAddressLength, &TdiAddr);
|
||
} else {
|
||
ASSERT(((PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress)->Address[0].AddressType == TDI_ADDRESS_TYPE_UNSPEC);
|
||
CTEMemCopy(&TdiAddr,
|
||
(PTDI_ADDRESS_NETBT_INTERNAL)((PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress)->Address[0].Address,
|
||
sizeof(TdiAddr));
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
if (status != STATUS_SUCCESS || (!NBT_REFERENCE_DEVICE (pConnEle->pDeviceContext, REF_DEV_AUTODIAL, FALSE)) ||
|
||
(!(pAddr = (ACD_ADDR *) NbtAllocMem(sizeof(ACD_ADDR),NBT_TAG('A'))))) {
|
||
if (pAddr) {
|
||
CTEMemFree(pAddr);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
pName = TdiAddr.OEMRemoteName.Buffer;
|
||
ulcbName = TdiAddr.OEMRemoteName.Length;
|
||
lNameType = TdiAddr.NameType;
|
||
|
||
//
|
||
// Save the address for pre-connect attempts,
|
||
// because if we have to cancel this irp,
|
||
// it is not saved anywhere else.
|
||
//
|
||
CTESpinLock(pConnEle, irql);
|
||
pConnEle->fAutoConnecting = TRUE;
|
||
CTEMemCopy(pConnEle->RemoteName, pName, NETBIOS_NAME_SIZE);
|
||
CTESpinFree(pConnEle, irql);
|
||
pAddr->fType = ACD_ADDR_NB;
|
||
RtlCopyMemory(&pAddr->cNetbios, pName, NETBIOS_NAME_SIZE);
|
||
|
||
IF_DBG(NBT_DEBUG_NAME)
|
||
KdPrint(("Nbt.NbtAttemptAutodial: szAddr=%-15.15s\n", pName));
|
||
//
|
||
// Enqueue this request on the network
|
||
// connection pending queue.
|
||
//
|
||
pArgs[0] = pConnEle;
|
||
pArgs[1] = pTimeout;
|
||
pArgs[2] = pCallInfo;
|
||
pArgs[3] = pIrp;
|
||
fSuccess = (*AcdDriverG.lpfnStartConnection) (ulDriverIdG, pAddr, ulFlags, pProc, 4, pArgs);
|
||
|
||
//
|
||
// If fSuccess is TRUE, then it means that the NetBT proc has
|
||
// already been called to setup the connection, and hence the
|
||
// data in pConnEle may not be valid now
|
||
//
|
||
// In the case it is FALSE, then pProc has not been called, and
|
||
// we should set the fAutoConnecting flag to FALSE also
|
||
//
|
||
if (!fSuccess)
|
||
{
|
||
NBT_DEREFERENCE_DEVICE (pConnEle->pDeviceContext, REF_DEV_AUTODIAL, FALSE);
|
||
CTESpinLock(pConnEle, irql);
|
||
pConnEle->fAutoConnecting = FALSE;
|
||
CTESpinFree(pConnEle, irql);
|
||
}
|
||
|
||
CTEMemFree(pAddr);
|
||
return fSuccess;
|
||
} // NbtAttemptAutoDial
|
||
|
||
|
||
|
||
VOID
|
||
NbtNoteNewConnection(
|
||
IN tNAMEADDR *pNameAddr,
|
||
IN ULONG IpAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Inform the automatic connection driver of a
|
||
successful new connection.
|
||
|
||
Arguments:
|
||
|
||
pNameAddr - a pointer to the remote name
|
||
IpAddress - Source IP address of the connection
|
||
|
||
Return Value:
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ACD_ADDR *pAddr = NULL;
|
||
ACD_ADAPTER *pAdapter = NULL;
|
||
|
||
//
|
||
// Notify the AcdDriver only if we have a valid Source address
|
||
//
|
||
// We can end up blowing the stack if we pre-allocate ACD_ADDR
|
||
// and ACD_ADAPTER on the stack -- so allocate them dynamically!
|
||
//
|
||
if ((IpAddress) &&
|
||
(pAddr = (ACD_ADDR *) NbtAllocMem(sizeof(ACD_ADDR),NBT_TAG('A'))) &&
|
||
(pAdapter = (ACD_ADAPTER *) NbtAllocMem(sizeof(ACD_ADAPTER),NBT_TAG('A'))))
|
||
{
|
||
pAddr->fType = ACD_ADDR_NB;
|
||
RtlCopyMemory(&pAddr->cNetbios, pNameAddr->Name, 15);
|
||
|
||
pAdapter->fType = ACD_ADAPTER_IP;
|
||
pAdapter->ulIpaddr = htonl(IpAddress); // Get the source IP address of the connection.
|
||
|
||
(*AcdDriverG.lpfnNewConnection) (pAddr, pAdapter);
|
||
}
|
||
|
||
if (pAddr)
|
||
{
|
||
CTEMemFree(pAddr);
|
||
}
|
||
|
||
if (pAdapter)
|
||
{
|
||
CTEMemFree(pAdapter);
|
||
}
|
||
} // NbtNoteNewConnection
|
||
|
||
|
||
|
||
VOID
|
||
NbtAcdBind()
|
||
{
|
||
NTSTATUS status;
|
||
UNICODE_STRING nameString;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
PIRP pIrp;
|
||
PFILE_OBJECT pAcdFileObject;
|
||
PDEVICE_OBJECT pAcdDeviceObject;
|
||
PACD_DRIVER pDriver = &AcdDriverG;
|
||
|
||
//
|
||
// Initialize the name of the automatic
|
||
// connection device.
|
||
//
|
||
RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
|
||
//
|
||
// Get the file and device objects for the
|
||
// device.
|
||
//
|
||
status = IoGetDeviceObjectPointer(
|
||
&nameString,
|
||
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
||
&pAcdFileObject,
|
||
&pAcdDeviceObject);
|
||
if (status != STATUS_SUCCESS)
|
||
return;
|
||
//
|
||
// Reference the device object.
|
||
//
|
||
ObReferenceObject(pAcdDeviceObject);
|
||
//
|
||
// Remove the reference IoGetDeviceObjectPointer()
|
||
// put on the file object.
|
||
//
|
||
ObDereferenceObject(pAcdFileObject);
|
||
//
|
||
// Initialize our part of the ACD_DRIVER
|
||
// structure.
|
||
//
|
||
KeInitializeSpinLock(&AcdDriverG.SpinLock);
|
||
AcdDriverG.ulDriverId = ulDriverIdG;
|
||
AcdDriverG.fEnabled = FALSE;
|
||
//
|
||
// Build a request to get the automatic
|
||
// connection driver entry points.
|
||
//
|
||
pIrp = IoBuildDeviceIoControlRequest (IOCTL_INTERNAL_ACD_BIND,
|
||
pAcdDeviceObject,
|
||
(PVOID)&pDriver,
|
||
sizeof (pDriver),
|
||
NULL,
|
||
0,
|
||
TRUE,
|
||
NULL,
|
||
&ioStatusBlock);
|
||
if (pIrp == NULL)
|
||
{
|
||
ObDereferenceObject(pAcdDeviceObject);
|
||
return;
|
||
}
|
||
//
|
||
// Submit the request to the
|
||
// automatic connection driver.
|
||
//
|
||
status = IoCallDriver(pAcdDeviceObject, pIrp);
|
||
fAcdLoadedG = (status == STATUS_SUCCESS);
|
||
//
|
||
// Close the device.
|
||
//
|
||
ObDereferenceObject(pAcdDeviceObject);
|
||
} // NbtAcdBind
|
||
|
||
|
||
|
||
VOID
|
||
NbtAcdUnbind()
|
||
{
|
||
NTSTATUS status;
|
||
UNICODE_STRING nameString;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
PIRP pIrp;
|
||
PFILE_OBJECT pAcdFileObject;
|
||
PDEVICE_OBJECT pAcdDeviceObject;
|
||
PACD_DRIVER pDriver = &AcdDriverG;
|
||
|
||
//
|
||
// Don't bother to unbind if we
|
||
// didn't successfully bind in the
|
||
// first place.
|
||
//
|
||
if (!fAcdLoadedG)
|
||
{
|
||
return;
|
||
}
|
||
|
||
fAcdLoadedG = FALSE;
|
||
|
||
//
|
||
// Initialize the name of the automatic
|
||
// connection device.
|
||
//
|
||
RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
|
||
//
|
||
// Get the file and device objects for the
|
||
// device.
|
||
//
|
||
status = IoGetDeviceObjectPointer (&nameString,
|
||
SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
|
||
&pAcdFileObject,
|
||
&pAcdDeviceObject);
|
||
if (status != STATUS_SUCCESS)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Reference the device object.
|
||
//
|
||
ObReferenceObject(pAcdDeviceObject);
|
||
//
|
||
// Remove the reference IoGetDeviceObjectPointer()
|
||
// put on the file object.
|
||
//
|
||
ObDereferenceObject(pAcdFileObject);
|
||
//
|
||
// Build a request to unbind from
|
||
// the automatic connection driver.
|
||
//
|
||
pIrp = IoBuildDeviceIoControlRequest (IOCTL_INTERNAL_ACD_UNBIND,
|
||
pAcdDeviceObject,
|
||
(PVOID)&pDriver,
|
||
sizeof (pDriver),
|
||
NULL,
|
||
0,
|
||
TRUE,
|
||
NULL,
|
||
&ioStatusBlock);
|
||
if (pIrp == NULL)
|
||
{
|
||
ObDereferenceObject(pAcdDeviceObject);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Submit the request to the
|
||
// automatic connection driver.
|
||
//
|
||
status = IoCallDriver(pAcdDeviceObject, pIrp);
|
||
//
|
||
// Close the device.
|
||
//
|
||
ObDereferenceObject(pAcdDeviceObject);
|
||
} // NbtAcdUnbind
|
||
|
||
#endif // RASAUTODIAL
|