Sync with the new ipfw3 version.
[ipfw.git] / original_passthru / passthru.c
diff --git a/original_passthru/passthru.c b/original_passthru/passthru.c
new file mode 100644 (file)
index 0000000..f614f2a
--- /dev/null
@@ -0,0 +1,458 @@
+/*++\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