blob: 1119224dec49bd6ac08efe5b12584586b1cfd49c [file]
/*
* b2ether driver -- derived from DDK packet driver sample
*
* Basilisk II (C) 1997-1999 Christian Bauer
*
* Windows platform specific code copyright (C) Lauri Pesonen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "stdarg.h"
#include "ntddk.h"
#include "ntiologc.h"
#include "ndis.h"
#include "ntddpack.h"
#include "b2ether.h"
#undef DBG
#define DBG 0
#include "debug.h"
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
PacketReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
PacketCreateSymbolicLink(
IN PUNICODE_STRING DeviceName,
IN BOOLEAN Create
);
NTSTATUS
PacketQueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
#if DBG
ULONG PacketDebugFlag = PACKET_DEBUG_LOUD;
#endif
PDEVICE_EXTENSION GlobalDeviceExtension;
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar;
UNICODE_STRING MacDriverName;
UNICODE_STRING UnicodeDeviceName;
PDEVICE_OBJECT DeviceObject = NULL;
PDEVICE_EXTENSION DeviceExtension = NULL;
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS ErrorCode = STATUS_SUCCESS;
NDIS_STRING ProtoName = NDIS_STRING_CONST("PacketDriver");
ULONG DevicesCreated=0;
PWSTR BindString;
PWSTR ExportString;
PWSTR BindStringSave;
PWSTR ExportStringSave;
NDIS_HANDLE NdisProtocolHandle;
IF_LOUD(DbgPrint("\n\nPacket: DriverEntry\n");)
RtlZeroMemory(&ProtocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
ProtocolChar.MajorNdisVersion = 3;
ProtocolChar.MinorNdisVersion = 0;
ProtocolChar.Reserved = 0;
ProtocolChar.OpenAdapterCompleteHandler = PacketOpenAdapterComplete;
ProtocolChar.CloseAdapterCompleteHandler = PacketCloseAdapterComplete;
ProtocolChar.SendCompleteHandler = PacketSendComplete;
ProtocolChar.TransferDataCompleteHandler = PacketTransferDataComplete;
ProtocolChar.ResetCompleteHandler = PacketResetComplete;
ProtocolChar.RequestCompleteHandler = PacketRequestComplete;
ProtocolChar.ReceiveHandler = PacketReceiveIndicate;
ProtocolChar.ReceiveCompleteHandler = PacketReceiveComplete;
ProtocolChar.StatusHandler = PacketStatus;
ProtocolChar.StatusCompleteHandler = PacketStatusComplete;
ProtocolChar.Name = ProtoName;
NdisRegisterProtocol(
&Status,
&NdisProtocolHandle,
&ProtocolChar,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS) {
IF_LOUD(DbgPrint("Packet: Failed to register protocol with NDIS\n");)
return Status;
}
//
// Set up the device driver entry points.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = PacketOpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PacketClose;
DriverObject->MajorFunction[IRP_MJ_READ] = PacketRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = PacketWrite;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = PacketCleanup;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PacketIoControl;
DriverObject->DriverUnload = PacketUnload;
//
// Get the name of the Packet driver and the name of the MAC driver
// to bind to from the registry
//
Status=PacketReadRegistry(
&BindString,
&ExportString,
RegistryPath
);
if (Status != STATUS_SUCCESS) {
IF_LOUD(DbgPrint("Perf: Failed to read registry\n");)
goto RegistryError;
}
BindStringSave = BindString;
ExportStringSave = ExportString;
// create a device object for each entry
while (*BindString!= UNICODE_NULL && *ExportString!= UNICODE_NULL) {
// Create a counted unicode string for both null terminated strings
RtlInitUnicodeString(
&MacDriverName,
BindString
);
RtlInitUnicodeString(
&UnicodeDeviceName,
ExportString
);
// Advance to the next string of the MULTI_SZ string
BindString += (MacDriverName.Length+sizeof(UNICODE_NULL))/sizeof(WCHAR);
ExportString += (UnicodeDeviceName.Length+sizeof(UNICODE_NULL))/sizeof(WCHAR);
IF_LOUD(DbgPrint("Packet: DeviceName=%ws MacName=%ws\n",UnicodeDeviceName.Buffer,MacDriverName.Buffer);)
// Create the device object
Status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&UnicodeDeviceName,
FILE_DEVICE_PROTOCOL,
0,
FALSE,
&DeviceObject
);
if (Status != STATUS_SUCCESS) {
IF_LOUD(DbgPrint("Perf: IoCreateDevice() failed:\n");)
break;
}
DevicesCreated++;
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
DeviceExtension->DeviceObject = DeviceObject;
// Save the the name of the MAC driver to open in the Device Extension
DeviceExtension->AdapterName=MacDriverName;
if (DevicesCreated == 1) {
DeviceExtension->BindString = BindStringSave;
DeviceExtension->ExportString = ExportStringSave;
}
DeviceExtension->NdisProtocolHandle=NdisProtocolHandle;
}
if (DevicesCreated > 0) {
return STATUS_SUCCESS;
}
ExFreePool(BindStringSave);
ExFreePool(ExportStringSave);
RegistryError:
NdisDeregisterProtocol(
&Status,
NdisProtocolHandle
);
Status=STATUS_UNSUCCESSFUL;
return(Status);
}
VOID PacketUnload( IN PDRIVER_OBJECT DriverObject )
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT OldDeviceObject;
PDEVICE_EXTENSION DeviceExtension;
NDIS_HANDLE NdisProtocolHandle;
NDIS_STATUS Status;
IF_LOUD(DbgPrint("Packet: Unload\n");)
DeviceObject = DriverObject->DeviceObject;
while (DeviceObject != NULL) {
DeviceExtension = DeviceObject->DeviceExtension;
NdisProtocolHandle = DeviceExtension->NdisProtocolHandle;
if (DeviceExtension->BindString != NULL) {
ExFreePool(DeviceExtension->BindString);
}
if (DeviceExtension->ExportString != NULL) {
ExFreePool(DeviceExtension->ExportString);
}
OldDeviceObject=DeviceObject;
DeviceObject=DeviceObject->NextDevice;
IoDeleteDevice(OldDeviceObject);
}
NdisDeregisterProtocol( &Status, NdisProtocolHandle );
}
NTSTATUS PacketIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST pRequest;
ULONG FunctionCode;
NDIS_STATUS Status;
IF_LOUD(DbgPrint("Packet: IoControl\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
Open=IrpSp->FileObject->FsContext;
RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList,&Open->RequestSpinLock);
if (RequestListEntry == NULL) {
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement);
pRequest->Irp=Irp;
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = STATUS_PENDING;
IF_LOUD(DbgPrint("Packet: Function code is %08lx buff size=%08lx %08lx\n",FunctionCode,IrpSp->Parameters.DeviceIoControl.InputBufferLength,IrpSp->Parameters.DeviceIoControl.OutputBufferLength);)
if (FunctionCode == IOCTL_PROTOCOL_RESET) {
IF_LOUD(DbgPrint("Packet: IoControl - Reset request\n");)
ExInterlockedInsertTailList(
&Open->ResetIrpList,
&Irp->Tail.Overlay.ListEntry,
&Open->RequestSpinLock);
NdisReset( &Status, Open->AdapterHandle );
if (Status != NDIS_STATUS_PENDING) {
IF_LOUD(DbgPrint("Packet: IoControl - ResetComplte being called\n");)
PacketResetComplete( Open, Status );
}
} else {
// See if it is an Ndis request
PPACKET_OID_DATA OidData=Irp->AssociatedIrp.SystemBuffer;
if (((FunctionCode == IOCTL_PROTOCOL_SET_OID) || (FunctionCode == IOCTL_PROTOCOL_QUERY_OID))
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength == IrpSp->Parameters.DeviceIoControl.OutputBufferLength)
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA))
&&
(IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(PACKET_OID_DATA)-1+OidData->Length)) {
IF_LOUD(DbgPrint("Packet: IoControl: Request: Oid=%08lx, Length=%08lx\n",OidData->Oid,OidData->Length);)
if (FunctionCode == IOCTL_PROTOCOL_SET_OID) {
pRequest->Request.RequestType=NdisRequestSetInformation;
pRequest->Request.DATA.SET_INFORMATION.Oid=OidData->Oid;
pRequest->Request.DATA.SET_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength=OidData->Length;
} else {
pRequest->Request.RequestType=NdisRequestQueryInformation;
pRequest->Request.DATA.QUERY_INFORMATION.Oid=OidData->Oid;
pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer=OidData->Data;
pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength=OidData->Length;
}
NdisRequest(
&Status,
Open->AdapterHandle,
&pRequest->Request
);
} else { // buffer too small
Status=NDIS_STATUS_FAILURE;
pRequest->Request.DATA.SET_INFORMATION.BytesRead=0;
pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten=0;
}
if (Status != NDIS_STATUS_PENDING) {
IF_LOUD(DbgPrint("Packet: Calling RequestCompleteHandler\n");)
PacketRequestComplete(
Open,
&pRequest->Request,
Status
);
}
}
return(STATUS_PENDING);
}
VOID PacketRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
PINTERNAL_REQUEST pRequest;
UINT FunctionCode;
PPACKET_OID_DATA OidData;
IF_LOUD(DbgPrint("Packet: RequestComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
pRequest=CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request);
Irp=pRequest->Irp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FunctionCode=IrpSp->Parameters.DeviceIoControl.IoControlCode;
OidData=Irp->AssociatedIrp.SystemBuffer;
if (FunctionCode == IOCTL_PROTOCOL_SET_OID) {
OidData->Length=pRequest->Request.DATA.SET_INFORMATION.BytesRead;
} else {
if (FunctionCode == IOCTL_PROTOCOL_QUERY_OID) {
OidData->Length=pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
}
}
Irp->IoStatus.Information=IrpSp->Parameters.DeviceIoControl.InputBufferLength;
ExInterlockedInsertTailList(
&Open->RequestList,
&pRequest->ListElement,
&Open->RequestSpinLock);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
VOID PacketStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
{
IF_LOUD(DbgPrint("Packet: Status Indication\n");)
}
VOID PacketStatusComplete( IN NDIS_HANDLE ProtocolBindingContext )
{
IF_LOUD(DbgPrint("Packet: StatusIndicationComplete\n");)
}
#if 0
NTSTATUS PacketCreateSymbolicLink(
IN PUNICODE_STRING DeviceName,
IN BOOLEAN Create
)
{
UNICODE_STRING UnicodeDosDeviceName;
NTSTATUS Status;
if (DeviceName->Length < sizeof(L"\\Device\\")) {
return STATUS_UNSUCCESSFUL;
}
RtlInitUnicodeString(&UnicodeDosDeviceName,NULL);
UnicodeDosDeviceName.MaximumLength=DeviceName->Length+sizeof(L"\\DosDevices")+sizeof(UNICODE_NULL);
UnicodeDosDeviceName.Buffer=ExAllocatePool(
NonPagedPool,
UnicodeDosDeviceName.MaximumLength
);
if (UnicodeDosDeviceName.Buffer != NULL) {
RtlZeroMemory( UnicodeDosDeviceName.Buffer, UnicodeDosDeviceName.MaximumLength );
RtlAppendUnicodeToString( &UnicodeDosDeviceName, L"\\DosDevices\\" );
RtlAppendUnicodeToString( &UnicodeDosDeviceName, (DeviceName->Buffer+(sizeof("\\Device"))) );
IF_LOUD(DbgPrint("Packet: DosDeviceName is %ws\n",UnicodeDosDeviceName.Buffer);)
if (Create) {
Status=IoCreateSymbolicLink(&UnicodeDosDeviceName,DeviceName);
} else {
Status=IoDeleteSymbolicLink(&UnicodeDosDeviceName);
}
ExFreePool(UnicodeDosDeviceName.Buffer);
}
return Status;
}
#endif
NTSTATUS PacketReadRegistry(
IN PWSTR *MacDriverName,
IN PWSTR *PacketDriverName,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS Status;
RTL_QUERY_REGISTRY_TABLE ParamTable[5];
PWSTR Bind = L"Bind"; // LAURI: \Device\W30NT1
PWSTR Export = L"Export"; // \Device\appletalk\W30NT1\0\0
PWSTR Parameters = L"Parameters";
PWSTR Linkage = L"Linkage";
PWCHAR Path;
Path=ExAllocatePool( PagedPool, RegistryPath->Length+sizeof(WCHAR) );
if (!Path) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory( Path, RegistryPath->Length+sizeof(WCHAR) );
RtlCopyMemory( Path, RegistryPath->Buffer, RegistryPath->Length );
IF_LOUD(DbgPrint("Packet: Reg path is %ws\n",RegistryPath->Buffer);)
RtlZeroMemory( ParamTable, sizeof(ParamTable) );
// change to the parmeters key
ParamTable[0].QueryRoutine = NULL;
ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
ParamTable[0].Name = Parameters;
// change to the linkage key
ParamTable[1].QueryRoutine = NULL;
ParamTable[1].Flags = RTL_QUERY_REGISTRY_SUBKEY;
ParamTable[1].Name = Linkage;
// Get the name of the mac driver we should bind to
ParamTable[2].QueryRoutine = PacketQueryRegistryRoutine;
ParamTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
ParamTable[2].Name = Bind;
ParamTable[2].EntryContext = (PVOID)MacDriverName;
ParamTable[2].DefaultType = REG_MULTI_SZ;
// Get the name that we should use for the driver object
ParamTable[3].QueryRoutine = PacketQueryRegistryRoutine;
ParamTable[3].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
ParamTable[3].Name = Export;
ParamTable[3].EntryContext = (PVOID)PacketDriverName;
ParamTable[3].DefaultType = REG_MULTI_SZ;
Status=RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
Path,
ParamTable,
NULL,
NULL
);
ExFreePool(Path);
return Status;
}
NTSTATUS PacketQueryRegistryRoutine(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
PUCHAR Buffer;
IF_LOUD(DbgPrint("Perf: QueryRegistryRoutine\n");)
if (ValueType != REG_MULTI_SZ) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
Buffer=ExAllocatePool(NonPagedPool,ValueLength);
if(!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory( Buffer, ValueData, ValueLength );
*((PUCHAR *)EntryContext)=Buffer;
return STATUS_SUCCESS;
}