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.
934 lines
22 KiB
934 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atkdrvr.c
|
|
|
|
Abstract:
|
|
|
|
This module implements Appletalk Transport Provider driver interfaces
|
|
for NT
|
|
|
|
Author:
|
|
|
|
Jameel Hyder ([email protected])
|
|
Nikhil Kamkolkar ([email protected])
|
|
|
|
Revision History:
|
|
19 Jun 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#include <atalk.h>
|
|
#pragma hdrstop
|
|
|
|
// File module number for errorlogging
|
|
#define FILENUM ATKDRVR
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#pragma alloc_text(PAGEINIT, AtalkCleanup)
|
|
#pragma alloc_text(PAGE, atalkUnload)
|
|
#pragma alloc_text(PAGE, AtalkDispatchCreate)
|
|
#pragma alloc_text(PAGE, AtalkDispatchCleanup)
|
|
#pragma alloc_text(PAGE, AtalkDispatchClose)
|
|
#pragma alloc_text(PAGE, AtalkDispatchDeviceControl)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the Windows NT Appletalk
|
|
driver. This routine creates the device object for the Atalk
|
|
device and performs all other driver initialization.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by the system.
|
|
RegistryPath- Path to the root of the section in the registry for this
|
|
driver
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the initialization operation. If
|
|
this is not STATUS_SUCCESS the driver will not load.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING deviceName;
|
|
USHORT i, j;
|
|
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("Appletalk DriverEntry - Entered !!!\n"));
|
|
|
|
|
|
TdiInitialize();
|
|
|
|
INITIALIZE_SPIN_LOCK(&AtalkStatsLock);
|
|
|
|
INITIALIZE_SPIN_LOCK(&AtalkSktCacheLock);
|
|
|
|
INITIALIZE_SPIN_LOCK(&ArapSpinLock);
|
|
|
|
#if DBG
|
|
INITIALIZE_SPIN_LOCK(&AtalkDebugSpinLock);
|
|
#endif
|
|
|
|
// Initialize event for locking/unlocking pageable sections. Set it to signalled state
|
|
// so that the first wait is satisfied.
|
|
KeInitializeMutex(&AtalkPgLkMutex, 0xFFFF);
|
|
|
|
// Create the device object. (IoCreateDevice zeroes the memory
|
|
// occupied by the object.)
|
|
for (i = 0; i < ATALK_NO_DEVICES; i++)
|
|
{
|
|
RtlInitUnicodeString(&deviceName, AtalkDeviceNames[i]);
|
|
status = IoCreateDevice(
|
|
DriverObject, // DriverObject
|
|
ATALK_DEV_EXT_LEN, // DeviceExtension
|
|
&deviceName, // DeviceName
|
|
FILE_DEVICE_NETWORK, // DeviceType
|
|
FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
|
|
(BOOLEAN)FALSE, // Exclusive
|
|
(PDEVICE_OBJECT *) &AtalkDeviceObject[i]); // DeviceObject
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_ERROR(EVENT_ATALK_CANT_CREATE_DEVICE, status, NULL, 0);
|
|
|
|
// Delete all the devices created so far, if any
|
|
for (j = 0; j < i; j++)
|
|
{
|
|
IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[j]);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// Assumption:
|
|
// 'i' will correspond to the Device type in the ATALK_DEVICE_TYPE enum
|
|
AtalkDeviceObject[i]->Ctx.adc_DevType = (ATALK_DEV_TYPE)i;
|
|
|
|
// Initialize the provider info and statistics structures for this device
|
|
AtalkQueryInitProviderInfo((ATALK_DEV_TYPE)i,
|
|
&AtalkDeviceObject[i]->Ctx.adc_ProvInfo);
|
|
|
|
#if 0
|
|
// NOTE: Implement
|
|
AtalkQueryInitProviderStatistics((ATALK_DEV_TYPE)i,
|
|
&AtalkDeviceObject[i]->Ctx.adc_ProvStats);
|
|
#endif
|
|
}
|
|
|
|
// Initialize the driver object for this driver's entry points.
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = AtalkDispatchCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = AtalkDispatchCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = AtalkDispatchClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AtalkDispatchDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AtalkDispatchInternalDeviceControl;
|
|
|
|
DriverObject->DriverUnload = atalkUnload;
|
|
|
|
// Get lock handles to all the conditional pageable sections
|
|
AtalkLockInit(&AtalkPgLkSection[NBP_SECTION], AtalkNbpAction);
|
|
AtalkLockInit(&AtalkPgLkSection[ZIP_SECTION], AtalkZipGetMyZone);
|
|
AtalkLockInit(&AtalkPgLkSection[TDI_SECTION], AtalkTdiCleanupAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[ATP_SECTION], AtalkAtpCloseAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[ASP_SECTION], AtalkAspCloseAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[PAP_SECTION], AtalkPapCleanupAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[ASPC_SECTION], AtalkAspCCloseAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[ADSP_SECTION], AtalkAdspCleanupAddress);
|
|
AtalkLockInit(&AtalkPgLkSection[ROUTER_SECTION], AtalkRtmpPacketInRouter);
|
|
AtalkLockInit(&AtalkPgLkSection[INIT_SECTION], AtalkInitRtmpStartProcessingOnPort);
|
|
AtalkLockInit(&AtalkPgLkSection[ARAP_SECTION], ArapExchangeParms);
|
|
AtalkLockInit(&AtalkPgLkSection[PPP_SECTION], AllocPPPConn);
|
|
|
|
AtalkLockInitIfNecessary();
|
|
|
|
status = AtalkInitializeTransport(DriverObject, RegistryPath);
|
|
|
|
AtalkUnlockInitIfNecessary();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
#if DBG
|
|
// Make sure we are not unloading with any locked sections
|
|
for (i = 0; i < LOCKABLE_SECTIONS; i++)
|
|
{
|
|
ASSERT (AtalkPgLkSection[i].ls_LockCount == 0);
|
|
}
|
|
#endif
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("DriverEntry: AtalkInitializeTransport failed %lx\n",status));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("DriverEntry: AtalkInitializeTransport complete %lx\n",status));
|
|
}
|
|
|
|
return status;
|
|
} // DriverEntry
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Create functions for the Appletalk driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
|
|
pIrp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PFILE_FULL_EA_INFORMATION ea;
|
|
|
|
INT createObject;
|
|
TA_APPLETALK_ADDRESS tdiAddress;
|
|
CONNECTION_CONTEXT connectionContext;
|
|
PATALK_DEV_OBJ atalkDeviceObject;
|
|
|
|
UCHAR protocolType, socketType;
|
|
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchCreate: entered for irp %lx\n", pIrp));
|
|
|
|
// Make sure status information is consistent every time.
|
|
IoMarkIrpPending(pIrp);
|
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
|
|
|
|
// Both opens must complete synchronously. It is possible we return
|
|
// status_pending to the system, but it will not return to the caller
|
|
// until the call actually completes. In our case, we block until the
|
|
// actions are complete. So we can be assured that we can complete the irp
|
|
// upon return from these calls.
|
|
|
|
createObject = AtalkIrpGetEaCreateType(pIrp);
|
|
ea = (PFILE_FULL_EA_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
switch (createObject)
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
if (ea->EaValueLength < sizeof(TA_APPLETALK_ADDRESS))
|
|
{
|
|
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
|
|
("AtalkDispatchCreate: addr size %d\n", ea->EaValueLength));
|
|
|
|
status = STATUS_EA_LIST_INCONSISTENT;
|
|
break;
|
|
}
|
|
|
|
// We have the AtalkTdiOpenAddress routine look at only the first
|
|
// address in the list of addresses by casting the passed address
|
|
// to TA_APPLETALK_ADDRESS.
|
|
RtlCopyMemory(
|
|
&tdiAddress,
|
|
(PBYTE)(&ea->EaName[ea->EaNameLength+1]),
|
|
sizeof(TA_APPLETALK_ADDRESS));
|
|
|
|
// Also, get the protocol type field for the socket
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchCreate: Remaining File Name : %S\n",
|
|
&pIrpSp->FileObject->FileName));
|
|
|
|
if (!NT_SUCCESS(AtalkGetProtocolSocketType(&atalkDeviceObject->Ctx,
|
|
&pIrpSp->FileObject->FileName,
|
|
&protocolType,
|
|
&socketType)))
|
|
{
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
status = AtalkTdiOpenAddress(
|
|
pIrp,
|
|
pIrpSp,
|
|
&tdiAddress,
|
|
protocolType,
|
|
socketType,
|
|
&atalkDeviceObject->Ctx);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
if (ea->EaValueLength < sizeof(CONNECTION_CONTEXT))
|
|
{
|
|
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
|
|
("AtalkDispatchCreate: Context size %d\n", ea->EaValueLength));
|
|
|
|
status = STATUS_EA_LIST_INCONSISTENT;
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(&connectionContext,
|
|
&ea->EaName[ea->EaNameLength+1],
|
|
sizeof(CONNECTION_CONTEXT));
|
|
|
|
status = AtalkTdiOpenConnection(pIrp,
|
|
pIrpSp,
|
|
connectionContext,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE :
|
|
status = AtalkTdiOpenControlChannel(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_ERR,
|
|
("AtalkDispatchCreate: unknown EA passed!\n"));
|
|
|
|
status = STATUS_INVALID_EA_NAME;
|
|
break;
|
|
}
|
|
|
|
// Successful completion.
|
|
|
|
DBGPRINT(DBG_COMP_CREATE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchCreate complete irp %lx status %lx\n", pIrp, status));
|
|
|
|
if (NT_SUCCESS(status))
|
|
INTERLOCKED_INCREMENT_LONG(&AtalkHandleCount, &AtalkStatsLock);
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
ASSERT (status != STATUS_PENDING);
|
|
TdiCompleteRequest(pIrp, status);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // AtalkDispatchCreate
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Cleanup functions for the Appletalk driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
pIrp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully
|
|
started/completed
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PATALK_DEV_OBJ atalkDeviceObject;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchCleanup: entered irp %lx\n", pIrp));
|
|
|
|
// Make sure status information is consistent every time.
|
|
IoMarkIrpPending (pIrp);
|
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
|
|
|
|
switch ((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF)
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
status = AtalkTdiCleanupAddress(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
status = AtalkTdiCleanupConnection(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE :
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_ERR,
|
|
("AtalkDispatchCleaup: Invalid object %s\n",
|
|
pIrpSp->FileObject->FsContext));
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchCleanup complete irp %lx status %lx\n", pIrp, status));
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
ASSERT (status != STATUS_PENDING);
|
|
TdiCompleteRequest(pIrp, status);
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // AtalkDispatchCleanup
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Close functions for the Appletalk driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
irp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PATALK_DEV_OBJ atalkDeviceObject;
|
|
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchClose: entered for IRP %lx\n", pIrp));
|
|
|
|
// Make sure status information is consistent every time.
|
|
IoMarkIrpPending(pIrp);
|
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
|
|
|
|
switch ((ULONG_PTR)(pIrpSp->FileObject->FsContext2) & 0xFF)
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
status = AtalkTdiCloseAddress(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
status = AtalkTdiCloseConnection(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE :
|
|
status = AtalkTdiCloseControlChannel(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_ERR,
|
|
("AtalkDispatchClose: Invalid object %s\n",
|
|
pIrpSp->FileObject->FsContext));
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_CLOSE, DBG_LEVEL_INFO,
|
|
("AtalkDispatchClose complete irp %lx status %lx\n", pIrp, status));
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
ASSERT (status != STATUS_PENDING);
|
|
TdiCompleteRequest(pIrp, status);
|
|
}
|
|
|
|
INTERLOCKED_DECREMENT_LONG(&AtalkHandleCount, &AtalkStatsLock);
|
|
|
|
return(status);
|
|
|
|
} // AtalkDispatchClose
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Device Control functions for the Appletalk driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
pIrp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PATALK_DEV_OBJ atalkDeviceObject;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
ULONG IoControlCode;
|
|
|
|
DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
|
|
("AtalkDispatchDeviceControl: irp %lx\n", pIrp));
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
|
|
|
|
|
|
IoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
//
|
|
// if it's a request from ARAP, process it here and return
|
|
//
|
|
if (IoControlCode > IOCTL_ARAP_START && IoControlCode < IOCTL_ARAP_END)
|
|
{
|
|
status = ArapProcessIoctl(pIrp);
|
|
|
|
return(status);
|
|
}
|
|
|
|
// Do a map and call the internal device io control function.
|
|
// That will also perform the completion.
|
|
status = TdiMapUserRequest(DeviceObject,
|
|
pIrp,
|
|
pIrpSp);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
status = AtalkDispatchInternalDeviceControl(
|
|
DeviceObject,
|
|
pIrp);
|
|
|
|
//
|
|
// AtalkDispatchInternalDeviceControl expects to complete the
|
|
// irp
|
|
//
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_WARN,
|
|
("AtalkDispatchDeviceControl: TdiMap failed %lx\n", status));
|
|
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
ASSERT (status != STATUS_PENDING);
|
|
TdiCompleteRequest(pIrp, status);
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // AtalkDispatchDeviceControl
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchInternalDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Internal Device Control functions
|
|
for the Appletalk driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
|
|
pIrp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PATALK_DEV_OBJ atalkDeviceObject;
|
|
KIRQL oldIrql;
|
|
|
|
DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
|
|
("AtalkDispatchInternalDeviceControl entered for IRP %lx\n", pIrp));
|
|
|
|
// Make sure status information is consistent every time.
|
|
IoMarkIrpPending (pIrp);
|
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
atalkDeviceObject = (PATALK_DEV_OBJ)DeviceObject;
|
|
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
if (!pIrp->Cancel)
|
|
{
|
|
IoSetCancelRoutine(pIrp, (PDRIVER_CANCEL)AtalkTdiCancel);
|
|
}
|
|
else
|
|
{
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
status = STATUS_CANCELLED;
|
|
TdiCompleteRequest(pIrp, status);
|
|
return(status);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
// Branch to the appropriate request handler.
|
|
switch (pIrpSp->MinorFunction)
|
|
{
|
|
case TDI_ACCEPT:
|
|
status = AtalkTdiAccept(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
status = AtalkTdiReceiveDgram(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_SEND_DATAGRAM:
|
|
status = AtalkTdiSendDgram(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_SET_EVENT_HANDLER:
|
|
status = AtalkTdiSetEventHandler(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_RECEIVE:
|
|
status = AtalkTdiReceive(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_SEND:
|
|
status = AtalkTdiSend(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_ACTION:
|
|
ASSERT(pIrp->MdlAddress != NULL);
|
|
status = AtalkTdiAction(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
status = AtalkTdiAssociateAddress(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
status = AtalkTdiDisassociateAddress(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_CONNECT:
|
|
status = AtalkTdiConnect(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_DISCONNECT:
|
|
status = AtalkTdiDisconnect(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_LISTEN:
|
|
status = AtalkTdiListen(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_QUERY_INFORMATION:
|
|
ASSERT(pIrp->MdlAddress != NULL);
|
|
status = AtalkTdiQueryInformation(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
case TDI_SET_INFORMATION:
|
|
status = AtalkTdiSetInformation(pIrp,
|
|
pIrpSp,
|
|
&atalkDeviceObject->Ctx);
|
|
break;
|
|
|
|
default:
|
|
// Something we don't know about was submitted.
|
|
DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_ERR,
|
|
("AtalkDispatchInternal: fnct %lx\n", pIrpSp->MinorFunction));
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_DISPATCH, DBG_LEVEL_INFO,
|
|
("AtalkDispatchInternal complete irp %lx status %lx\n", pIrp, status));
|
|
|
|
// Return the immediate status code to the caller.
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
// Complete the request, this will also dereference it.
|
|
pIrp->CancelRoutine = NULL;
|
|
ASSERT (status != STATUS_PENDING);
|
|
TdiCompleteRequest(pIrp, status);
|
|
}
|
|
|
|
return status;
|
|
} // AtalkDispatchInternalDeviceControl
|
|
|
|
|
|
|
|
|
|
VOID
|
|
atalkUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the unload routine for the Appletalk driver.
|
|
|
|
NOTE: Unload will not be called until all the handles have been
|
|
closed successfully. We just shutdown all the ports, and do
|
|
misc. cleanup.
|
|
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object for this driver.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER (DriverObject);
|
|
|
|
AtalkBindnUnloadStates |= ATALK_UNLOADING;
|
|
|
|
// if we hit that timing window where binding or PnP event is going on,
|
|
// sleep (for a second each time) until that action completes
|
|
while (AtalkBindnUnloadStates & (ATALK_BINDING | ATALK_PNP_IN_PROGRESS))
|
|
{
|
|
AtalkSleep(1000);
|
|
}
|
|
|
|
AtalkLockInitIfNecessary();
|
|
|
|
AtalkCleanup();
|
|
|
|
AtalkUnlockInitIfNecessary();
|
|
|
|
#if DBG
|
|
{
|
|
int i;
|
|
|
|
// Make sure we are not unloading with any locked sections
|
|
for (i = 0; i < LOCKABLE_SECTIONS; i++)
|
|
{
|
|
ASSERT (AtalkPgLkSection[i].ls_LockCount == 0);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("Appletalk driver unloaded\n"));
|
|
|
|
#endif
|
|
} // atalkUnload
|
|
|
|
|
|
|
|
VOID
|
|
AtalkCleanup(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is synchronous and will block until Unload Completes
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PPORT_DESCRIPTOR pPortDesc;
|
|
LONG i;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
// Stop the timer subsystem
|
|
AtalkTimerFlushAndStop();
|
|
|
|
ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
|
|
|
|
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
|
|
|
|
// Shut down all ports
|
|
while ((pPortDesc = AtalkPortList) != NULL)
|
|
{
|
|
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
|
|
|
|
AtalkPortShutdown(pPortDesc);
|
|
|
|
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
|
|
|
|
if (AtalkRegPath.Buffer != NULL)
|
|
{
|
|
AtalkFreeMemory(AtalkRegPath.Buffer);
|
|
}
|
|
|
|
if (AtalkDefaultPortName.Buffer != NULL)
|
|
{
|
|
AtalkFreeMemory(AtalkDefaultPortName.Buffer);
|
|
}
|
|
|
|
for (i = 0; i < ATALK_NO_DEVICES; i++)
|
|
{
|
|
//
|
|
// Delete all the devices created
|
|
//
|
|
IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[i]);
|
|
}
|
|
|
|
// Deinitialize the Block Package
|
|
AtalkDeInitMemorySystem();
|
|
|
|
// Check if routing is on, if so unlock the router code now
|
|
if (AtalkRouter)
|
|
AtalkUnlockRouterIfNecessary();
|
|
|
|
// Free the rtmp tables
|
|
AtalkRtmpInit(FALSE);
|
|
|
|
// Free the zip tables
|
|
AtalkZipInit(FALSE);
|
|
|
|
// Release ndis resources (buffer/packet pools)
|
|
AtalkNdisReleaseResources();
|
|
|
|
// Deregister the protocol from ndis if handle is non-null
|
|
if (AtalkNdisProtocolHandle != (NDIS_HANDLE)NULL)
|
|
AtalkNdisDeregisterProtocol();
|
|
|
|
ASSERT(AtalkStatistics.stat_CurAllocSize == 0);
|
|
|
|
ASSERT(AtalkDbgMdlsAlloced == 0);
|
|
ASSERT(AtalkDbgIrpsAlloced == 0);
|
|
|
|
#ifdef PROFILING
|
|
ASSERT(AtalkStatistics.stat_CurAllocCount == 0);
|
|
ASSERT(AtalkStatistics.stat_CurMdlCount == 0);
|
|
#endif
|
|
}
|
|
|
|
|