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.
923 lines
22 KiB
923 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atkdrvr.c
|
|
|
|
Abstract:
|
|
|
|
This module implements Appletalk Transport Provider driver interfaces
|
|
for NT
|
|
|
|
Author:
|
|
|
|
Nikhil Kamkolkar (NikhilK) 8-Jun-1992
|
|
(Code liberally adapted from NBF and various NT components)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define GLOBALS
|
|
#include "atalknt.h"
|
|
#include "atkdrvr.h"
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the LAN Manager Atalk
|
|
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;
|
|
|
|
//DbgBreakPoint();
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: DriverEntry(ATALK) - entered\n" ));
|
|
|
|
|
|
//
|
|
// Create the device object. (IoCreateDevice zeroes the memory
|
|
// occupied by the object.)
|
|
//
|
|
|
|
for (i = 0; i < ATALK_NODEVICES; i++) {
|
|
|
|
RtlInitUnicodeString (&deviceName, AtalkDeviceNames[i]);
|
|
status = IoCreateDevice(
|
|
DriverObject, // DriverObject
|
|
ATALK_DEVICE_EXTENSION_LENGTH, // DeviceExtension
|
|
&deviceName, // DeviceName
|
|
FILE_DEVICE_NETWORK, // DeviceType
|
|
0, // DeviceCharacteristics
|
|
(BOOLEAN)FALSE, // Exclusive
|
|
(PDEVICE_OBJECT *) &AtalkDeviceObject[i] // DeviceObject
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
//
|
|
// BUGBUG:
|
|
// Log error
|
|
//
|
|
|
|
//
|
|
// 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]->Context.DeviceType = (ATALK_DEVICE_TYPE)i;
|
|
|
|
//
|
|
// Initialize the provider info and statistics structures for this device
|
|
//
|
|
|
|
AtalkQueryInitProviderInfo(
|
|
(ATALK_DEVICE_TYPE)i,
|
|
&AtalkDeviceObject[i]->Context.ProviderInfo);
|
|
|
|
AtalkQueryInitProviderStatistics(
|
|
(ATALK_DEVICE_TYPE)i,
|
|
&AtalkDeviceObject[i]->Context.ProviderStatistics);
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Initialize critical section module
|
|
//
|
|
|
|
InitCriticalSectionNt();
|
|
|
|
status=AtalkInitializeTransport(
|
|
DriverObject,
|
|
RegistryPath,
|
|
&NdisPortDesc,
|
|
&NumberOfPorts
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Delete all the devices created
|
|
//
|
|
|
|
for (j=0; j < ATALK_NODEVICES; j++ )
|
|
IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[j]);
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_FATAL,
|
|
("ERROR: DriverEntry - AtalkInitializeTransport failed - %lx\n", status));
|
|
|
|
return(status);
|
|
}
|
|
|
|
#if DBG
|
|
NdisAllocateSpinLock(&AtalkGlobalInterlock);
|
|
#endif
|
|
|
|
NdisAllocateSpinLock(&AtalkGlobalRefLock);
|
|
NdisAllocateSpinLock(&AtalkGlobalStatLock);
|
|
|
|
DBGPRINT(ATALK_DEBUG_INIT, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: DriverEntry - AtalkInitialize complete %lx\n",status));
|
|
|
|
return status;
|
|
|
|
} // DriverEntry
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Create functions for the LAN
|
|
Manager Atalk 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 irpSp;
|
|
PFILE_FULL_EA_INFORMATION ea;
|
|
|
|
INT createObject;
|
|
TA_APPLETALK_ADDRESS tdiAddress;
|
|
CONNECTION_CONTEXT connectionContext;
|
|
PATALK_DEVICE_OBJECT atalkDeviceObject;
|
|
|
|
UCHAR protocolType, socketType;
|
|
|
|
BOOLEAN pending = Irp->PendingReturned;
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchCreate - entered for irp %lx\n", Irp ));
|
|
|
|
//
|
|
// Make sure status information is consistent every time.
|
|
//
|
|
|
|
IoMarkIrpPending (Irp);
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
atalkDeviceObject = (PATALK_DEVICE_OBJECT)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. Due to our portable stack's design
|
|
// we will not return from the following calls until the actions are
|
|
// complete. The stack blocks until the actions complete. So we can be
|
|
// assured that we can complete the irp upon return from these calls.
|
|
//
|
|
|
|
createObject = IrpGetEaCreateType(Irp);
|
|
ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
switch (createObject) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
|
|
if (ea->EaValueLength < sizeof(TA_APPLETALK_ADDRESS)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchCreate - addr size %d\n", ea->EaValueLength));
|
|
|
|
return(STATUS_EA_LIST_INCONSISTENT);
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
RtlMoveMemory(&tdiAddress, &ea->EaName[ea->EaNameLength+1],
|
|
sizeof(TA_APPLETALK_ADDRESS));
|
|
|
|
//
|
|
// Also, get the protocol type field for the socket
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchCreate - Remaining File Name : %S\n",
|
|
&irpSp->FileObject->FileName));
|
|
|
|
if (!NT_SUCCESS(AtalkGetProtocolSocketType(
|
|
&atalkDeviceObject->Context,
|
|
&irpSp->FileObject->FileName,
|
|
&protocolType,
|
|
&socketType ))) {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
status = AtalkTdiOpenAddress(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
&tdiAddress,
|
|
irpSp->Parameters.Create.SecurityContext,
|
|
irpSp->Parameters.Create.ShareAccess,
|
|
protocolType,
|
|
socketType,
|
|
&atalkDeviceObject->Context);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
|
|
if (ea->EaValueLength < sizeof(CONNECTION_CONTEXT)) {
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchCreate - Context size %d\n", ea->EaValueLength));
|
|
|
|
return(STATUS_EA_LIST_INCONSISTENT);
|
|
}
|
|
|
|
connectionContext =
|
|
*((CONNECTION_CONTEXT *)&ea->EaName[ea->EaNameLength+1]);
|
|
|
|
status = AtalkTdiOpenConnection(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
connectionContext,
|
|
&atalkDeviceObject->Context);
|
|
break;
|
|
|
|
|
|
case ATALK_FILE_TYPE_CONTROL :
|
|
|
|
status = AtalkTdiOpenControlChannel(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
&atalkDeviceObject->Context);
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchCreate - unknown EA passed!\n"));
|
|
|
|
status = STATUS_INVALID_EA_NAME;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Successful completion.
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_CREATE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchCreate complete irp %lx status %lx\n", Irp, status ));
|
|
|
|
if (status != STATUS_PENDING) {
|
|
Irp->PendingReturned = pending;
|
|
TdiCompleteRequest(Irp, status);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // AtalkDispatchCreate
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Cleanup functions for the LAN
|
|
Manager Atalk 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
|
|
started/completed
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PATALK_DEVICE_OBJECT atalkDeviceObject;
|
|
PIO_STACK_LOCATION irpSp;
|
|
BOOLEAN pending = Irp->PendingReturned;
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchCleanup - entered irp %lx\n", Irp ));
|
|
|
|
//
|
|
// Make sure status information is consistent every time.
|
|
//
|
|
|
|
IoMarkIrpPending (Irp);
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
atalkDeviceObject = (PATALK_DEVICE_OBJECT)DeviceObject;
|
|
|
|
switch ((ULONG)irpSp->FileObject->FsContext2) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
|
|
status = AtalkTdiCleanupAddress(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
Irp,
|
|
&atalkDeviceObject->Context);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
|
|
status = AtalkTdiCleanupConnection(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
Irp,
|
|
&atalkDeviceObject->Context);
|
|
|
|
break;
|
|
|
|
case ATALK_FILE_TYPE_CONTROL :
|
|
|
|
//
|
|
// No cleanup for control channel
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchCleanup - invalid obj %s\n",
|
|
irpSp->FileObject->FsContext));
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchCleanup - complete irp %lx status %lx\n", Irp, status ));
|
|
|
|
if (status != STATUS_PENDING) {
|
|
Irp->PendingReturned = pending;
|
|
TdiCompleteRequest(Irp, status);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // AtalkDispatchCleanup
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Close functions for the LAN
|
|
Manager Atalk 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 irpSp;
|
|
PATALK_DEVICE_OBJECT atalkDeviceObject;
|
|
BOOLEAN pending = Irp->PendingReturned;
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchClose - entered for IRP %lx\n", Irp ));
|
|
|
|
//
|
|
// Make sure status information is consistent every time.
|
|
//
|
|
|
|
IoMarkIrpPending (Irp);
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
atalkDeviceObject = (PATALK_DEVICE_OBJECT)DeviceObject;
|
|
|
|
switch ((ULONG)irpSp->FileObject->FsContext2) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE :
|
|
|
|
status = AtalkTdiCloseAddress(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
Irp,
|
|
&atalkDeviceObject->Context);
|
|
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE :
|
|
|
|
status = AtalkTdiCloseConnection(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
Irp,
|
|
&atalkDeviceObject->Context);
|
|
|
|
break;
|
|
|
|
case ATALK_FILE_TYPE_CONTROL :
|
|
|
|
status = AtalkTdiCloseControlChannel(
|
|
&Irp->IoStatus,
|
|
irpSp->FileObject,
|
|
Irp,
|
|
&atalkDeviceObject->Context);
|
|
break;
|
|
|
|
default:
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchClose - Invalid object %s\n",
|
|
irpSp->FileObject->FsContext));
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
DBGPRINT(ATALK_DEBUG_CLOSE, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchClose complete irp %lx status %lx\n", Irp, status ));
|
|
|
|
if (status != STATUS_PENDING) {
|
|
Irp->PendingReturned = pending;
|
|
TdiCompleteRequest(Irp, status);
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // AtalkDispatchClose
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Device Control functions for the
|
|
LAN Manager Atalk 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;
|
|
PATALK_DEVICE_OBJECT atalkDeviceObject;
|
|
PIO_STACK_LOCATION irpSp;
|
|
BOOLEAN pending = Irp->PendingReturned;
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchDeviceControl - irp %lx\n", Irp ));
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
atalkDeviceObject = (PATALK_DEVICE_OBJECT)DeviceObject;
|
|
|
|
//
|
|
// Do a map and call the internal device io control function.
|
|
// That will also perform the completion.
|
|
//
|
|
|
|
status = TdiMapUserRequest(
|
|
DeviceObject,
|
|
Irp,
|
|
irpSp);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
status = AtalkDispatchInternalDeviceControl(
|
|
DeviceObject,
|
|
Irp);
|
|
|
|
//
|
|
// AtalkDispatchInternalDeviceControl expects to complete the
|
|
// irp
|
|
//
|
|
|
|
} else {
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchDeviceControl - TdiMap failed %lx\n", status));
|
|
|
|
Irp->PendingReturned = pending;
|
|
TdiCompleteRequest(Irp, status);
|
|
}
|
|
|
|
return(status);
|
|
|
|
} // AtalkDispatchDeviceControl
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AtalkDispatchInternalDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Internal Device Control functions
|
|
for the LAN Manager Atalk 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 irpSp;
|
|
PATALK_DEVICE_OBJECT atalkDeviceObject;
|
|
|
|
PATALK_TDI_REQUEST request;
|
|
BOOLEAN pending = Irp->PendingReturned;
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS0, ("\n\nAtalkDispatchInternalDeviceControl entered for IRP %lx\n", Irp ));
|
|
|
|
//
|
|
// Make sure status information is consistent every time.
|
|
//
|
|
|
|
IoMarkIrpPending (Irp);
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
atalkDeviceObject = (PATALK_DEVICE_OBJECT)DeviceObject;
|
|
|
|
|
|
//
|
|
// Branch to the appropriate request handler. Create a request block to
|
|
// shield called routines from being irp-dependent.
|
|
//
|
|
|
|
status = AtalkCreateTdiRequest(&request);
|
|
if (!NT_SUCCESS(status)) {
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Set the common parameter pointers
|
|
//
|
|
|
|
request->OwningDevice = atalkDeviceObject->Context.DeviceType;
|
|
request->Parameters = (PVOID)NULL;
|
|
request->CompletionRoutine = (PVOID)NULL;
|
|
|
|
request->FileObject = irpSp->FileObject;
|
|
request->DeviceObject = atalkDeviceObject;
|
|
request->DeviceContext = &atalkDeviceObject->Context;
|
|
request->IoRequestIrp = Irp;
|
|
request->IoStatus = &Irp->IoStatus;
|
|
|
|
switch (irpSp->MinorFunction) {
|
|
|
|
case TDI_ACCEPT:
|
|
|
|
request->MinorCommand = TDI_ACCEPT;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiAccept(request);
|
|
break;
|
|
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
|
|
request->MinorCommand = TDI_RECEIVE_DATAGRAM;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
request->ReceiveDatagram.MdlAddress = Irp->MdlAddress;
|
|
|
|
status = AtalkTdiReceiveDatagram(request);
|
|
break;
|
|
|
|
case TDI_SEND_DATAGRAM:
|
|
|
|
request->MinorCommand = TDI_SEND_DATAGRAM;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
request->SendDatagram.MdlAddress = Irp->MdlAddress;
|
|
|
|
status = AtalkTdiSendDatagram(request);
|
|
break;
|
|
|
|
case TDI_SET_EVENT_HANDLER:
|
|
|
|
request->MinorCommand = TDI_SET_EVENT_HANDLER;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiSetEventHandler(request);
|
|
break;
|
|
|
|
case TDI_RECEIVE:
|
|
|
|
request->MinorCommand = TDI_RECEIVE;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
//
|
|
// These need to be done here so we can distinguish between
|
|
// a NtRead and TdiWrite
|
|
//
|
|
|
|
request->Receive.SystemRead = FALSE;
|
|
request->Receive.ReceiveBufferLength =
|
|
((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveLength;
|
|
request->Receive.ReceiveFlags =
|
|
&((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveFlags;
|
|
|
|
request->Receive.MdlAddress = Irp->MdlAddress;
|
|
|
|
status = AtalkTdiReceive(request);
|
|
break;
|
|
|
|
case TDI_SEND:
|
|
|
|
request->MinorCommand = TDI_SEND;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
//
|
|
// These need to be done here so we can distinguish between
|
|
// a NtWrite and TdiSend
|
|
//
|
|
|
|
request->Send.SystemWrite = FALSE;
|
|
request->Send.SendBufferLength =
|
|
((PTDI_REQUEST_KERNEL_SEND)&irpSp->Parameters)->SendLength;
|
|
request->Send.SendFlags =
|
|
((PTDI_REQUEST_KERNEL_SEND)&irpSp->Parameters)->SendFlags;
|
|
|
|
request->Send.MdlAddress = Irp->MdlAddress;
|
|
|
|
status = AtalkTdiSend(request);
|
|
break;
|
|
|
|
case TDI_ACTION:
|
|
|
|
//
|
|
// Set the request specific parameters in the request block
|
|
// Completion routine for TdiAction is set further on
|
|
//
|
|
|
|
request->MinorCommand = TDI_ACTION;
|
|
request->Action.MdlAddress = Irp->MdlAddress;
|
|
|
|
ASSERT(Irp->MdlAddress != NULL);
|
|
status = AtalkTdiAction (request);
|
|
break;
|
|
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
|
|
request->MinorCommand = TDI_ASSOCIATE_ADDRESS;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiAssociateAddress(request);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
|
|
request->MinorCommand = TDI_DISASSOCIATE_ADDRESS;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiDisassociateAddress (request);
|
|
break;
|
|
|
|
case TDI_CONNECT:
|
|
|
|
request->MinorCommand = TDI_CONNECT;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiConnect (request);
|
|
break;
|
|
|
|
case TDI_DISCONNECT:
|
|
|
|
request->MinorCommand = TDI_DISCONNECT;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
status = AtalkTdiDisconnect (request);
|
|
break;
|
|
|
|
case TDI_LISTEN:
|
|
|
|
request->MinorCommand = TDI_LISTEN;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
request->Listen.ListenFlags =
|
|
((PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters)->RequestFlags;
|
|
|
|
status = AtalkTdiListen (request);
|
|
break;
|
|
|
|
case TDI_QUERY_INFORMATION:
|
|
|
|
request->MinorCommand = TDI_QUERY_INFORMATION;
|
|
request->Query.MdlAddress = Irp->MdlAddress;
|
|
request->Parameters = (PVOID)&irpSp->Parameters;
|
|
|
|
ASSERT(Irp->MdlAddress != NULL);
|
|
status = AtalkTdiQueryInformation (request);
|
|
break;
|
|
|
|
case TDI_SET_INFORMATION:
|
|
|
|
request->MinorCommand = TDI_SET_INFORMATION;
|
|
|
|
status = AtalkTdiSetInformation (request);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Something we don't know about was submitted.
|
|
//
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkDispatchInternal - fnct %lx\n", irpSp->MinorFunction));
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_INFOCLASS0,
|
|
("INFO0: AtalkDispatchInternal complete irp %lx status %lx\n", Irp, status ));
|
|
|
|
//
|
|
// Return the immediate status code to the caller.
|
|
//
|
|
|
|
if (status != STATUS_PENDING) {
|
|
|
|
Irp->PendingReturned = pending;
|
|
|
|
//
|
|
// Complete the request, this will also dereference it.
|
|
//
|
|
|
|
AtalkCompleteTdiRequest (
|
|
request,
|
|
status);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // AtalkDispatchInternalDeviceControl
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the unload routine for the LAN Manager Atalk driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object for this driver.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
USHORT i;
|
|
|
|
UNREFERENCED_PARAMETER (DriverObject);
|
|
|
|
DBGPRINT(ATALK_DEBUG_DISPATCH, DEBUG_LEVEL_ERROR,
|
|
("ERROR: AtalkUnload - Maybe it'll work, maybe it won't!\n"));
|
|
|
|
UnloadAppleTalk();
|
|
AtalkUnloadStack(&NdisPortDesc, &NumberOfPorts);
|
|
|
|
for (i = 0; i < ATALK_NODEVICES; i++) {
|
|
|
|
//
|
|
// Delete all the devices created
|
|
//
|
|
|
|
IoDeleteDevice((PDEVICE_OBJECT)AtalkDeviceObject[i]);
|
|
}
|
|
|
|
return;
|
|
|
|
} // AtalkUnload
|
|
|
|
|