windows-nt/Source/XPSP1/NT/net/rras/ras/autodial/rasacd/ntdisp.c

435 lines
9.6 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ntdisp.c
Abstract:
NT specific routines for dispatching and handling automatic
connection notification IRPs.
The basic architecture involves a user address space,
a network transport, and this driver.
The user address space is responsible for creating a
new network connection given a notification from this
driver (IOCTL_ACD_NOTIFICATION). When it gets a
notification, it is also responsible for pinging the
this driver (IOCTL_ACD_KEEPALIVE) so it can be guaranteed
the connection is progressing. Once the connection is
created, it informs this driver of the success or
failure of the connection attempt (IOCTL_ACD_CONNECTION).
Network transports are responsible for informing this
driver of network unreachable errors via TdiConnect()
or TdiSendDatagram(). When this happens, the transport
is responsible for dequeueing the send request from any
of its internal queues and enqueueing the request in
this driver (AcdWaitForCompletion()), supplying a callback
to be called when the connection has been completed.
Author:
Anthony Discolo (adiscolo) 18-Apr-1995
Revision History:
--*/
#include <ndis.h>
#include <cxport.h>
#include <tdikrnl.h>
#include <tdistat.h>
#include <tdiinfo.h>
#include <acd.h>
#include "acdapi.h"
#include "debug.h"
//
// Driver reference count
//
ULONG ulAcdOpenCountG;
//
// Imported routines
//
NTSTATUS
AcdEnable(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
VOID
AcdCancelNotifications();
NTSTATUS
AcdWaitForNotification(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdConnectionInProgress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdSignalCompletion(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdConnectAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
VOID
AcdReset();
NTSTATUS
AcdGetAddressAttributes(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdSetAddressAttributes(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdQueryState(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdEnableAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
//
// Internal function prototypes
//
NTSTATUS
AcdCreate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdDispatchDeviceControl(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdDispatchInternalDeviceControl(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdCleanup(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdClose(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdBind(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
NTSTATUS
AcdUnbind(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
);
//
// All of this code is pageable.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, AcdCreate)
#pragma alloc_text(PAGE, AcdDispatchDeviceControl)
#pragma alloc_text(PAGE, AcdDispatchInternalDeviceControl)
#pragma alloc_text(PAGE, AcdCleanup)
#pragma alloc_text(PAGE, AcdClose)
#endif // ALLOC_PRAGMA
NTSTATUS
AcdCreate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
{
ulAcdOpenCountG++;
IF_ACDDBG(ACD_DEBUG_OPENCOUNT) {
AcdPrint(("AcdCreate: ulAcdOpenCountG=%d\n", ulAcdOpenCountG));
}
return STATUS_SUCCESS;
} // AcdCreate
NTSTATUS
AcdDispatchDeviceControl(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
{
NTSTATUS status;
PAGED_CODE();
//
// Set this in advance. Any IOCTL dispatch routine that cares about it
// will modify it itself.
//
pIrp->IoStatus.Information = 0;
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_ACD_RESET:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_RESET\n"));
}
AcdReset();
status = STATUS_SUCCESS;
break;
case IOCTL_ACD_ENABLE:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_ENABLE\n"));
}
//
// Enable/disable requests to/from the driver.
//
status = AcdEnable(pIrp, pIrpSp);
break;
case IOCTL_ACD_NOTIFICATION:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_NOTIFICATION\n"));
}
//
// This irp will be completed upon the
// next connection attempt to
// allow a user-space process to attempt
// to make a connection.
//
status = AcdWaitForNotification(pIrp, pIrpSp);
break;
case IOCTL_ACD_KEEPALIVE:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_KEEPALIVE\n"));
}
//
// Inform the driver that the connection
// is in the process of being created.
//
status = AcdConnectionInProgress(pIrp, pIrpSp);
break;
case IOCTL_ACD_COMPLETION:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_COMPLETION\n"));
}
//
// Complete all pending irps that initially
// encountered a network unreachable error,
// and have been waiting for a connection to be
// made.
//
status = AcdSignalCompletion(pIrp, pIrpSp);
break;
case IOCTL_ACD_CONNECT_ADDRESS:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_ACD_CONNECT_ADDRESS\n"));
}
//
// This allows a user space application to
// generate the same automatic connection
// mechanism as a transport protocol.
//
status = AcdConnectAddress(pIrp, pIrpSp);
break;
case IOCTL_ACD_ENABLE_ADDRESS:
//DbgPrint("AcdDispatchDeviceControl: IOCTL_ACD_ENABLE_ADDRESS\n");
status = AcdEnableAddress(pIrp, pIrpSp);
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
if (status != STATUS_PENDING) {
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return status;
} // AcdDispatchDeviceControl
NTSTATUS
AcdDispatchInternalDeviceControl(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
{
NTSTATUS status;
PAGED_CODE();
//
// Set this in advance. Any IOCTL dispatch routine that cares about it
// will modify it itself.
//
pIrp->IoStatus.Information = 0;
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_ACD_BIND:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchInternalDeviceControl: IOCTL_INTERNAL_ACD_BIND\n"));
}
//
// Transfer entrypoints to client.
//
status = AcdBind(pIrp, pIrpSp);
break;
case IOCTL_INTERNAL_ACD_UNBIND:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchInternalDeviceControl: IOCTL_INTERNAL_ACD_UNBIND\n"));
}
//
// Remove any pending requests from
// this driver.
//
status = AcdUnbind(pIrp, pIrpSp);
break;
case IOCTL_INTERNAL_ACD_QUERY_STATE:
IF_ACDDBG(ACD_DEBUG_IOCTL) {
AcdPrint(("AcdDispatchDeviceControl: IOCTL_INTERNAL_ACD_QUERY_STATE\n"));
}
status = AcdQueryState(pIrp, pIrpSp);
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
if (status != STATUS_PENDING) {
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return status;
} // AcdDispatchInternalDeviceControl
NTSTATUS
AcdCleanup(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
{
return STATUS_SUCCESS;
} // AcdCleanup
NTSTATUS
AcdClose(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
{
ulAcdOpenCountG--;
IF_ACDDBG(ACD_DEBUG_OPENCOUNT) {
AcdPrint(("AcdClose: ulAcdOpenCountG=%d\n", ulAcdOpenCountG));
}
if (!ulAcdOpenCountG)
AcdReset();
return STATUS_SUCCESS;
} // AcdClose
NTSTATUS
AcdDispatch(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
DESCRIPTION
This is the dispatch routine for the network connection
notification driver.
ARGUMENTS
pDeviceObject: a pointer to device object for target device
pIrp: a pointer to I/O request packet
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION pIrpSp;
UNREFERENCED_PARAMETER(pDeviceObject);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
switch (pIrpSp->MajorFunction) {
case IRP_MJ_CREATE:
status = AcdCreate(pIrp, pIrpSp);
break;
case IRP_MJ_DEVICE_CONTROL:
return AcdDispatchDeviceControl(pIrp, pIrpSp);
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
return AcdDispatchInternalDeviceControl(pIrp, pIrpSp);
case IRP_MJ_CLEANUP:
status = AcdCleanup(pIrp, pIrpSp);
break;
case IRP_MJ_CLOSE:
status = AcdClose(pIrp, pIrpSp);
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
if (status != STATUS_PENDING) {
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return status;
} // AcdDispatch