--- /dev/null
+/*++\r
+\r
+Copyright (c) 1992-2000 Microsoft Corporation\r
+ \r
+Module Name:\r
+ \r
+ passthru.c\r
+\r
+Abstract:\r
+\r
+ Ndis Intermediate Miniport driver sample. This is a passthru driver.\r
+\r
+Author:\r
+\r
+Environment:\r
+\r
+\r
+Revision History:\r
+\r
+\r
+--*/\r
+\r
+\r
+#include "precomp.h"\r
+#pragma hdrstop\r
+\r
+#pragma NDIS_INIT_FUNCTION(DriverEntry)\r
+\r
+NDIS_HANDLE ProtHandle = NULL;\r
+NDIS_HANDLE DriverHandle = NULL;\r
+NDIS_MEDIUM MediumArray[4] =\r
+ {\r
+ NdisMedium802_3, // Ethernet\r
+ NdisMedium802_5, // Token-ring\r
+ NdisMediumFddi, // Fddi\r
+ NdisMediumWan // NDISWAN\r
+ };\r
+\r
+NDIS_SPIN_LOCK GlobalLock;\r
+\r
+PADAPT pAdaptList = NULL;\r
+LONG MiniportCount = 0;\r
+\r
+NDIS_HANDLE NdisWrapperHandle;\r
+\r
+//\r
+// To support ioctls from user-mode:\r
+//\r
+\r
+#define LINKNAME_STRING L"\\DosDevices\\Passthru"\r
+#define NTDEVICE_STRING L"\\Device\\Passthru"\r
+\r
+NDIS_HANDLE NdisDeviceHandle = NULL;\r
+PDEVICE_OBJECT ControlDeviceObject = NULL;\r
+\r
+enum _DEVICE_STATE\r
+{\r
+ PS_DEVICE_STATE_READY = 0, // ready for create/delete\r
+ PS_DEVICE_STATE_CREATING, // create operation in progress\r
+ PS_DEVICE_STATE_DELETING // delete operation in progress\r
+} ControlDeviceState = PS_DEVICE_STATE_READY;\r
+\r
+\r
+\r
+NTSTATUS\r
+DriverEntry(\r
+ IN PDRIVER_OBJECT DriverObject,\r
+ IN PUNICODE_STRING RegistryPath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ First entry point to be called, when this driver is loaded.\r
+ Register with NDIS as an intermediate driver.\r
+\r
+Arguments:\r
+\r
+ DriverObject - pointer to the system's driver object structure\r
+ for this driver\r
+ \r
+ RegistryPath - system's registry path for this driver\r
+ \r
+Return Value:\r
+\r
+ STATUS_SUCCESS if all initialization is successful, STATUS_XXX\r
+ error code if not.\r
+\r
+--*/\r
+{\r
+ NDIS_STATUS Status;\r
+ NDIS_PROTOCOL_CHARACTERISTICS PChars;\r
+ NDIS_MINIPORT_CHARACTERISTICS MChars;\r
+ NDIS_STRING Name;\r
+\r
+ Status = NDIS_STATUS_SUCCESS;\r
+ NdisAllocateSpinLock(&GlobalLock);\r
+\r
+ NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);\r
+\r
+ do\r
+ {\r
+ //\r
+ // Register the miniport with NDIS. Note that it is the miniport\r
+ // which was started as a driver and not the protocol. Also the miniport\r
+ // must be registered prior to the protocol since the protocol's BindAdapter\r
+ // handler can be initiated anytime and when it is, it must be ready to\r
+ // start driver instances.\r
+ //\r
+\r
+ NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));\r
+\r
+ MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;\r
+ MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;\r
+\r
+ MChars.InitializeHandler = MPInitialize;\r
+ MChars.QueryInformationHandler = MPQueryInformation;\r
+ MChars.SetInformationHandler = MPSetInformation;\r
+ MChars.ResetHandler = NULL;\r
+ MChars.TransferDataHandler = MPTransferData;\r
+ MChars.HaltHandler = MPHalt;\r
+#ifdef NDIS51_MINIPORT\r
+ MChars.CancelSendPacketsHandler = MPCancelSendPackets;\r
+ MChars.PnPEventNotifyHandler = MPDevicePnPEvent;\r
+ MChars.AdapterShutdownHandler = MPAdapterShutdown;\r
+#endif // NDIS51_MINIPORT\r
+\r
+ //\r
+ // We will disable the check for hang timeout so we do not\r
+ // need a check for hang handler!\r
+ //\r
+ MChars.CheckForHangHandler = NULL;\r
+ MChars.ReturnPacketHandler = MPReturnPacket;\r
+\r
+ //\r
+ // Either the Send or the SendPackets handler should be specified.\r
+ // If SendPackets handler is specified, SendHandler is ignored\r
+ //\r
+ MChars.SendHandler = NULL; // MPSend;\r
+ MChars.SendPacketsHandler = MPSendPackets;\r
+\r
+ Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,\r
+ &MChars,\r
+ sizeof(MChars),\r
+ &DriverHandle);\r
+ if (Status != NDIS_STATUS_SUCCESS)\r
+ {\r
+ break;\r
+ }\r
+\r
+#ifndef WIN9X\r
+ NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);\r
+#endif\r
+\r
+ //\r
+ // Now register the protocol.\r
+ //\r
+ NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
+ PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;\r
+ PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;\r
+\r
+ //\r
+ // Make sure the protocol-name matches the service-name\r
+ // (from the INF) under which this protocol is installed.\r
+ // This is needed to ensure that NDIS can correctly determine\r
+ // the binding and call us to bind to miniports below.\r
+ //\r
+ NdisInitUnicodeString(&Name, L"Passthru"); // Protocol name\r
+ PChars.Name = Name;\r
+ PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;\r
+ PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;\r
+ PChars.SendCompleteHandler = PtSendComplete;\r
+ PChars.TransferDataCompleteHandler = PtTransferDataComplete;\r
+ \r
+ PChars.ResetCompleteHandler = PtResetComplete;\r
+ PChars.RequestCompleteHandler = PtRequestComplete;\r
+ PChars.ReceiveHandler = PtReceive;\r
+ PChars.ReceiveCompleteHandler = PtReceiveComplete;\r
+ PChars.StatusHandler = PtStatus;\r
+ PChars.StatusCompleteHandler = PtStatusComplete;\r
+ PChars.BindAdapterHandler = PtBindAdapter;\r
+ PChars.UnbindAdapterHandler = PtUnbindAdapter;\r
+ PChars.UnloadHandler = PtUnloadProtocol;\r
+\r
+ PChars.ReceivePacketHandler = PtReceivePacket;\r
+ PChars.PnPEventHandler= PtPNPHandler;\r
+\r
+ NdisRegisterProtocol(&Status,\r
+ &ProtHandle,\r
+ &PChars,\r
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
+\r
+ if (Status != NDIS_STATUS_SUCCESS)\r
+ {\r
+ NdisIMDeregisterLayeredMiniport(DriverHandle);\r
+ break;\r
+ }\r
+\r
+ NdisIMAssociateMiniport(DriverHandle, ProtHandle);\r
+ }\r
+ while (FALSE);\r
+\r
+ if (Status != NDIS_STATUS_SUCCESS)\r
+ {\r
+ NdisTerminateWrapper(NdisWrapperHandle, NULL);\r
+ }\r
+\r
+ return(Status);\r
+}\r
+\r
+\r
+NDIS_STATUS\r
+PtRegisterDevice(\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Register an ioctl interface - a device object to be used for this\r
+ purpose is created by NDIS when we call NdisMRegisterDevice.\r
+\r
+ This routine is called whenever a new miniport instance is\r
+ initialized. However, we only create one global device object,\r
+ when the first miniport instance is initialized. This routine\r
+ handles potential race conditions with PtDeregisterDevice via\r
+ the ControlDeviceState and MiniportCount variables.\r
+\r
+ NOTE: do not call this from DriverEntry; it will prevent the driver\r
+ from being unloaded (e.g. on uninstall).\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Return Value:\r
+\r
+ NDIS_STATUS_SUCCESS if we successfully register a device object.\r
+\r
+--*/\r
+{\r
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;\r
+ UNICODE_STRING DeviceName;\r
+ UNICODE_STRING DeviceLinkUnicodeString;\r
+ PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];\r
+\r
+ DBGPRINT(("==>PtRegisterDevice\n"));\r
+\r
+ NdisAcquireSpinLock(&GlobalLock);\r
+\r
+ ++MiniportCount;\r
+ \r
+ if (1 == MiniportCount)\r
+ {\r
+ ASSERT(ControlDeviceState != PS_DEVICE_STATE_CREATING);\r
+\r
+ //\r
+ // Another thread could be running PtDeregisterDevice on\r
+ // behalf of another miniport instance. If so, wait for\r
+ // it to exit.\r
+ //\r
+ while (ControlDeviceState != PS_DEVICE_STATE_READY)\r
+ {\r
+ NdisReleaseSpinLock(&GlobalLock);\r
+ NdisMSleep(1);\r
+ NdisAcquireSpinLock(&GlobalLock);\r
+ }\r
+\r
+ ControlDeviceState = PS_DEVICE_STATE_CREATING;\r
+\r
+ NdisReleaseSpinLock(&GlobalLock);\r
+\r
+ \r
+ NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));\r
+\r
+ DispatchTable[IRP_MJ_CREATE] = PtDispatch;\r
+ DispatchTable[IRP_MJ_CLEANUP] = PtDispatch;\r
+ DispatchTable[IRP_MJ_CLOSE] = PtDispatch;\r
+ DispatchTable[IRP_MJ_DEVICE_CONTROL] = PtDispatch;\r
+ \r
+\r
+ NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);\r
+ NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);\r
+\r
+ //\r
+ // Create a device object and register our dispatch handlers\r
+ //\r
+ \r
+ Status = NdisMRegisterDevice(\r
+ NdisWrapperHandle, \r
+ &DeviceName,\r
+ &DeviceLinkUnicodeString,\r
+ &DispatchTable[0],\r
+ &ControlDeviceObject,\r
+ &NdisDeviceHandle\r
+ );\r
+\r
+ NdisAcquireSpinLock(&GlobalLock);\r
+\r
+ ControlDeviceState = PS_DEVICE_STATE_READY;\r
+ }\r
+\r
+ NdisReleaseSpinLock(&GlobalLock);\r
+\r
+ DBGPRINT(("<==PtRegisterDevice: %x\n", Status));\r
+\r
+ return (Status);\r
+}\r
+\r
+\r
+NTSTATUS\r
+PtDispatch(\r
+ IN PDEVICE_OBJECT DeviceObject,\r
+ IN PIRP Irp\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Process IRPs sent to this device.\r
+\r
+Arguments:\r
+\r
+ DeviceObject - pointer to a device object\r
+ Irp - pointer to an I/O Request Packet\r
+\r
+Return Value:\r
+\r
+ NTSTATUS - STATUS_SUCCESS always - change this when adding\r
+ real code to handle ioctls.\r
+\r
+--*/\r
+{\r
+ PIO_STACK_LOCATION irpStack;\r
+ NTSTATUS status = STATUS_SUCCESS;\r
+\r
+ UNREFERENCED_PARAMETER(DeviceObject);\r
+ \r
+ DBGPRINT(("==>Pt Dispatch\n"));\r
+ irpStack = IoGetCurrentIrpStackLocation(Irp);\r
+ \r
+\r
+ switch (irpStack->MajorFunction)\r
+ {\r
+ case IRP_MJ_CREATE:\r
+ break;\r
+ \r
+ case IRP_MJ_CLEANUP:\r
+ break;\r
+ \r
+ case IRP_MJ_CLOSE:\r
+ break; \r
+ \r
+ case IRP_MJ_DEVICE_CONTROL:\r
+ //\r
+ // Add code here to handle ioctl commands sent to passthru.\r
+ //\r
+ break; \r
+ default:\r
+ break;\r
+ }\r
+\r
+ Irp->IoStatus.Status = status;\r
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+\r
+ DBGPRINT(("<== Pt Dispatch\n"));\r
+\r
+ return status;\r
+\r
+} \r
+\r
+\r
+NDIS_STATUS\r
+PtDeregisterDevice(\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Deregister the ioctl interface. This is called whenever a miniport\r
+ instance is halted. When the last miniport instance is halted, we\r
+ request NDIS to delete the device object\r
+\r
+Arguments:\r
+\r
+ NdisDeviceHandle - Handle returned by NdisMRegisterDevice\r
+\r
+Return Value:\r
+\r
+ NDIS_STATUS_SUCCESS if everything worked ok\r
+\r
+--*/\r
+{\r
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;\r
+\r
+ DBGPRINT(("==>PassthruDeregisterDevice\n"));\r
+\r
+ NdisAcquireSpinLock(&GlobalLock);\r
+\r
+ ASSERT(MiniportCount > 0);\r
+\r
+ --MiniportCount;\r
+ \r
+ if (0 == MiniportCount)\r
+ {\r
+ //\r
+ // All miniport instances have been halted. Deregister\r
+ // the control device.\r
+ //\r
+\r
+ ASSERT(ControlDeviceState == PS_DEVICE_STATE_READY);\r
+\r
+ //\r
+ // Block PtRegisterDevice() while we release the control\r
+ // device lock and deregister the device.\r
+ // \r
+ ControlDeviceState = PS_DEVICE_STATE_DELETING;\r
+\r
+ NdisReleaseSpinLock(&GlobalLock);\r
+\r
+ if (NdisDeviceHandle != NULL)\r
+ {\r
+ Status = NdisMDeregisterDevice(NdisDeviceHandle);\r
+ NdisDeviceHandle = NULL;\r
+ }\r
+\r
+ NdisAcquireSpinLock(&GlobalLock);\r
+ ControlDeviceState = PS_DEVICE_STATE_READY;\r
+ }\r
+\r
+ NdisReleaseSpinLock(&GlobalLock);\r
+\r
+ DBGPRINT(("<== PassthruDeregisterDevice: %x\n", Status));\r
+ return Status;\r
+ \r
+}\r
+\r
+VOID\r
+PtUnload(\r
+ IN PDRIVER_OBJECT DriverObject\r
+ )\r
+//\r
+// PassThru driver unload function\r
+//\r
+{\r
+ UNREFERENCED_PARAMETER(DriverObject);\r
+ \r
+ DBGPRINT(("PtUnload: entered\n"));\r
+ \r
+ PtUnloadProtocol();\r
+ \r
+ NdisIMDeregisterLayeredMiniport(DriverHandle);\r
+ \r
+ NdisFreeSpinLock(&GlobalLock);\r
+\r
+ DBGPRINT(("PtUnload: done!\n"));\r
+}\r
+\r