diff --git a/BasiliskII/src/Windows/b2ether/nt5/B2Win2k.inf b/BasiliskII/src/Windows/b2ether/nt5/B2Win2k.inf new file mode 100644 index 00000000..d8726610 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/B2Win2k.inf @@ -0,0 +1,80 @@ +[version] +Signature = "$Windows NT$" +Class = NetTrans +ClassGUID = {4d36e975-e325-11ce-bfc1-08002be10318} +Provider = %Msft% +DriverVer = 12/05/1999,5.00.2128 + +[Manufacturer] +%Msft%=MSFT + +[MSFT] +%B2ETHER_Desc%=Install, MS_B2ETHER + +;------------------------------------------------------------------------- +; Installation Section +;------------------------------------------------------------------------- +[Install] +AddReg=Inst_Ndi +Characteristics=0 ; Has no characterstic +CopyFiles=CpyFiles_Sys + +;------------------------------------------------------------------------- +; Ndi installation support +;------------------------------------------------------------------------- +[Inst_Ndi] +HKR,Ndi,Service,,"B2Ether" +HKR,Ndi,HelpText,,%B2ETHER_HelpText% +HKR, Ndi\Interfaces, UpperRange,, noupper +HKR,"Ndi\Interfaces","LowerRange",,"ndis5,ndis4" + +;------------------------------------------------------------------------- +; Service installation support +;------------------------------------------------------------------------- +[Install.Services] +AddService=B2Ether,,B2ETHER_Service_Inst + +[B2Ether_Service_Inst] +DisplayName = %B2ETHER_Desc% +ServiceType = 1 ;SERVICE_KERNEL_DRIVER +StartType = 2 ;SERVICE_AUTO_START +ErrorControl = 1 ;SERVICE_ERROR_NORMAL +ServiceBinary = %12%\B2Ether.sys +LoadOrderGroup = "PNP_TDI" +AddReg = AddReg_B2ETHER_Service_Inst +Description = %B2ETHER_Desc% + +[AddReg_B2ETHER_Service_Inst] +HKLM,"System\CurrentControlSet\Services\B2Ether","TextModeFlags",%REG_DWORD%,0x0001 +HKR,"Parameters","Version",,"5.00.2128" + +;------------------------------------------------------------------------- +; Support for removal of static registry settings +;------------------------------------------------------------------------- +[Install.Remove] +DelReg=Del_Static_Reg + +[Install.Remove.Services] +DelService=B2Ether + +[Del_Static_Reg] +HKLM,"System\CurrentControlSet\Services\B2Ether","TextModeFlags" + +;------------------------------------------------------------------------- +; Declare Destination Directories for file copy/deletion +;------------------------------------------------------------------------- +[DestinationDirs] +CpyFiles_Sys = 12 ; DIRID_DRIVERS + + +;------------------------------------------------------------------------- +; Files to Copy/Delete - Referenced by Install and Remove sections above +;------------------------------------------------------------------------- +[CpyFiles_Sys] +B2Ether.sys,,,2 + +[Strings] +Msft = "Microsoft" +B2ETHER_Desc = "Basilisk II Ethernet Driver" +B2ETHER_HelpText = "Adds ethernet capability to the Basilisk II Macintosh II emulator." +REG_DWORD = 0x10001 diff --git a/BasiliskII/src/Windows/b2ether/nt5/MAKEFILE b/BasiliskII/src/Windows/b2ether/nt5/MAKEFILE new file mode 100644 index 00000000..58189757 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/MAKEFILE @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/BasiliskII/src/Windows/b2ether/nt5/SOURCES b/BasiliskII/src/Windows/b2ether/nt5/SOURCES new file mode 100644 index 00000000..1e0c1aca --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/SOURCES @@ -0,0 +1,17 @@ +# MYMODE must be set + +TARGETNAME=b2ether +TARGETPATH=obj +TARGETTYPE=DRIVER + +TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib +C_DEFINES=$(C_DEFINES) -DNDIS50 +INCLUDES=$(BASEDIR)\inc;$(BASEDIR)\src\network\inc;..\inc + +MSC_WARNING_LEVEL=/W3 /WX /FR /FAcs /D$(MYMODE) + +SOURCES=b2ether.c \ + b2ether_openclose.c \ + b2ether_read.c \ + b2ether_write.c \ + b2ether.rc diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether.c b/BasiliskII/src/Windows/b2ether/nt5/b2ether.c new file mode 100644 index 00000000..ec2c69c9 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether.c @@ -0,0 +1,755 @@ +/* + * 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 "ntddk.h" +#include "ndis.h" +#include "ntddpack.h" +#include "b2ether.h" +#include "stdio.h" + + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath +) +{ + NDIS_PROTOCOL_CHARACTERISTICS protocolChar; + NTSTATUS status = STATUS_SUCCESS; + NDIS_STRING protoName = NDIS_STRING_CONST("B2ether"); + UNICODE_STRING ntDeviceName; + UNICODE_STRING win32DeviceName; + BOOLEAN fSymbolicLink = FALSE; + PDEVICE_OBJECT deviceObject; + + // DebugPrint(("\n\nDriverEntry\n")); + + Globals.DriverObject = DriverObject; + Globals.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); + Globals.RegistryPath.Length = RegistryPath->Length; + Globals.RegistryPath.Buffer = ExAllocatePool( PagedPool, Globals.RegistryPath.MaximumLength ); + if (!Globals.RegistryPath.Buffer) { + // DebugPrint (("Couldn't allocate pool for registry path.")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath); + RtlInitUnicodeString(&ntDeviceName, NT_DEVICE_NAME); + + status = IoCreateDevice (DriverObject, + 0, + &ntDeviceName, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &deviceObject); + + + if (!NT_SUCCESS (status)) { + // Either not enough memory to create a deviceobject or another + // deviceobject with the same name exits. This could happen + // if you install another instance of this device. + goto ERROR; + } + + RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME); + + status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName ); + if (!NT_SUCCESS(status)) goto ERROR; + + fSymbolicLink = TRUE; + + deviceObject->Flags |= DO_BUFFERED_IO; + Globals.ControlDeviceObject = deviceObject; + + InitializeListHead(&Globals.AdapterList); + KeInitializeSpinLock(&Globals.GlobalLock); + + NdisZeroMemory(&protocolChar,sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + + protocolChar.MajorNdisVersion = 5; + protocolChar.MinorNdisVersion = 0; + protocolChar.Name = protoName; + 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.BindAdapterHandler = PacketBindAdapter; + protocolChar.UnbindAdapterHandler = PacketUnbindAdapter; + protocolChar.UnloadHandler = NULL; + protocolChar.ReceivePacketHandler = PacketReceivePacket; + protocolChar.PnPEventHandler = PacketPNPHandler; + + NdisRegisterProtocol( + &status, + &Globals.NdisProtocolHandle, + &protocolChar, + sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + + if (status != NDIS_STATUS_SUCCESS) { + // DebugPrint(("Failed to register protocol with NDIS\n")); + status = STATUS_UNSUCCESSFUL; + goto ERROR; + } + + 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; + + return(STATUS_SUCCESS); + +ERROR: + if(deviceObject) + IoDeleteDevice(deviceObject); + if(fSymbolicLink) + IoDeleteSymbolicLink(&win32DeviceName); + if(Globals.RegistryPath.Buffer) + ExFreePool(Globals.RegistryPath.Buffer); + return status; +} + + +VOID PacketUnload( IN PDRIVER_OBJECT DriverObject ) +{ + NDIS_STATUS status; + UNICODE_STRING win32DeviceName; + + // DebugPrint(("Unload Enter\n")); + + RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME); + IoDeleteSymbolicLink(&win32DeviceName); + + if(Globals.ControlDeviceObject) + IoDeleteDevice(Globals.ControlDeviceObject); + + // Unbind from all the adapters. The system removes the driver code + // pages from the memory as soon as the unload returns. So you + // must wait for all the CloseAdapterCompleteHandler to finish + // before returning from the unload routine. You don't any callbacks + // to trigger after the driver is unloaded. + + while(DriverObject->DeviceObject) { + PacketUnbindAdapter(&status, DriverObject->DeviceObject->DeviceExtension,NULL); + } + + if(Globals.RegistryPath.Buffer) + ExFreePool(Globals.RegistryPath.Buffer); + + // DebugPrint(("Deregister\n")); + + NdisDeregisterProtocol( &status, Globals.NdisProtocolHandle ); + // DebugPrint(("Unload Exit\n")); +} + + + +NTSTATUS PacketIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + PIO_STACK_LOCATION irpSp; + PINTERNAL_REQUEST pRequest; + ULONG functionCode; + NDIS_STATUS status; + ULONG dataLength =0; + + // DebugPrint(("IoControl\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + functionCode=irpSp->Parameters.DeviceIoControl.IoControlCode; + + if (functionCode == IOCTL_ENUM_ADAPTERS) { + // If the request is not made to the controlobject, fail the request. + + if(DeviceObject != Globals.ControlDeviceObject) { + status = STATUS_INVALID_DEVICE_REQUEST; + } else { + status = PacketGetAdapterList( + Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.DeviceIoControl.OutputBufferLength, + &dataLength + ); + } + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = dataLength; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + open = DeviceObject->DeviceExtension; + IoIncrement(open); + + if(!open->Bound) { + Irp->IoStatus.Status = status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + IoDecrement(open); + return status; + } + + // DebugPrint(("Function code is %08lx buff size=%08lx %08lx\n", + // functionCode,irpSp->Parameters.DeviceIoControl.InputBufferLength, + // irpSp->Parameters.DeviceIoControl.OutputBufferLength)); + + // Important: Since we have marked the IRP pending, we must return + // STATUS_PENDING even we happen to complete the IRP synchronously. + + IoMarkIrpPending(Irp); + + if (functionCode == IOCTL_PROTOCOL_RESET) { + // DebugPrint(("IoControl - Reset request\n")); + + // + // Since NDIS doesn't have an interface to cancel a request + // pending at miniport, we cannot set a cancel routine. + // As a result if the application that made the request + // terminates, we wait in the Cleanup routine for all pending + // NDIS requests to complete. + + ExInterlockedInsertTailList( + &open->ResetIrpList, + &Irp->Tail.Overlay.ListEntry, + &open->ResetQueueLock); + + NdisReset( &status, open->AdapterHandle ); + + if (status != NDIS_STATUS_PENDING) { + // DebugPrint(("IoControl - ResetComplete being called\n")); + PacketResetComplete( open, status ); + } + } else { + // See if it is an Ndis request + PPACKET_OID_DATA OidData=Irp->AssociatedIrp.SystemBuffer; + + pRequest = ExAllocatePool(NonPagedPool, sizeof(INTERNAL_REQUEST)); + + if(!pRequest) { + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return STATUS_PENDING; + } + pRequest->Irp=Irp; + + 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)) + { + // DebugPrint(("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 { + status=NDIS_STATUS_FAILURE; + pRequest->Request.DATA.SET_INFORMATION.BytesRead=0; + pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten=0; + } + + if (status != NDIS_STATUS_PENDING) { + // DebugPrint(("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; + + // DebugPrint(("RequestComplete\n")); + + open = (POPEN_INSTANCE)ProtocolBindingContext; + + pRequest=CONTAINING_RECORD(NdisRequest,INTERNAL_REQUEST,Request); + irp = pRequest->Irp; + + if(Status == NDIS_STATUS_SUCCESS) { + 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.Status = STATUS_SUCCESS; + irp->IoStatus.Information=irpSp->Parameters.DeviceIoControl.InputBufferLength; + } else { + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + irp->IoStatus.Information = 0; + } + + ExFreePool(pRequest); + IoCompleteRequest(irp, IO_NO_INCREMENT); + IoDecrement(open); +} + + +VOID +PacketStatus( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize +) +{ + // DebugPrint(("Indication Status: %0x, StatusBufferSize: %d\n", Status, StatusBufferSize)); +} + + +VOID PacketStatusComplete( IN NDIS_HANDLE ProtocolBindingContext ) +{ + // DebugPrint(("StatusIndicationComplete\n")); +} + + +NTSTATUS +PacketGetAdapterList( + IN PVOID Buffer, + IN ULONG Length, + IN OUT PULONG DataLength +) +{ + ULONG requiredLength = 0, numOfAdapters = 0; + KIRQL oldIrql; + PLIST_ENTRY thisEntry, listHead; + POPEN_INSTANCE open; + + // DebugPrint(("Enter PacketGetAdapterList\n")); + + KeAcquireSpinLock(&Globals.GlobalLock, &oldIrql); + + // Walks the list to find out total space required for AdapterName and Symbolic Link. + + listHead = &Globals.AdapterList; + + for( thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = thisEntry->Flink) { + open = CONTAINING_RECORD(thisEntry, OPEN_INSTANCE, AdapterListEntry); + requiredLength += open->AdapterName.Length + sizeof(UNICODE_NULL); + requiredLength += open->SymbolicLink.Length + sizeof(UNICODE_NULL); + numOfAdapters++; + } + + // + // We will return the data in the following format: + // numOfAdapters + One_Or_More("AdapterName\0" + "SymbolicLink\0") + UNICODE_NULL + // So let's include the numOfAdapters and UNICODE_NULL size + // to the total length. + // + + requiredLength += sizeof(ULONG) + sizeof(UNICODE_NULL); + *DataLength = requiredLength; + + if(requiredLength > Length) { + KeReleaseSpinLock(&Globals.GlobalLock, oldIrql); + return STATUS_BUFFER_TOO_SMALL; + } + + *(PULONG)Buffer = numOfAdapters; + (PCHAR)Buffer += sizeof(ULONG); + + for( thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = thisEntry->Flink ) { + open = CONTAINING_RECORD(thisEntry, OPEN_INSTANCE, AdapterListEntry); + RtlCopyMemory( Buffer, open->AdapterName.Buffer, open->AdapterName.Length+sizeof(WCHAR) ); + (PCHAR)Buffer += open->AdapterName.Length+sizeof(WCHAR); + RtlCopyMemory( Buffer, open->SymbolicLink.Buffer, open->SymbolicLink.Length+sizeof(WCHAR) ); + (PCHAR)Buffer += open->SymbolicLink.Length+sizeof(WCHAR); + } + + *(PWCHAR)Buffer = UNICODE_NULL; + KeReleaseSpinLock(&Globals.GlobalLock, oldIrql); + return STATUS_SUCCESS; +} + +VOID +PacketBindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE BindContext, + IN PNDIS_STRING DeviceName, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2 +) +{ + NDIS_STATUS status; + UINT mediumIndex; + USHORT length; + POPEN_INSTANCE open = NULL; + UNICODE_STRING unicodeDeviceName; + PDEVICE_OBJECT deviceObject = NULL; + PWSTR symbolicLink = NULL, deviceNameStr = NULL; + NDIS_MEDIUM mediumArray = NdisMedium802_3; // Ethernet medium + + // DebugPrint(("Binding DeviceName %ws\n", DeviceName->Buffer)); + + do { + // Create a deviceobject for every adapter we bind to. + // To make a name for the deviceObject, we will append Packet_ + // to the name portion of the input DeviceName. + + unicodeDeviceName.Buffer = NULL; + length = DeviceName->Length + 7 * sizeof(WCHAR) + sizeof(UNICODE_NULL); + + deviceNameStr = ExAllocatePool(NonPagedPool, length); + if (!deviceNameStr) { + // DebugPrint(("Memory allocation for create symbolic failed\n")); + *Status = NDIS_STATUS_FAILURE; + break; + } + swprintf(deviceNameStr, L"\\Device\\B2ether_%ws", &DeviceName->Buffer[8]); + RtlInitUnicodeString(&unicodeDeviceName, deviceNameStr); + + // DebugPrint(("Exported DeviceName %ws\n", unicodeDeviceName.Buffer)); + + status = IoCreateDevice( + Globals.DriverObject, + sizeof(OPEN_INSTANCE), + &unicodeDeviceName, + FILE_DEVICE_PROTOCOL, + 0, + TRUE, // only one handle to the device at a time. + &deviceObject + ); + + if (status != STATUS_SUCCESS) { + // DebugPrint(("CreateDevice Failed: %x\n", status)); + *Status = NDIS_STATUS_FAILURE; + break; + } + + deviceObject->Flags |= DO_DIRECT_IO; + open = (POPEN_INSTANCE) deviceObject->DeviceExtension; + open->DeviceObject = deviceObject; + + // Create a symbolic link. + // We need to replace Device from \Device\Packet_{GUID} with DosDevices + // to create a symbolic link of the form \DosDevices\Packet_{GUID} + // There is a four character difference between these two + // strings. + + length = unicodeDeviceName.Length + sizeof(UNICODE_NULL) + (4 * sizeof(WCHAR)); + + symbolicLink = ExAllocatePool(NonPagedPool, length); + if (!symbolicLink) { + // DebugPrint(("Memory allocation for create symbolic failed\n")); + *Status = NDIS_STATUS_FAILURE; + break; + } + + swprintf( symbolicLink, L"\\DosDevices\\%ws", &unicodeDeviceName.Buffer[8]); + + RtlInitUnicodeString(&open->SymbolicLink,symbolicLink); + + // DebugPrint(("Symbolic Link: %ws\n", open->SymbolicLink.Buffer)); + + status = IoCreateSymbolicLink( + (PUNICODE_STRING) &open->SymbolicLink, + (PUNICODE_STRING) &unicodeDeviceName + ); + if (status != STATUS_SUCCESS) { + // DebugPrint(("Create symbolic failed\n")); + *Status = NDIS_STATUS_FAILURE; + break; + } + + ExFreePool(unicodeDeviceName.Buffer); + unicodeDeviceName.Buffer = NULL; + + NdisAllocatePacketPool( + &status, + &open->PacketPool, + TRANSMIT_PACKETS, + sizeof(PACKET_RESERVED)); + + if (status != NDIS_STATUS_SUCCESS) { + // DebugPrint(("B2ether: Failed to allocate packet pool\n")); + break; + } + + NdisInitializeEvent(&open->Event); + InitializeListHead(&open->ResetIrpList); + KeInitializeSpinLock(&open->ResetQueueLock); + KeInitializeSpinLock(&open->RcvQSpinLock); + InitializeListHead(&open->RcvList); + + NdisOpenAdapter(Status, + &status, + &open->AdapterHandle, + &mediumIndex, + &mediumArray, + sizeof(mediumArray)/sizeof(NDIS_MEDIUM), + Globals.NdisProtocolHandle, + open, + DeviceName, + 0, + NULL); + + if(*Status == NDIS_STATUS_PENDING) { + NdisWaitEvent(&open->Event, 0); + *Status = open->Status; + } + if(*Status != NDIS_STATUS_SUCCESS) { + // DebugPrint(("Failed to openAdapter\n")); + break; + } + + open->IrpCount = 0; + InterlockedExchange( (PLONG)&open->Bound, TRUE ); + NdisInitializeEvent(&open->CleanupEvent); + + NdisSetEvent(&open->CleanupEvent); + + NdisQueryAdapterInstanceName( &open->AdapterName, open->AdapterHandle ); + // DebugPrint(("Bound AdapterName %ws\n", open->AdapterName.Buffer)); + + open->Medium = mediumArray; + + InitializeListHead(&open->AdapterListEntry); + + ExInterlockedInsertTailList(&Globals.AdapterList, + &open->AdapterListEntry, + &Globals.GlobalLock); + + // Clear the DO_DEVICE_INITIALIZING flag. This is required + // if you create deviceobjects outside of DriverEntry. + // Untill you do this, application cannot send I/O request. + + deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + } while (FALSE); + + if (*Status != NDIS_STATUS_SUCCESS) { + if (open && open->PacketPool) NdisFreePacketPool(open->PacketPool); + if (deviceObject) IoDeleteDevice(deviceObject); + if(unicodeDeviceName.Buffer) ExFreePool(unicodeDeviceName.Buffer); + if(symbolicLink) { + IoDeleteSymbolicLink(&open->SymbolicLink); + ExFreePool(open->SymbolicLink.Buffer); + } + } + // DebugPrint(("Return BindAdapter :0x%x\n", *Status)); +} + + +VOID +PacketUnbindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE UnbindContext +) +{ + POPEN_INSTANCE open =(POPEN_INSTANCE)ProtocolBindingContext; + KIRQL oldIrql; + + // DebugPrint(("PacketUnbindAdapter :%ws\n", open->AdapterName.Buffer)); + + if(open->AdapterHandle) { + NdisResetEvent(&open->Event); + InterlockedExchange( (PLONG) &open->Bound, FALSE ); + PacketCancelReadIrps(open->DeviceObject); + + // DebugPrint(("Waiting on CleanupEvent\n")); + NdisWaitEvent(&open->CleanupEvent, 0); + + NdisCloseAdapter(Status, open->AdapterHandle); + + // Wait for it to complete + if(*Status == NDIS_STATUS_PENDING) { + NdisWaitEvent(&open->Event, 0); + *Status = open->Status; + } else { + *Status = NDIS_STATUS_FAILURE; + // ASSERT(0); + } + + KeAcquireSpinLock(&Globals.GlobalLock, &oldIrql); + RemoveEntryList(&open->AdapterListEntry); + KeReleaseSpinLock(&Globals.GlobalLock, oldIrql); + + NdisFreePacketPool(open->PacketPool); + + NdisFreeMemory(open->AdapterName.Buffer, open->AdapterName.Length, 0); + + IoDeleteSymbolicLink(&open->SymbolicLink); + ExFreePool(open->SymbolicLink.Buffer); + + IoDeleteDevice(open->DeviceObject); + } + + // DebugPrint(("Exit PacketUnbindAdapter\n")); +} + +VOID +PacketOpenAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus +) +{ + POPEN_INSTANCE open = ProtocolBindingContext; + + // DebugPrint(("B2ether: OpenAdapterComplete\n")); + + open->Status = Status; + NdisSetEvent(&open->Event); +} + +VOID +PacketCloseAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status +) +{ + POPEN_INSTANCE open = ProtocolBindingContext; + + // DebugPrint(("CloseAdapterComplete\n")); + + open->Status = Status; + NdisSetEvent(&open->Event); +} + + +NDIS_STATUS +PacketPNPHandler( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNET_PNP_EVENT NetPnPEvent +) +{ + POPEN_INSTANCE open =(POPEN_INSTANCE)ProtocolBindingContext; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PNET_DEVICE_POWER_STATE powerState; + + // DebugPrint(("PacketPNPHandler\n")); + + powerState = (PNET_DEVICE_POWER_STATE)NetPnPEvent->Buffer; + + // This will happen when all entities in the system need to be notified + // + //if(open == NULL) + //{ + // return Status; + //} + + switch(NetPnPEvent->NetEvent) { + case NetEventSetPower : + // DebugPrint(("NetEventSetPower\n")); + switch (*powerState) { + case NetDeviceStateD0: + Status = NDIS_STATUS_SUCCESS; + break; + default: + // We can't suspend, so we ask NDIS to Unbind us by + // returning this status: + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + break; + case NetEventQueryPower : + // DebugPrint(("NetEventQueryPower\n")); + break; + case NetEventQueryRemoveDevice : + // DebugPrint(("NetEventQueryRemoveDevice \n")); + break; + case NetEventCancelRemoveDevice : + // DebugPrint(("NetEventCancelRemoveDevice \n")); + break; + case NetEventReconfigure : + // The protocol should always succeed this event by returning NDIS_STATUS_SUCCESS + // DebugPrint(("NetEventReconfigure\n")); + break; + case NetEventBindsComplete : + // DebugPrint(("NetEventBindsComplete \n")); + break; + case NetEventPnPCapabilities : + // DebugPrint(("NetEventPnPCapabilities \n")); + case NetEventBindList: + // DebugPrint(("NetEventBindList \n")); + default: + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + return Status; +} + + +VOID IoIncrement( IN OUT POPEN_INSTANCE Open ) +{ + LONG result = InterlockedIncrement(&Open->IrpCount); + + //DebugPrint(("IoIncrement %d\n", result)); + + // Need to clear event (when IrpCount bumps from 0 to 1) + if (result == 1) { + NdisResetEvent(&Open->CleanupEvent); + } +} + + +VOID IoDecrement ( IN OUT POPEN_INSTANCE Open ) +{ + LONG result = InterlockedDecrement(&Open->IrpCount); + + //DebugPrint(("IoDecrement %d\n", result)); + + if (result == 0) { + // Set the event when the count transition from 1 to 0. + NdisSetEvent (&Open->CleanupEvent); + } +} diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether.h b/BasiliskII/src/Windows/b2ether/nt5/b2ether.h new file mode 100644 index 00000000..e1c729f8 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether.h @@ -0,0 +1,276 @@ +/* + * 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 + */ + +#ifndef _B2ETHER_H_ +#define _B2ETHER_H_ + +#undef ExAllocatePool +#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a, b, 'te2B') + +#if DBG +#define DebugPrint(_x_) \ + DbgPrint("B2ETHER: ");\ + DbgPrint _x_; +#else +#define DebugPrint(_x_) +#endif + +#define NT_DEVICE_NAME L"\\Device\\B2ether" +#define DOS_DEVICE_NAME L"\\DosDevices\\B2ether" + +typedef struct _GLOBAL { + PDRIVER_OBJECT DriverObject; + NDIS_HANDLE NdisProtocolHandle; + UNICODE_STRING RegistryPath; + LIST_ENTRY AdapterList; + KSPIN_LOCK GlobalLock; + PDEVICE_OBJECT ControlDeviceObject; +} GLOBAL, *PGLOBAL; + +GLOBAL Globals; + +typedef struct _INTERNAL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; +} INTERNAL_REQUEST, *PINTERNAL_REQUEST; + +typedef struct _OPEN_INSTANCE { + PDEVICE_OBJECT DeviceObject; + ULONG IrpCount; + NDIS_STRING AdapterName; + NDIS_STRING SymbolicLink; + NDIS_HANDLE AdapterHandle; + NDIS_HANDLE PacketPool; + KSPIN_LOCK RcvQSpinLock; + LIST_ENTRY RcvList; + NDIS_MEDIUM Medium; + KSPIN_LOCK ResetQueueLock; + LIST_ENTRY ResetIrpList; + NDIS_STATUS Status; + NDIS_EVENT Event; + NDIS_EVENT CleanupEvent; + LIST_ENTRY AdapterListEntry; + BOOLEAN Bound; + CHAR Filler[3]; +} OPEN_INSTANCE, *POPEN_INSTANCE; + +typedef struct _PACKET_RESERVED { + LIST_ENTRY ListElement; + PIRP Irp; + PMDL pMdl; +} PACKET_RESERVED, *PPACKET_RESERVED; + + +#define ETHERNET_HEADER_LENGTH 14 +#define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved)) +#define TRANSMIT_PACKETS 16 + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +PacketCancelReadIrps( + IN PDEVICE_OBJECT DeviceObject +); + +NTSTATUS +PacketCleanup( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +VOID +PacketBindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE BindContext, + IN PNDIS_STRING DeviceName, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2 + ); +VOID +PacketUnbindAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE UnbindContext + ); + + +VOID +PacketOpenAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ); + +VOID +PacketCloseAdapterComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + + +NDIS_STATUS +PacketReceiveIndicate( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookAheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +VOID +PacketReceiveComplete( + IN NDIS_HANDLE ProtocolBindingContext + ); + + +VOID +PacketRequestComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_REQUEST pRequest, + IN NDIS_STATUS Status + ); + +VOID +PacketSendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status + ); + + +VOID +PacketResetComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ); + + +VOID +PacketStatus( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ); + + +VOID +PacketStatusComplete( + IN NDIS_HANDLE ProtocolBindingContext + ); + +VOID +PacketTransferDataComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ); + + +NTSTATUS +PacketShutdown( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +VOID +PacketUnload( + IN PDRIVER_OBJECT DriverObject + ); + + + +NTSTATUS +PacketOpen( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +PacketClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +PacketWrite( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +PacketRead( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +PacketIoControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +VOID +PacketCancelRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +INT +PacketReceivePacket( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet + ); + +NTSTATUS +PacketGetAdapterList( + IN PVOID Buffer, + IN ULONG Length, + IN OUT PULONG DataLength + ); + +NDIS_STATUS +PacketPNPHandler( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNET_PNP_EVENT pNetPnPEvent + ); + + +VOID +IoIncrement ( + IN OUT POPEN_INSTANCE Open + ); + +VOID +IoDecrement ( + IN OUT POPEN_INSTANCE Open + ); + +#endif //_B2ETHER_H_ diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether.rc b/BasiliskII/src/Windows/b2ether/nt5/b2ether.rc new file mode 100644 index 00000000..3e4e918a --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether.rc @@ -0,0 +1,10 @@ +#include +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +#define VER_FILEDESCRIPTION_STR "Basilisk II Protocol Driver" +#define VER_INTERNALNAME_STR "B2ETHER.SYS" +#define VER_ORIGINALFILENAME_STR "B2ETHER.SYS" + +#include "common.ver" diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether_openclose.c b/BasiliskII/src/Windows/b2ether/nt5/b2ether_openclose.c new file mode 100644 index 00000000..b584dbc7 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether_openclose.c @@ -0,0 +1,155 @@ +/* + * 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 "ntddk.h" +#include "ndis.h" +#include "b2ether.h" + +NTSTATUS PacketOpen( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + NTSTATUS status = STATUS_SUCCESS; + + // DebugPrint(("OpenAdapter\n")); + + if(DeviceObject == Globals.ControlDeviceObject) { + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + open = DeviceObject->DeviceExtension; + + // DebugPrint(("AdapterName :%ws\n", open->AdapterName.Buffer)); + + IoIncrement(open); + + if(!open->Bound) { + status = STATUS_DEVICE_NOT_READY; + } + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return status; +} + + +NTSTATUS PacketClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + NTSTATUS status = STATUS_SUCCESS; + + // DebugPrint(("CloseAdapter \n")); + + if(DeviceObject == Globals.ControlDeviceObject) { + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + open = DeviceObject->DeviceExtension; + IoIncrement(open); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return status; +} + + +NTSTATUS PacketCleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + NTSTATUS status = STATUS_SUCCESS; + + // DebugPrint(("Packet: Cleanup\n")); + + if(DeviceObject == Globals.ControlDeviceObject) { + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + open = DeviceObject->DeviceExtension; + + IoIncrement(open); + + PacketCancelReadIrps(DeviceObject); + + // Since the current implementation of NDIS doesn't + // allow us to cancel requests pending at the + // minport, we must wait here until they complete. + + IoDecrement(open); + + NdisWaitEvent(&open->CleanupEvent, 0); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + return status; +} + + +VOID +PacketResetComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status +) +{ + POPEN_INSTANCE open; + PIRP irp; + + PLIST_ENTRY resetListEntry; + + // DebugPrint(("PacketResetComplte\n")); + + open= (POPEN_INSTANCE)ProtocolBindingContext; + + resetListEntry=ExInterlockedRemoveHeadList( + &open->ResetIrpList, + &open->ResetQueueLock + ); + +#if DBG + if (resetListEntry == NULL) { + DbgBreakPoint(); + return; + } +#endif + + irp=CONTAINING_RECORD(resetListEntry,IRP,Tail.Overlay.ListEntry); + + if(Status == NDIS_STATUS_SUCCESS) { + irp->IoStatus.Status = STATUS_SUCCESS; + } else { + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + } + + irp->IoStatus.Information = 0; + IoCompleteRequest(irp, IO_NO_INCREMENT); + IoDecrement(open); + + // DebugPrint(("PacketResetComplte exit\n")); +} diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether_read.c b/BasiliskII/src/Windows/b2ether/nt5/b2ether_read.c new file mode 100644 index 00000000..3f4f100d --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether_read.c @@ -0,0 +1,418 @@ +/* + * 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 "ntddk.h" +#include "ndis.h" +#include "b2ether.h" + + +NTSTATUS PacketRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + PNDIS_PACKET pPacket; + NDIS_STATUS status; + NTSTATUS ntStatus; + PIO_STACK_LOCATION irpSp; + + // DebugPrint(("Read\n")); + + open = DeviceObject->DeviceExtension; + + IoIncrement(open); + + if(!open->Bound) { + ntStatus = STATUS_DEVICE_NOT_READY; + goto ERROR; + } + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + if (irpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) { + ntStatus = STATUS_BUFFER_TOO_SMALL; + goto ERROR; + } + + NdisAllocatePacket( &status, &pPacket, open->PacketPool ); + if (status != NDIS_STATUS_SUCCESS) { + // DebugPrint(("Packet: Read- No free packets\n")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto ERROR; + } + + RESERVED(pPacket)->Irp=Irp; + RESERVED(pPacket)->pMdl=NULL; + IoMarkIrpPending(Irp); + + IoSetCancelRoutine(Irp, PacketCancelRoutine); + + ExInterlockedInsertTailList( + &open->RcvList, + &RESERVED(pPacket)->ListElement, + &open->RcvQSpinLock); + + return STATUS_PENDING; + +ERROR: + Irp->IoStatus.Status = ntStatus; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return ntStatus; +} + + + +NDIS_STATUS +PacketReceiveIndicate ( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookAheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize +) +{ + POPEN_INSTANCE open; + PIO_STACK_LOCATION irpSp; + PIRP irp; + PLIST_ENTRY packetListEntry; + PNDIS_PACKET pPacket; + ULONG sizeToTransfer; + NDIS_STATUS status; + UINT bytesTransfered = 0; + ULONG bufferLength; + PPACKET_RESERVED reserved; + PMDL pMdl; + + // DebugPrint(("ReceiveIndicate\n")); + + open= (POPEN_INSTANCE)ProtocolBindingContext; + + if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) { + return NDIS_STATUS_SUCCESS; + } + + // See if there are any pending read that we can satisfy + packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); + + if (packetListEntry == NULL) { + // DebugPrint(("No pending read, dropping packets\n")); + return NDIS_STATUS_NOT_ACCEPTED; + } + + reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); + pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); + + irp = RESERVED(pPacket)->Irp; + irpSp = IoGetCurrentIrpStackLocation(irp); + + // We don't have to worry about the situation where the IRP is cancelled + // after we remove it from the queue and before we reset the cancel + // routine because the cancel routine has been coded to cancel an IRP + // only if it's in the queue. + + IoSetCancelRoutine(irp, NULL); + + bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH; + + sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength; + + NdisMoveMappedMemory( + MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority), + HeaderBuffer, + HeaderBufferSize + ); + + pMdl=IoAllocateMdl( + MmGetMdlVirtualAddress(irp->MdlAddress), + MmGetMdlByteCount(irp->MdlAddress), + FALSE, + FALSE, + NULL + ); + + if (pMdl == NULL) { + // DebugPrint(("Packet: Read-Failed to allocate Mdl\n")); + status = NDIS_STATUS_RESOURCES; + goto ERROR; + } + + IoBuildPartialMdl( + irp->MdlAddress, + pMdl, + ((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH, + 0 + ); + + pMdl->Next = NULL; + + RESERVED(pPacket)->pMdl=pMdl; + + NdisChainBufferAtFront(pPacket,pMdl); + + NdisTransferData( + &status, + open->AdapterHandle, + MacReceiveContext, + 0, + sizeToTransfer, + pPacket, + &bytesTransfered + ); + + if (status == NDIS_STATUS_PENDING) { + return NDIS_STATUS_SUCCESS; + } + +ERROR: + PacketTransferDataComplete( open, pPacket, status, bytesTransfered ); + return NDIS_STATUS_SUCCESS; +} + + +VOID +PacketTransferDataComplete ( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status, + IN UINT BytesTransfered +) +{ + PIO_STACK_LOCATION irpSp; + POPEN_INSTANCE open; + PIRP irp; + PMDL pMdl; + + // DebugPrint(("Packet: TransferDataComplete\n")); + + open = (POPEN_INSTANCE)ProtocolBindingContext; + irp = RESERVED(pPacket)->Irp; + irpSp = IoGetCurrentIrpStackLocation(irp); + pMdl = RESERVED(pPacket)->pMdl; + + + if(pMdl) IoFreeMdl(pMdl); + + NdisFreePacket(pPacket); + + if(Status == NDIS_STATUS_SUCCESS) { + irp->IoStatus.Status = STATUS_SUCCESS; + irp->IoStatus.Information = BytesTransfered+ETHERNET_HEADER_LENGTH; + } else { + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + irp->IoStatus.Information = 0; + } + + // DebugPrint(("BytesTransfered:%d\n", irp->IoStatus.Information)); + + IoCompleteRequest(irp, IO_NO_INCREMENT); + IoDecrement(open); +} + +VOID PacketReceiveComplete( IN NDIS_HANDLE ProtocolBindingContext ) +{ +} + +INT +PacketReceivePacket( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet +) +{ + UINT bytesTransfered = 0; + POPEN_INSTANCE open; + PIRP irp; + PNDIS_PACKET myPacket; + PLIST_ENTRY packetListEntry; + ULONG bufferLength; + PPACKET_RESERVED reserved; + PIO_STACK_LOCATION irpSp; + PMDL mdl; + PVOID startAddress; + NTSTATUS status; + + // DebugPrint(("PacketReceivePacket\n")); + + open = (POPEN_INSTANCE)ProtocolBindingContext; + + packetListEntry = ExInterlockedRemoveHeadList( + &open->RcvList, + &open->RcvQSpinLock + ); + + if (packetListEntry == NULL) { + // DebugPrint(("No pending read, dropping packets\n")); + return 0; + } + + reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); + myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); + + irp = RESERVED(myPacket)->Irp; + irpSp = IoGetCurrentIrpStackLocation(irp); + + // We don't have to worry about the situation where the IRP is cancelled + // after we remove it from the queue and before we reset the cancel + // routine because the cancel routine has been coded to cancel an IRP + // only if it's in the queue. + + IoSetCancelRoutine(irp, NULL); + + // Following block of code locks the destination packet + // MDLs in a safe manner. This is a temporary workaround + // for NdisCopyFromPacketToPacket that currently doesn't use + // safe functions to lock pages of MDL. This is required to + // prevent system from bugchecking under low memory resources. + // + { + PVOID virtualAddress; + PNDIS_BUFFER firstBuffer, nextBuffer; + ULONG totalLength; + + NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength); + while( firstBuffer ) { + NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority ); + if(!virtualAddress) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto CleanExit; + } + NdisGetNextBuffer(firstBuffer, &nextBuffer); + firstBuffer = nextBuffer; + } + } + + NdisChainBufferAtFront( myPacket, irp->MdlAddress ); + bufferLength=irpSp->Parameters.Read.Length; + NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0, &bytesTransfered ); + +CleanExit: + NdisFreePacket(myPacket); + irp->IoStatus.Status = status; + irp->IoStatus.Information = bytesTransfered; + IoCompleteRequest(irp, IO_NO_INCREMENT); + // DebugPrint(("BytesTransfered:%d\n", bytesTransfered)); + IoDecrement(open); + return 0; +} + + +VOID +PacketCancelRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) + +{ + POPEN_INSTANCE open = DeviceObject->DeviceExtension; + KIRQL oldIrql; + PIRP irpToComplete = NULL; + PLIST_ENTRY thisEntry, listHead; + PIRP pendingIrp; + PNDIS_PACKET myPacket = NULL; + PPACKET_RESERVED reserved; + PMDL mdl; + + // Don't assume that the IRP being cancelled is in the queue. + // Only complete the IRP if it IS in the queue. + // + // Must acquire the local spinlock before releasing + // the global cancel spinlock + // + // DebugPrint(("PacketCancelRoutine\n")); + + oldIrql = Irp->CancelIrql; + + // One should not intermix KeAcquireSpinLock(AtDpcLevel) + // and ExInterlocked...List() functions on the same spinlock if the + // routines that use the lock run at IRQL > DISPATCH_LEVEL. + // After acquiring the lock using Ke function, if we got interrupted + // and entered into an ISR and tried to manipulate the list using + // ExInterlocked...List function with the same lock, we deadlock. + // In this sample we can safely do that because none of our routines + // will be called at IRQL > DISPATCH_LEVEL. + + KeAcquireSpinLockAtDpcLevel(&open->RcvQSpinLock); + IoReleaseCancelSpinLock( KeGetCurrentIrql() ); + + listHead = &open->RcvList; + for( thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = thisEntry->Flink ) { + reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); + myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); + pendingIrp = RESERVED(myPacket)->Irp; + if (pendingIrp == Irp) { + RemoveEntryList(thisEntry); + irpToComplete = pendingIrp; + break; + } + } + + KeReleaseSpinLock(&open->RcvQSpinLock, oldIrql); + + if(irpToComplete) { + // DebugPrint(("Cancelling IRP\n")); + // ASSERT(myPacket); + + NdisFreePacket(myPacket); + + irpToComplete->IoStatus.Status = STATUS_CANCELLED; + irpToComplete->IoStatus.Information = 0; + IoCompleteRequest(irpToComplete, IO_NO_INCREMENT); + IoDecrement(open); + } +} + + +NTSTATUS PacketCancelReadIrps( IN PDEVICE_OBJECT DeviceObject ) +{ + POPEN_INSTANCE open = DeviceObject->DeviceExtension; + PLIST_ENTRY thisEntry; + PIRP pendingIrp; + PNDIS_PACKET myPacket = NULL; + PPACKET_RESERVED reserved; + PMDL mdl; + + // DebugPrint(("PacketCancelReadIrps\n")); + + // Walk through the RcvList and cancel all read IRPs. + + while( thisEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock )) { + reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); + myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); + + ASSERT(myPacket); + + pendingIrp = RESERVED(myPacket)->Irp; + + NdisFreePacket(myPacket); + + // DebugPrint(("Cancelled : 0%0x\n", pendingIrp)); + + IoSetCancelRoutine(pendingIrp, NULL); + + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + IoDecrement(open); + } + + return STATUS_SUCCESS; +} diff --git a/BasiliskII/src/Windows/b2ether/nt5/b2ether_write.c b/BasiliskII/src/Windows/b2ether/nt5/b2ether_write.c new file mode 100644 index 00000000..42b1ec94 --- /dev/null +++ b/BasiliskII/src/Windows/b2ether/nt5/b2ether_write.c @@ -0,0 +1,101 @@ +/* + * 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 "ntddk.h" +#include "ndis.h" +#include "b2ether.h" + + +NTSTATUS PacketWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) +{ + POPEN_INSTANCE open; + PNDIS_PACKET pPacket; + NDIS_STATUS Status; + + // DebugPrint(("SendAdapter\n")); + + open = DeviceObject->DeviceExtension; + + IoIncrement(open); + + if(!open->Bound) { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return STATUS_UNSUCCESSFUL; + } + + NdisAllocatePacket( &Status, &pPacket, open->PacketPool ); + + if (Status != NDIS_STATUS_SUCCESS) { + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + IoDecrement(open); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RESERVED(pPacket)->Irp=Irp; + + NdisChainBufferAtFront(pPacket,Irp->MdlAddress); + + // Important: Since we have marked the IRP pending, we must return + // STATUS_PENDING even we happen to complete the IRP synchronously. + + IoMarkIrpPending(Irp); + + NdisSend( &Status, open->AdapterHandle, pPacket ); + + if (Status != NDIS_STATUS_PENDING) { + PacketSendComplete( open, pPacket, Status ); + } + + return STATUS_PENDING; +} + +VOID +PacketSendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET pPacket, + IN NDIS_STATUS Status +) +{ + PIRP irp; + PIO_STACK_LOCATION irpSp; + + // DebugPrint(("Packet: SendComplete :%x\n", Status)); + + irp = RESERVED(pPacket)->Irp; + irpSp = IoGetCurrentIrpStackLocation(irp); + + NdisFreePacket(pPacket); + + if(Status == NDIS_STATUS_SUCCESS) { + irp->IoStatus.Information = irpSp->Parameters.Write.Length; + irp->IoStatus.Status = STATUS_SUCCESS; + } else { + irp->IoStatus.Information = 0; + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + } + + IoCompleteRequest(irp, IO_NO_INCREMENT); + IoDecrement((POPEN_INSTANCE)ProtocolBindingContext); +}