435 lines
9.6 KiB
C
435 lines
9.6 KiB
C
|
/*++
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
|