|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Module Name:
IOCTL.C
Abstract:
This modules contains functions to register/deregsiter a control- deviceobject for ioctl purposes and dispatch routine for handling ioctl requests from usermode.
Revision History:
Notes:
--*/
#if defined(IOCTL_INTERFACE)
#include "miniport.h"
#include "public.h"
//
// Simple Mutual Exclusion constructs used in preference to
// using KeXXX calls since we don't have Mutex calls in NDIS.
// These can only be called at passive IRQL.
//
typedef struct _NIC_MUTEX { ULONG Counter; ULONG ModuleAndLine; // useful for debugging
} NIC_MUTEX, *PNIC_MUTEX;
#define NIC_INIT_MUTEX(_pMutex) \
{ \ (_pMutex)->Counter = 0; \ (_pMutex)->ModuleAndLine = 0; \ }
#define NIC_ACQUIRE_MUTEX(_pMutex) \
{ \ while (NdisInterlockedIncrement((PLONG)&((_pMutex)->Counter)) != 1)\ { \ NdisInterlockedDecrement((PLONG)&((_pMutex)->Counter)); \ NdisMSleep(10000); \ } \ (_pMutex)->ModuleAndLine = ('I' << 16) | __LINE__;\ }
#define NIC_RELEASE_MUTEX(_pMutex) \
{ \ (_pMutex)->ModuleAndLine = 0; \ NdisInterlockedDecrement((PLONG)&(_pMutex)->Counter); \ }
#define LINKNAME_STRING L"\\DosDevices\\NETVMINI"
#define NTDEVICE_STRING L"\\Device\\NETVMINI"
//
// Global variables
//
NDIS_HANDLE NdisDeviceHandle = NULL; // From NdisMRegisterDevice
LONG MiniportCount = 0; // Total number of miniports in existance
PDEVICE_OBJECT ControlDeviceObject = NULL; // Device for IOCTLs
NIC_MUTEX ControlDeviceMutex; extern NDIS_HANDLE NdisWrapperHandle;
#pragma NDIS_PAGEABLE_FUNCTION(NICRegisterDevice)
#pragma NDIS_PAGEABLE_FUNCTION(NICDeregisterDevice)
#pragma NDIS_PAGEABLE_FUNCTION(NICDispatch)
NDIS_STATUS NICRegisterDevice( 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 NICDeregisterDevice via the ControlDeviceMutex.
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];
DEBUGP(MP_TRACE, ("==>NICRegisterDevice\n"));
NIC_ACQUIRE_MUTEX(&ControlDeviceMutex);
++MiniportCount; if (1 == MiniportCount) { NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH)); DispatchTable[IRP_MJ_CREATE] = NICDispatch; DispatchTable[IRP_MJ_CLEANUP] = NICDispatch; DispatchTable[IRP_MJ_CLOSE] = NICDispatch; DispatchTable[IRP_MJ_DEVICE_CONTROL] = NICDispatch;
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 ); }
NIC_RELEASE_MUTEX(&ControlDeviceMutex);
DEBUGP(MP_TRACE, ("<==NICRegisterDevice: %x\n", Status));
return (Status); }
NTSTATUS NICDispatch( 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; ULONG inlen; PVOID buffer;
irpStack = IoGetCurrentIrpStackLocation(Irp); DEBUGP(MP_TRACE, ("==>NICDispatch %d\n", irpStack->MajorFunction)); switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: break; case IRP_MJ_CLEANUP: break; case IRP_MJ_CLOSE: break; case IRP_MJ_DEVICE_CONTROL: {
buffer = Irp->AssociatedIrp.SystemBuffer; inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
//
// Add code here to handle ioctl commands.
//
case IOCTL_NETVMINI_READ_DATA: DEBUGP(MP_TRACE, ("Received Read IOCTL\n")); break; case IOCTL_NETVMINI_WRITE_DATA: DEBUGP(MP_TRACE, ("Received Write IOCTL\n")); break; default: status = STATUS_UNSUCCESSFUL; break; } break; } default: break; } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
DEBUGP(MP_TRACE, ("<== NIC Dispatch\n"));
return status;
}
NDIS_STATUS NICDeregisterDevice( 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;
DEBUGP(MP_TRACE, ("==>NICDeregisterDevice\n"));
NIC_ACQUIRE_MUTEX(&ControlDeviceMutex);
ASSERT(MiniportCount > 0);
--MiniportCount; if (0 == MiniportCount) { //
// All miniport instances have been halted.
// Deregister the control device.
//
if (NdisDeviceHandle != NULL) { Status = NdisMDeregisterDevice(NdisDeviceHandle); NdisDeviceHandle = NULL; } }
NIC_RELEASE_MUTEX(&ControlDeviceMutex);
DEBUGP(MP_TRACE, ("<== NICDeregisterDevice: %x\n", Status)); return Status; }
#endif
|