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.
723 lines
18 KiB
723 lines
18 KiB
/*++
|
|
|
|
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 "nbtprocs.h" // procedure headings
|
|
|
|
#ifdef RASAUTODIAL
|
|
|
|
#ifndef VXD
|
|
#include <nbtioctl.h>
|
|
#include <acd.h>
|
|
#include <acdapi.h>
|
|
#endif
|
|
|
|
//
|
|
// 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 PTDI_CONNECTION_INFORMATION pReturnInfo,
|
|
IN PIRP pIrp
|
|
);
|
|
|
|
|
|
|
|
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];
|
|
PTDI_CONNECTION_INFORMATION pReturnInfo = pArgs[3];
|
|
PIRP pIrp = pArgs[4];
|
|
TDI_REQUEST request;
|
|
KIRQL irql;
|
|
CTELockHandle OldIrq;
|
|
|
|
#ifdef notdef // DBG
|
|
DbgPrint(
|
|
"NbtRetryPreConnect: fSuccess=%d, pIrp=0x%x, pIrp->Cancel=%d, pConnEle=0x%x\n",
|
|
fSuccess,
|
|
pIrp,
|
|
pIrp->Cancel,
|
|
pConnEle);
|
|
#endif
|
|
request.Handle.ConnectionContext = pConnEle;
|
|
status = NTCancelCancelRoutine ( 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,
|
|
pReturnInfo,
|
|
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);
|
|
}
|
|
}
|
|
} // 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 addr;
|
|
BOOLEAN fCanceled;
|
|
|
|
UNREFERENCED_PARAMETER(pDeviceObject);
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
|
|
if (pConnEle == NULL)
|
|
return FALSE;
|
|
#ifdef notdef // DBG
|
|
DbgPrint("NbtCancelPreConnect: pIrp=0x%x, pConnEle=0x%x\n",
|
|
pIrp,
|
|
pConnEle);
|
|
#endif
|
|
//
|
|
// Get the address of the connection.
|
|
//
|
|
addr.fType = ACD_ADDR_NB;
|
|
RtlCopyMemory(&addr.cNetbios, pConnEle->RemoteName, 16);
|
|
//
|
|
// Cancel the autodial request.
|
|
//
|
|
fCanceled = (*AcdDriverG.lpfnCancelConnection)(
|
|
ulDriverIdG,
|
|
&addr,
|
|
NbtCancelAutoDialRequest,
|
|
pIrp);
|
|
if (fCanceled)
|
|
IoSetCancelRoutine(pIrp, NULL);
|
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|
//
|
|
// If the request could not be found
|
|
// in the driver, then it has already
|
|
// been completed, so we simply return.
|
|
//
|
|
if (!fCanceled)
|
|
return FALSE;
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &irql);
|
|
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
{
|
|
//
|
|
// 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.
|
|
//
|
|
// BUGBUG[WISHLIST] 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.
|
|
//
|
|
CTELockHandle OldIrq;
|
|
|
|
CTESpinLock(pConnEle,OldIrq);
|
|
|
|
pConnEle->pIrp = NULL;
|
|
|
|
CTESpinFree(pConnEle,OldIrq);
|
|
}
|
|
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
KeLowerIrql(irql);
|
|
|
|
return TRUE;
|
|
} // NbtCancelPreConnect
|
|
|
|
|
|
|
|
VOID
|
|
NbtRetryPostConnect(
|
|
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];
|
|
PTDI_CONNECTION_INFORMATION pReturnInfo = pArgs[3];
|
|
PIRP pIrp = pArgs[4];
|
|
tDGRAM_SEND_TRACKING *pTracker = (tDGRAM_SEND_TRACKING *)pReturnInfo;
|
|
TDI_REQUEST request;
|
|
CTELockHandle irqlConnEle, irqlJointLock;
|
|
KIRQL irql;
|
|
|
|
#ifdef notdef // DBG
|
|
DbgPrint(
|
|
"NbtRetryPostConnect: fSuccess=%d, pIrp=0x%x, pIrp->Cancel=%d, pConnEle=0x%x\n",
|
|
fSuccess,
|
|
pIrp,
|
|
pIrp->Cancel,
|
|
pConnEle);
|
|
#endif
|
|
if (fSuccess) {
|
|
//
|
|
// We set the state here to fool NbtConnect
|
|
// into doing a reconnect.
|
|
//
|
|
request.Handle.ConnectionContext = pConnEle;
|
|
pConnEle->state = NBT_ASSOCIATED;
|
|
status = NTCancelCancelRoutine ( pIrp );
|
|
if ( status != STATUS_CANCELLED )
|
|
{
|
|
status = NbtConnectCommon(
|
|
&request,
|
|
pTimeout,
|
|
pCallInfo,
|
|
pReturnInfo,
|
|
pIrp);
|
|
//
|
|
// 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.
|
|
//
|
|
CTELockHandle OldIrq;
|
|
|
|
CTESpinLock(pConnEle,OldIrq);
|
|
|
|
ASSERT(pIrp == pConnEle->pIrp);
|
|
pConnEle->pIrp = NULL;
|
|
|
|
CTESpinFree(pConnEle, OldIrq);
|
|
|
|
pIrp->IoStatus.Status = status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
CTESpinLock(&NbtConfig.JointLock,irqlJointLock);
|
|
CTESpinLock(pConnEle,irqlConnEle);
|
|
CleanUpPartialConnection(
|
|
STATUS_BAD_NETWORK_PATH,
|
|
pConnEle,
|
|
pTracker,
|
|
pIrp,
|
|
irqlJointLock,
|
|
irqlConnEle);
|
|
}
|
|
} // NbtRetryPostConnect
|
|
|
|
|
|
|
|
VOID
|
|
NbtCancelPostConnect(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
tCONNECTELE *pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
|
|
ACD_ADDR addr;
|
|
|
|
if (pConnEle == NULL)
|
|
return;
|
|
#ifdef notdef // DBG
|
|
DbgPrint(
|
|
"NbtCancelPostConnect: pIrp=0x%x, pConnEle=0x%x\n",
|
|
pIrp,
|
|
pConnEle);
|
|
#endif
|
|
//
|
|
// Get the address of the connection.
|
|
//
|
|
addr.fType = ACD_ADDR_NB;
|
|
RtlCopyMemory(&addr.cNetbios, pConnEle->RemoteName, 15);
|
|
//
|
|
// Cancel the autodial request.
|
|
//
|
|
(*AcdDriverG.lpfnCancelConnection)(
|
|
ulDriverIdG,
|
|
&addr,
|
|
NbtCancelAutoDialRequest,
|
|
pIrp);
|
|
} // NbtCancelPostConnect
|
|
|
|
|
|
|
|
BOOLEAN
|
|
NbtAttemptAutoDial(
|
|
IN tCONNECTELE *pConnEle,
|
|
IN PVOID pTimeout,
|
|
IN PTDI_CONNECTION_INFORMATION pCallInfo,
|
|
IN PTDI_CONNECTION_INFORMATION pReturnInfo,
|
|
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 addr;
|
|
KIRQL irql;
|
|
PVOID pArgs[5];
|
|
PTRANSPORT_ADDRESS pRemoteAddress;
|
|
PTA_NETBIOS_ADDRESS pRemoteNetBiosAddress;
|
|
PTA_NETBIOS_EX_ADDRESS pRemoteNetbiosExAddress;
|
|
ULONG tdiAddressType;
|
|
PCHAR pName;
|
|
ULONG ulcbName;
|
|
LONG lNameType;
|
|
|
|
//
|
|
// If this connection has already been through the
|
|
// automatic connection process, don't do it again.
|
|
//
|
|
if (pCallInfo == NULL || pConnEle->fAutoConnected)
|
|
return FALSE;
|
|
//
|
|
// Get the address of the connection.
|
|
//
|
|
pRemoteAddress = (PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress;
|
|
tdiAddressType = pRemoteAddress->Address[0].AddressType;
|
|
if (tdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
|
|
PTDI_ADDRESS_NETBIOS pNetbiosAddress;
|
|
|
|
pRemoteNetbiosExAddress = (PTA_NETBIOS_EX_ADDRESS)pRemoteAddress;
|
|
pNetbiosAddress = &pRemoteNetbiosExAddress->Address[0].Address[0].NetbiosAddress;
|
|
pName = pNetbiosAddress->NetbiosName;
|
|
lNameType = pNetbiosAddress->NetbiosNameType;
|
|
ulcbName = pRemoteNetbiosExAddress->Address[0].AddressLength -
|
|
FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) -
|
|
FIELD_OFFSET(TDI_ADDRESS_NETBIOS,NetbiosName);
|
|
IF_DBG(NBT_DEBUG_NETBIOS_EX) {
|
|
KdPrint((
|
|
"NetBt:NETBIOS address ulNameLen(%ld) Name %16s\n",
|
|
ulcbName,
|
|
pName));
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else if (tdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) {
|
|
pRemoteNetBiosAddress = (PTA_NETBIOS_ADDRESS)pRemoteAddress;
|
|
status = GetNetBiosNameFromTransportAddress(
|
|
pRemoteNetBiosAddress,
|
|
&pName,
|
|
&ulcbName,
|
|
&lNameType);
|
|
}
|
|
else
|
|
status = STATUS_INVALID_ADDRESS_COMPONENT;
|
|
//
|
|
// Save the address for pre-connect attempts,
|
|
// because if we have to cancel this irp,
|
|
// it is not saved anywhere else.
|
|
//
|
|
CTESpinLock(pConnEle, irql);
|
|
CTEMemCopy(pConnEle->RemoteName, pName, NETBIOS_NAME_SIZE);
|
|
CTESpinFree(pConnEle, irql);
|
|
addr.fType = ACD_ADDR_NB;
|
|
RtlCopyMemory(&addr.cNetbios, pName, NETBIOS_NAME_SIZE);
|
|
#ifdef DBG
|
|
DbgPrint("NbtAttemptAutodial: szAddr=%-15.15s\n", pName);
|
|
#endif
|
|
//
|
|
// Enqueue this request on the network
|
|
// connection pending queue.
|
|
//
|
|
pArgs[0] = pConnEle;
|
|
pArgs[1] = pTimeout;
|
|
pArgs[2] = pCallInfo;
|
|
pArgs[3] = pReturnInfo;
|
|
pArgs[4] = pIrp;
|
|
fSuccess = (*AcdDriverG.lpfnStartConnection)(
|
|
ulDriverIdG,
|
|
&addr,
|
|
ulFlags,
|
|
pProc,
|
|
5,
|
|
pArgs);
|
|
if (fSuccess) {
|
|
//
|
|
// We set the automatic connection in progress
|
|
// flag so we know to clean up the connection
|
|
// block in the automatic connection driver if
|
|
// the request gets canceled.
|
|
//
|
|
CTESpinLock(pConnEle, irql);
|
|
pConnEle->fAutoConnecting = TRUE;
|
|
CTESpinFree(pConnEle, irql);
|
|
}
|
|
|
|
return fSuccess;
|
|
} // NbtAttemptAutoDial
|
|
|
|
|
|
|
|
VOID
|
|
NbtNoteNewConnection(
|
|
IN tCONNECTELE *pConnEle,
|
|
IN tNAMEADDR *pNameAddr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform the automatic connection driver of a
|
|
successful new connection.
|
|
|
|
Arguments:
|
|
|
|
pConnEle - a pointer to the upper connection
|
|
|
|
pNameAddr - a pointer to the remote name
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL irql;
|
|
ACD_ADDR addr;
|
|
ACD_ADAPTER adapter;
|
|
|
|
if (pConnEle == NULL || pConnEle->pClientEle == NULL ||
|
|
pConnEle->pClientEle->pDeviceContext == NULL)
|
|
{
|
|
return;
|
|
}
|
|
//
|
|
// Get the source IP address of the connection.
|
|
//
|
|
addr.fType = ACD_ADDR_NB;
|
|
RtlCopyMemory(&addr.cNetbios, pNameAddr->Name, 15);
|
|
adapter.fType = ACD_ADAPTER_IP;
|
|
adapter.ulIpaddr = 0;
|
|
CTESpinLock(pConnEle, irql);
|
|
adapter.ulIpaddr = htonl(pConnEle->pClientEle->pDeviceContext->IpAddress);
|
|
CTESpinFree(pConnEle, irql);
|
|
//
|
|
// If the connection did not have a
|
|
// TCP connection associated with it,
|
|
// then we're done.
|
|
//
|
|
if (adapter.ulIpaddr == 0)
|
|
return;
|
|
(*AcdDriverG.lpfnNewConnection)(&addr, &adapter);
|
|
} // 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;
|
|
//
|
|
// 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
|