diff options
Diffstat (limited to 'datapath-windows/ovsext/OvsIoctl.c')
-rw-r--r-- | datapath-windows/ovsext/OvsIoctl.c | 758 |
1 files changed, 758 insertions, 0 deletions
diff --git a/datapath-windows/ovsext/OvsIoctl.c b/datapath-windows/ovsext/OvsIoctl.c new file mode 100644 index 000000000..893cbf744 --- /dev/null +++ b/datapath-windows/ovsext/OvsIoctl.c @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2014 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "precomp.h" +#include "OvsIoctl.h" +#include "OvsJhash.h" +#include "OvsSwitch.h" +#include "OvsVport.h" +#include "OvsEvent.h" +#include "OvsUser.h" +#include "OvsPacketIO.h" +#include "OvsNetProto.h" +#include "OvsFlow.h" +#include "OvsUser.h" + +#ifdef OVS_DBG_MOD +#undef OVS_DBG_MOD +#endif +#define OVS_DBG_MOD OVS_DBG_IOCTL +#include "OvsDebug.h" + +/* Handles to the device object for communication with userspace. */ +NDIS_HANDLE gOvsDeviceHandle; +PDEVICE_OBJECT gOvsDeviceObject; + +/* + * There seems to be a skew between the kernel's version of current time and + * the userspace's version of current time. The skew was seen to + * monotonically increase as well. + * + * In order to deal with the situation, we pass down the userspace's version + * of the timestamp to the kernel, and let the kernel calculate the delta. + */ +UINT64 ovsUserTimestampDelta; +UINT64 ovsTimeIncrementPerTick; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH OvsOpenCloseDevice; + +_Dispatch_type_(IRP_MJ_CLEANUP) +DRIVER_DISPATCH OvsCleanupDevice; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH OvsDeviceControl; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, OvsCreateDeviceObject) +#pragma alloc_text(PAGE, OvsOpenCloseDevice) +#pragma alloc_text(PAGE, OvsCleanupDevice) +#pragma alloc_text(PAGE, OvsDeviceControl) +#endif // ALLOC_PRAGMA + + +#define OVS_MAX_OPEN_INSTANCES 128 + +POVS_OPEN_INSTANCE ovsOpenInstanceArray[OVS_MAX_OPEN_INSTANCES]; +UINT32 ovsNumberOfOpenInstances; +extern POVS_SWITCH_CONTEXT gOvsSwitchContext; + +NDIS_SPIN_LOCK ovsCtrlLockObj; +NDIS_SPIN_LOCK ovsFlowLockObj; +PNDIS_SPIN_LOCK gOvsCtrlLock; +PNDIS_SPIN_LOCK ovsFlowLock; + +VOID +OvsInitIoctl() +{ + gOvsCtrlLock = &ovsCtrlLockObj; + ovsFlowLock = &ovsFlowLockObj; + NdisAllocateSpinLock(ovsFlowLock); + NdisAllocateSpinLock(gOvsCtrlLock); +} + +VOID +OvsCleanupIoctl() +{ + if (ovsFlowLock) { + NdisFreeSpinLock(ovsFlowLock); + NdisFreeSpinLock(gOvsCtrlLock); + gOvsCtrlLock = NULL; + gOvsCtrlLock = NULL; + } +} + +VOID +OvsInit() +{ + OvsInitIoctl(); + OvsInitEventQueue(); + OvsUserInit(); +} + +VOID +OvsCleanup() +{ + OvsCleanupEventQueue(); + OvsCleanupIoctl(); + OvsUserCleanup(); +} + +VOID +OvsAcquireCtrlLock() +{ + NdisAcquireSpinLock(gOvsCtrlLock); +} +VOID +OvsReleaseCtrlLock() +{ + NdisReleaseSpinLock(gOvsCtrlLock); +} + + +/* + * -------------------------------------------------------------------------- + * Creates the communication device between user and kernel, and also + * initializes the data associated data structures. + * -------------------------------------------------------------------------- + */ +NDIS_STATUS +OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + UNICODE_STRING deviceName; + UNICODE_STRING symbolicDeviceName; + PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; + NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttributes; + OVS_LOG_TRACE("ovsExtDriverHandle: %p", ovsExtDriverHandle); + + RtlZeroMemory(dispatchTable, + (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof (PDRIVER_DISPATCH)); + dispatchTable[IRP_MJ_CREATE] = OvsOpenCloseDevice; + dispatchTable[IRP_MJ_CLOSE] = OvsOpenCloseDevice; + dispatchTable[IRP_MJ_CLEANUP] = OvsCleanupDevice; + dispatchTable[IRP_MJ_DEVICE_CONTROL] = OvsDeviceControl; + + NdisInitUnicodeString(&deviceName, OVS_NT_DEVICE_NAME); + NdisInitUnicodeString(&symbolicDeviceName, OVS_DOS_DEVICE_NAME); + + RtlZeroMemory(&deviceAttributes, sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES)); + + OVS_INIT_OBJECT_HEADER(&deviceAttributes.Header, + NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES, + NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1, + sizeof (NDIS_DEVICE_OBJECT_ATTRIBUTES)); + + deviceAttributes.DeviceName = &deviceName; + deviceAttributes.SymbolicName = &symbolicDeviceName; + deviceAttributes.MajorFunctions = dispatchTable; + deviceAttributes.ExtensionSize = sizeof (OVS_DEVICE_EXTENSION); + + status = NdisRegisterDeviceEx(ovsExtDriverHandle, + &deviceAttributes, + &gOvsDeviceObject, + &gOvsDeviceHandle); + if (status != NDIS_STATUS_SUCCESS) { + POVS_DEVICE_EXTENSION ovsExt = + (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(gOvsDeviceObject); + ASSERT(gOvsDeviceObject != NULL); + ASSERT(gOvsDeviceHandle != NULL); + + if (ovsExt) { + ovsExt->numberOpenInstance = 0; + } + } else { + /* Initialize the associated data structures. */ + OvsInit(); + } + OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject); + return status; +} + + +VOID +OvsDeleteDeviceObject() +{ + if (gOvsDeviceHandle) { +#ifdef DBG + POVS_DEVICE_EXTENSION ovsExt = (POVS_DEVICE_EXTENSION) + NdisGetDeviceReservedExtension(gOvsDeviceObject); + if (ovsExt) { + ASSERT(ovsExt->numberOpenInstance == 0); + } +#endif + + ASSERT(gOvsDeviceObject); + NdisDeregisterDeviceEx(gOvsDeviceHandle); + gOvsDeviceHandle = NULL; + gOvsDeviceObject = NULL; + } + OvsCleanup(); +} + +POVS_OPEN_INSTANCE +OvsGetOpenInstance(PFILE_OBJECT fileObject, + UINT32 dpNo) +{ + POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext; + ASSERT(instance); + ASSERT(instance->fileObject == fileObject); + if (gOvsSwitchContext == NULL || + gOvsSwitchContext->dpNo != dpNo) { + return NULL; + } + return instance; +} + + +POVS_OPEN_INSTANCE +OvsFindOpenInstance(PFILE_OBJECT fileObject) +{ + UINT32 i, j; + for (i = 0, j = 0; i < OVS_MAX_OPEN_INSTANCES && + j < ovsNumberOfOpenInstances; i++) { + if (ovsOpenInstanceArray[i]) { + if (ovsOpenInstanceArray[i]->fileObject == fileObject) { + return ovsOpenInstanceArray[i]; + } + j++; + } + } + return NULL; +} + +NTSTATUS +OvsAddOpenInstance(PFILE_OBJECT fileObject) +{ + POVS_OPEN_INSTANCE instance = + (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE)); + UINT32 i; + + if (instance == NULL) { + return STATUS_NO_MEMORY; + } + OvsAcquireCtrlLock(); + ASSERT(OvsFindOpenInstance(fileObject) == NULL); + + if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) { + OvsReleaseCtrlLock(); + OvsFreeMemory(instance); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE)); + + for (i = 0; i < OVS_MAX_OPEN_INSTANCES; i++) { + if (ovsOpenInstanceArray[i] == NULL) { + ovsOpenInstanceArray[i] = instance; + instance->cookie = i; + break; + } + } + ASSERT(i < OVS_MAX_OPEN_INSTANCES); + instance->fileObject = fileObject; + ASSERT(fileObject->FsContext == NULL); + fileObject->FsContext = instance; + OvsReleaseCtrlLock(); + return STATUS_SUCCESS; +} + +static VOID +OvsCleanupOpenInstance(PFILE_OBJECT fileObject) +{ + POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext; + ASSERT(instance); + ASSERT(fileObject == instance->fileObject); + OvsCleanupEvent(instance); + OvsCleanupPacketQueue(instance); +} + +VOID +OvsRemoveOpenInstance(PFILE_OBJECT fileObject) +{ + POVS_OPEN_INSTANCE instance; + ASSERT(fileObject->FsContext); + instance = (POVS_OPEN_INSTANCE)fileObject->FsContext; + ASSERT(instance->cookie < OVS_MAX_OPEN_INSTANCES); + + OvsAcquireCtrlLock(); + fileObject->FsContext = NULL; + ASSERT(ovsOpenInstanceArray[instance->cookie] == instance); + ovsOpenInstanceArray[instance->cookie] = NULL; + OvsReleaseCtrlLock(); + ASSERT(instance->eventQueue == NULL); + ASSERT (instance->packetQueue == NULL); + OvsFreeMemory(instance); +} + +NTSTATUS +OvsCompleteIrpRequest(PIRP irp, + ULONG_PTR infoPtr, + NTSTATUS status) +{ + irp->IoStatus.Information = infoPtr; + irp->IoStatus.Status = status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return status; +} + + +NTSTATUS +OvsOpenCloseDevice(PDEVICE_OBJECT deviceObject, + PIRP irp) +{ + PIO_STACK_LOCATION irpSp; + NTSTATUS status = STATUS_SUCCESS; + PFILE_OBJECT fileObject; + POVS_DEVICE_EXTENSION ovsExt = + (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject); + + ASSERT(deviceObject == gOvsDeviceObject); + ASSERT(ovsExt != NULL); + + irpSp = IoGetCurrentIrpStackLocation(irp); + fileObject = irpSp->FileObject; + OVS_LOG_TRACE("DeviceObject: %p, fileObject:%p, instance: %u", + deviceObject, fileObject, + ovsExt->numberOpenInstance); + + switch (irpSp->MajorFunction) { + case IRP_MJ_CREATE: + status = OvsAddOpenInstance(fileObject); + if (STATUS_SUCCESS == status) { + InterlockedIncrement((LONG volatile *)&ovsExt->numberOpenInstance); + } + break; + case IRP_MJ_CLOSE: + ASSERT(ovsExt->numberOpenInstance > 0); + OvsRemoveOpenInstance(fileObject); + InterlockedDecrement((LONG volatile *)&ovsExt->numberOpenInstance); + break; + default: + ASSERT(0); + } + return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status); +} + +_Use_decl_annotations_ +NTSTATUS +OvsCleanupDevice(PDEVICE_OBJECT deviceObject, + PIRP irp) +{ + + PIO_STACK_LOCATION irpSp; + PFILE_OBJECT fileObject; + + NTSTATUS status = STATUS_SUCCESS; +#ifdef DBG + POVS_DEVICE_EXTENSION ovsExt = + (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject); + if (ovsExt) { + ASSERT(ovsExt->numberOpenInstance > 0); + } +#else + UNREFERENCED_PARAMETER(deviceObject); +#endif + ASSERT(deviceObject == gOvsDeviceObject); + irpSp = IoGetCurrentIrpStackLocation(irp); + fileObject = irpSp->FileObject; + + ASSERT(irpSp->MajorFunction == IRP_MJ_CLEANUP); + + OvsCleanupOpenInstance(fileObject); + + return OvsCompleteIrpRequest(irp, (ULONG_PTR)0, status); +} + +/* + *---------------------------------------------------------------------------- + * OvsGetVersionIoctl -- + * + * On entry None + * On exit Driver version + * + * Result: + * STATUS_SUCCESS + * STATUS_BUFFER_TOO_SMALL + *---------------------------------------------------------------------------- + */ +NTSTATUS +OvsGetVersionIoctl(PVOID outputBuffer, + uint32 outputLength, + uint32 *replyLen) +{ + POVS_VERSION driverOut = (POVS_VERSION)outputBuffer; + + if (outputLength < sizeof (*driverOut)) { + return STATUS_BUFFER_TOO_SMALL; + } + *replyLen = sizeof (*driverOut); + driverOut->mjrDrvVer = OVS_DRIVER_MAJOR_VER; + driverOut->mnrDrvVer = OVS_DRIVER_MINOR_VER; + + return STATUS_SUCCESS; +} + + +/* + *---------------------------------------------------------------------------- + * OvsDpDumpIoctl -- + * Get All Datapath. For now, we only support one datapath. + * + * Result: + * STATUS_SUCCESS + * STATUS_BUFFER_TOO_SMALL + *---------------------------------------------------------------------------- + */ +NTSTATUS +OvsDpDumpIoctl(PVOID outputBuffer, + UINT32 outputLength, + UINT32 *replyLen) +{ + *replyLen = sizeof (UINT32); + if (outputLength < sizeof (UINT32)) { + return STATUS_BUFFER_TOO_SMALL; + } + OvsAcquireCtrlLock(); + if (gOvsSwitchContext) { + *(UINT32 *)outputBuffer = gOvsSwitchContext->dpNo; + } else { + *replyLen = 0; + } + OvsReleaseCtrlLock(); + + return STATUS_SUCCESS; +} + + +/* + *---------------------------------------------------------------------------- + * OvsDpGetIoctl -- + * Given dpNo, get all datapath info as defined in OVS_DP_INFO. + * + * Result: + * STATUS_SUCCESS + * STATUS_BUFFER_TOO_SMALL + * STATUS_INVALID_PARAMETER + *---------------------------------------------------------------------------- + */ +NTSTATUS +OvsDpGetIoctl(PVOID inputBuffer, + UINT32 inputLength, + PVOID outputBuffer, + UINT32 outputLength, + UINT32 *replyLen) +{ + UINT32 dpNo; + POVS_DP_INFO info; + OVS_DATAPATH *datapath; + + if (inputLength < sizeof (UINT32)) { + return STATUS_INVALID_PARAMETER; + } + + if (outputLength < sizeof (OVS_DP_INFO)) { + *replyLen = sizeof (OVS_DP_INFO); + return STATUS_BUFFER_TOO_SMALL; + } + + dpNo = *(UINT32 *)inputBuffer; + OvsAcquireCtrlLock(); + if (gOvsSwitchContext == NULL || + gOvsSwitchContext->dpNo != dpNo) { + OvsReleaseCtrlLock(); + return STATUS_INVALID_PARAMETER; + } + *replyLen = sizeof (OVS_DP_INFO); + RtlZeroMemory(outputBuffer, sizeof (OVS_DP_INFO)); + info = (POVS_DP_INFO)outputBuffer; + RtlCopyMemory(info->name, "ovs-system", sizeof ("ovs-system")); + datapath = &gOvsSwitchContext->datapath; + info->nMissed = datapath->misses; + info->nHit = datapath->hits; + info->nLost = datapath->lost; + info->nFlows = datapath->nFlows; + OvsReleaseCtrlLock(); + return STATUS_SUCCESS; +} + +NTSTATUS +OvsDeviceControl(PDEVICE_OBJECT deviceObject, + PIRP irp) +{ + + PIO_STACK_LOCATION irpSp; + NTSTATUS status = STATUS_SUCCESS; + PFILE_OBJECT fileObject; + PVOID inputBuffer; + PVOID outputBuffer; + UINT32 inputBufferLen, outputBufferLen, mdlBufferLen; + UINT32 code, replyLen = 0; +#ifdef DBG + POVS_DEVICE_EXTENSION ovsExt = + (POVS_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(deviceObject); + ASSERT(deviceObject == gOvsDeviceObject); + ASSERT(ovsExt); + ASSERT(ovsExt->numberOpenInstance > 0); +#else + UNREFERENCED_PARAMETER(deviceObject); +#endif + + irpSp = IoGetCurrentIrpStackLocation(irp); + + + ASSERT(irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL); + ASSERT(irpSp->FileObject != NULL); + + fileObject = irpSp->FileObject; + code = irpSp->Parameters.DeviceIoControl.IoControlCode; + inputBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; + outputBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + /* + * In case of an IRP with METHOD_IN_DIRECT or METHOD_OUT_DIRECT, the size + * of the MDL is stored in Parameters.DeviceIoControl.OutputBufferLength. + */ + mdlBufferLen = outputBufferLen; + outputBuffer = inputBuffer = irp->AssociatedIrp.SystemBuffer; + + switch(code) { + case OVS_IOCTL_VERSION_GET: + status = OvsGetVersionIoctl(outputBuffer, outputBufferLen, + &replyLen); + break; + case OVS_IOCTL_DP_DUMP: + status = OvsDpDumpIoctl(outputBuffer, outputBufferLen, &replyLen); + break; + case OVS_IOCTL_DP_GET: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + status = OvsDpGetIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, &replyLen); + } + break; + case OVS_IOCTL_DP_SET: + status = STATUS_NOT_IMPLEMENTED; + break; + case OVS_IOCTL_VPORT_DUMP: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsDumpVportIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_VPORT_GET: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsGetVportIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_VPORT_SET: + status = STATUS_NOT_IMPLEMENTED; + break; + case OVS_IOCTL_VPORT_ADD: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsAddVportIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_VPORT_DEL: + status = OvsDelVportIoctl(inputBuffer, inputBufferLen, + &replyLen); + break; + case OVS_IOCTL_VPORT_EXT_INFO: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsGetExtInfoIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + OVS_LOG_INFO("ExtInfo: fail to get outputBuffer address"); + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_FLOW_DUMP: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsDumpFlowIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_FLOW_GET: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsGetFlowIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_FLOW_PUT: + // XXX: This is not really working - mapping the input buffer + // XXX: inputBufferLen = mdlBufferLen; + // inputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + // NormalPagePriority); + status = OvsPutFlowIoctl(inputBuffer, inputBufferLen, + outputBuffer, outputBufferLen, + &replyLen); + break; + case OVS_IOCTL_FLOW_FLUSH: + status = OvsFlushFlowIoctl(inputBuffer, inputBufferLen); + break; + case OVS_IOCTL_QOS_QUEUE_DUMP: + case OVS_IOCTL_QOS_QUEUE_GET: + case OVS_IOCTL_QOS_QUEUE_SET: + status = STATUS_NOT_IMPLEMENTED; + break; + case OVS_IOCTL_DATAPATH_SUBSCRIBE: + status = OvsSubscribeDpIoctl(fileObject, inputBuffer, + inputBufferLen); + break; + case OVS_IOCTL_DATAPATH_READ: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer) { + status = OvsReadDpIoctl(fileObject, outputBuffer, + outputBufferLen, &replyLen); + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + case OVS_IOCTL_DATAPATH_OPERATE: + status = STATUS_NOT_IMPLEMENTED; + break; + case OVS_IOCTL_DATAPATH_EXECUTE: + // XXX: need to make the input direct + status = OvsExecuteDpIoctl(inputBuffer, inputBufferLen, + outputBufferLen); + break; + case OVS_IOCTL_DATAPATH_PURGE: + status = OvsPurgeDpIoctl(fileObject); + break; + case OVS_IOCTL_DATAPATH_WAIT: + status = OvsWaitDpIoctl(irp, fileObject); + break; + case OVS_IOCTL_EVENT_SUBSCRIBE: + status = OvsSubscribeEventIoctl(fileObject, inputBuffer, + inputBufferLen); + break; + case OVS_IOCTL_EVENT_POLL: + if (irp->MdlAddress == NULL) { + status = STATUS_INVALID_PARAMETER; + break; + } + outputBuffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, + NormalPagePriority); + if (outputBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + status = OvsPollEventIoctl(fileObject, inputBuffer, + inputBufferLen, outputBuffer, + outputBufferLen, &replyLen); + } + break; + case OVS_IOCTL_EVENT_WAIT: + status = OvsWaitEventIoctl(irp, fileObject, + inputBuffer, inputBufferLen); + break; + case OVS_IOCTL_DP_TIMESTAMP_SET: + if (inputBufferLen != sizeof (ovsUserTimestampDelta)) { + status = STATUS_INFO_LENGTH_MISMATCH; + } else { + int64 currentUserTS = *(int64 *)inputBuffer; + LARGE_INTEGER tickCount; + + /* So many ticks since system booted. */ + KeQueryTickCount(&tickCount); + ovsUserTimestampDelta = currentUserTS - + (tickCount.QuadPart * ovsTimeIncrementPerTick); + status = STATUS_SUCCESS; + } + break; + default: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (status == STATUS_PENDING) { + return status; + } else { + /* + * When the system-address-space mapping that is returned by + * MmGetSystemAddressForMdlSafe is no longer needed, it must be + * released. + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff554559(v=vs.85).aspx + * + * We might have to release the MDL here. + */ + return OvsCompleteIrpRequest(irp, (ULONG_PTR)replyLen, status); + } +} |