Windows NT 4.0 source code leak
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

/*++
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