static NTSTATUS NTAPI V4vDispatchWmi(PDEVICE_OBJECT fdo, PIRP irp) { NTSTATUS status; PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo); TraceVerbose(("====> '%s'.\n", __FUNCTION__)); // We don't support WMI, so just pass it on down the stack status = IoAcquireRemoveLock(&pde->removeLock, irp); if (!NT_SUCCESS(status)) { TraceError(("failed to acquire IO lock - error: 0x%x\n", status)); return V4vSimpleCompleteIrp(irp, status); } IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); IoReleaseRemoveLock(&pde->removeLock, irp); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
static VOID V4vStopDevice(PDEVICE_OBJECT fdo, PXENV4V_EXTENSION pde) { PIRP pendingIrp; XENV4V_QPEEK peek; // Go to the stopped state to prevent IO, stop the timer and // interrupt (ec). InterlockedExchange(&pde->state, XENV4V_DEV_STOPPED); V4vUninitializeEventChannel(fdo); KeCancelTimer(&pde->timer); peek.types = XENV4V_PEEK_STREAM; // process for stream types peek.ops = XENV4V_PEEK_SYN|XENV4V_PEEK_ACK; // all SYN/ACK ops peek.pfo = NULL; // not using file object search peek.dst.domain = DOMID_INVALID; // not using destination search peek.dst.port = V4V_PORT_NONE; pendingIrp = IoCsqRemoveNextIrp(&pde->csqObject, &peek); while (pendingIrp != NULL) { V4vSimpleCompleteIrp(pendingIrp, STATUS_CANCELLED); pendingIrp = IoCsqRemoveNextIrp(&pde->csqObject, &peek); } }
VOID V4vDoAccepts(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx) { NTSTATUS status; KLOCK_QUEUE_HANDLE lqh; PIO_STACK_LOCATION isl; PIRP nextIrp = NULL; XENV4V_QPEEK peek; ULONG ioControlCode; PVOID ioBuffer; struct v4v_addr *peer; ULONG size; XENV4V_CONTEXT *actx; XENV4V_SYN *sptr; V4V_ACCEPT_PRIVATE *priv; peek.types = XENV4V_PEEK_STREAM; // process for stream types peek.ops = XENV4V_PEEK_ACCEPT; // accept ops peek.pfo = ctx->pfoParent; // for a specific file object // Lock the SYN list state and process SYN entries. For each, // try to locate an accept IRP in the queue for this listener. KeAcquireInStackQueuedSpinLock(&ctx->u.listener.synLock, &lqh); do { if (ctx->u.listener.synCount == 0) { // No data so clear any events indicating pending accepts. KeClearEvent(ctx->kevReceive); break; // no more to read } // SYNs, any pending accepts? nextIrp = IoCsqRemoveNextIrp(&pde->csqObject, &peek); if (nextIrp == NULL) { // Nobody to accept it so tell the listener there are SYNs waiting. // Set the data ready event for clients who use it. KeSetEvent(ctx->kevReceive, EVENT_INCREMENT, FALSE); break; } // Now there is a SYN and an accept IRP to take it. isl = IoGetCurrentIrpStackLocation(nextIrp); ioControlCode = isl->Parameters.DeviceIoControl.IoControlCode; ioBuffer = nextIrp->AssociatedIrp.SystemBuffer; // Gather the private accept information size = V4vGetAcceptPrivate(ioControlCode, ioBuffer, &priv, &peer); // Get the stashed referenced context pointer for the new accepter #if defined(_WIN64) actx = (XENV4V_CONTEXT*)priv->q.a; #else actx = (XENV4V_CONTEXT*)priv->d.a; #endif // Pop the next in order from the head of the list ASSERT(ctx->u.listener.synHead != NULL); ASSERT(ctx->u.listener.synTail != NULL); sptr = ctx->u.listener.synHead; if (ctx->u.listener.synHead != ctx->u.listener.synTail) { // More than one on the list ctx->u.listener.synHead = sptr->next; } else { // Only one on the list, reset pointers ctx->u.listener.synHead = NULL; ctx->u.listener.synTail = NULL; } ctx->u.listener.synCount--; ASSERT(ctx->u.listener.synCount >= 0); // Finish the accept, clear the SYN entry and drop the ref count on the context actx->sdst = sptr->sdst; actx->connId = sptr->connId; (*peer) = sptr->sdst; RtlZeroMemory(sptr, sizeof(XENV4V_SYN)); V4vReleaseContext(pde, actx); InterlockedExchange(&actx->state, XENV4V_STATE_ACCEPTED); // Send the ACK to our peer status = V4vSendAcknowledge(pde, actx); if (!NT_SUCCESS(status)) { // Fail the IRP and go to the disconnected state for the new context V4vSimpleCompleteIrp(nextIrp, status); InterlockedExchange(&actx->state, XENV4V_STATE_DISCONNECTED); continue; } // Complete the IRP - this will finish the accept call. Set the IOCTL output // buffer to the size appropriate for the user mode caller (32b vs 64b). nextIrp->IoStatus.Information = size; nextIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(nextIrp, IO_NO_INCREMENT); } while (TRUE); KeReleaseInStackQueuedSpinLock(&lqh); }
static NTSTATUS NTAPI V4vDispatchPower(PDEVICE_OBJECT fdo, PIRP irp) { NTSTATUS status; PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo); PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp); TraceVerbose(("====> '%s'.\n", __FUNCTION__)); switch (isl->MinorFunction) { case IRP_MN_SET_POWER: if (isl->Parameters.Power.Type == SystemPowerState) { TraceNotice(("SET system power: %d %d\n", isl->Parameters.Power.State.SystemState, isl->Parameters.Power.ShutdownType)); // If we are transitioning from the working (S0) power state to a lower state, // disconnect the VIRQ. If we are resuming to the working power state, re-connect. if (isl->Parameters.Power.State.SystemState == PowerSystemWorking) { // When resuming from hibernation w/ multi-vCPUs, the pv drivers // may be initialized in parallel causing problems with xenbus being // initialized before we try to bind our VIRQ. Kick the job off to a // work item and wait for initialization there. if (pde->lastPoState == PowerSystemHibernate) { V4vStartDehibernateWorkItem(fdo); } else { (VOID)V4vInitializeEventChannel(fdo); } } else if (isl->Parameters.Power.State.SystemState >= PowerSystemSleeping1) { V4vUninitializeEventChannel(fdo); } // If the last state was S4, flush all connections if (pde->lastPoState == PowerSystemHibernate) { V4vDisconnectAllStreams(pde); } // Reset the last state to what we just saw pde->lastPoState = isl->Parameters.Power.State.SystemState; } else if (isl->Parameters.Power.Type == DevicePowerState) { TraceNotice(("SET device power: %d %d\n", isl->Parameters.Power.State.SystemState, isl->Parameters.Power.ShutdownType)); } break; case IRP_MN_QUERY_POWER: if (isl->Parameters.Power.Type == SystemPowerState) { TraceNotice(("QUERY system power: %d %d\n", isl->Parameters.Power.State.SystemState, isl->Parameters.Power.ShutdownType)); } else if (isl->Parameters.Power.Type == DevicePowerState) { TraceNotice(("QUERY device power: %d %d\n", isl->Parameters.Power.State.SystemState, isl->Parameters.Power.ShutdownType)); } break; }; status = IoAcquireRemoveLock(&pde->removeLock, irp); if (!NT_SUCCESS(status)) { TraceError(("failed to acquire IO lock - error: 0x%x\n", status)); PoStartNextPowerIrp(irp); // for xp and 2k3 return V4vSimpleCompleteIrp(irp, status); } PoStartNextPowerIrp(irp); // for xp and 2k3 IoSkipCurrentIrpStackLocation(irp); status = PoCallDriver(pde->ldo, irp); IoReleaseRemoveLock(&pde->removeLock, irp); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
static NTSTATUS NTAPI V4vDispatchPnP(PDEVICE_OBJECT fdo, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp); PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo); KEVENT kev; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); TraceVerbose((" =PnP= 0x%x\n", isl->MinorFunction)); status = IoAcquireRemoveLock(&pde->removeLock, irp); if (!NT_SUCCESS(status)) { TraceError(("failed to acquire IO lock - error: 0x%x\n", status)); return V4vSimpleCompleteIrp(irp, status); } switch (isl->MinorFunction) { case IRP_MN_START_DEVICE: KeInitializeEvent(&kev, NotificationEvent, FALSE); // Send the start down and wait for it to complete IoCopyCurrentIrpStackLocationToNext(irp); IoSetCompletionRoutine(irp, V4vStartDeviceIoCompletion, &kev, TRUE, TRUE, TRUE); status = IoCallDriver(pde->ldo, irp); if (status == STATUS_PENDING) { // Wait for everything underneath us to complete TraceVerbose(("Device start waiting for lower device.\n")); KeWaitForSingleObject(&kev, Executive, KernelMode, FALSE, NULL); TraceVerbose(("Device start wait finished.\n")); } status = irp->IoStatus.Status; if (!NT_SUCCESS(status)) { TraceError(("Failed to start lower drivers: %x.\n", status)); IoCompleteRequest(irp, IO_NO_INCREMENT); break; } status = STATUS_SUCCESS; // Connect our interrupt (ec). status = V4vInitializeEventChannel(fdo); if (NT_SUCCESS(status)) { InterlockedExchange(&pde->state, XENV4V_DEV_STARTED); } else { TraceError(("failed to initialize event channel - error: 0x%x\n", status)); } irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case IRP_MN_STOP_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Pass it down irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); break; case IRP_MN_REMOVE_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Cleanup anything here that locks for IO IoReleaseRemoveLockAndWait(&pde->removeLock, irp); // Pass it down first IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); // Then detach and cleanup our device xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CLOSED); IoDetachDevice(pde->ldo); ExDeleteNPagedLookasideList(&pde->destLookasideList); XmFreeMemory(pde->frontendPath); IoDeleteSymbolicLink(&pde->symbolicLink); IoDeleteDevice(fdo); InterlockedAnd(&g_deviceCreated, 0); return status; default: // Pass it down TraceVerbose(("IRP_MJ_PNP MinorFunction %d passed down\n", isl->MinorFunction)); IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); }; // Everybody but REMOVE IoReleaseRemoveLock(&pde->removeLock, irp); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }