| /* | |
| * 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; | |
| } |