mirror of https://github.com/tongzx/nt5src
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.
434 lines
9.6 KiB
434 lines
9.6 KiB
/*++
|
|
|
|
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
|
|
|
|
|