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