Ejemplo n.º 1
0
/*************************************************************************
*
* Function: Ext2PassDownMultiReadWriteIRP()
*
* Description:
*	pass down multiple read IRPs as Associated IRPs
*
* Expected Interrupt Level (for execution) :
*
*  ?
*
* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error
*
*************************************************************************/
NTSTATUS NTAPI Ext2PassDownMultiReadWriteIRP( 
	PEXT2_IO_RUN			PtrIoRuns, 
	UINT					Count, 
	ULONG					TotalReadWriteLength,
	PtrExt2IrpContext		PtrIrpContext,
	PtrExt2FCB				PtrFCB,
	BOOLEAN					SynchronousIo)
{
	PIRP				PtrMasterIrp;
	PIRP				PtrAssociatedIrp;
    PIO_STACK_LOCATION	PtrIrpSp;
    PMDL				PtrMdl;
	PtrExt2VCB			PtrVCB;
	UINT				i;
	ULONG				BufferOffset;
	PEXT2_IO_CONTEXT	PtrIoContext = NULL;
	PKEVENT				PtrSyncEvent = NULL;
	ULONG				LogicalBlockSize;
	ULONG				ReadWriteLength;

	NTSTATUS RC = STATUS_SUCCESS;

	PtrVCB = PtrFCB->PtrVCB;
	PtrMasterIrp = PtrIrpContext->Irp;
	LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;

	try
	{
		if( !SynchronousIo )
		{
			IoMarkIrpPending( PtrIrpContext->Irp );
			//	We will be returning STATUS_PENDING...
		}

		if( !PtrMasterIrp->MdlAddress )
		{
			Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength );
		}

		if( SynchronousIo )
		{
			PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) )  );
			if ( !PtrSyncEvent )
			{
				RC = STATUS_INSUFFICIENT_RESOURCES;
				try_return();
			}
			KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
		}
		//
		//	Allocate and initialize a completion context
		//
		PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) )  );
		if ( !PtrIoContext )
		{
			RC = STATUS_INSUFFICIENT_RESOURCES;
			try_return();
		}

		RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) );
		PtrIoContext->Count = Count;
		PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT;
		PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT );
		PtrIoContext->PtrMasterIrp = PtrMasterIrp;
		PtrIoContext->PtrSyncEvent = PtrSyncEvent;
		PtrIoContext->ReadWriteLength = TotalReadWriteLength;

		

		for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength )
		{
			
			ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset;
			
			//
			//	Allocating an Associated IRP...
			//
			PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp,
					(CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) );
			PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp;
			ASSERT ( PtrAssociatedIrp );
			PtrMasterIrp->AssociatedIrp.IrpCount ++;
			
			//
			//	Allocating a Memory Descriptor List...
			//
			PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, //	Virtual Address
				ReadWriteLength,	FALSE, FALSE, PtrAssociatedIrp );
			
			//
			//	and building a partial MDL...
			//
			IoBuildPartialMdl( PtrMasterIrp->MdlAddress,
				PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength );

			//
			//	Create an Irp stack location for ourselves...
			//
			IoSetNextIrpStackLocation( PtrAssociatedIrp );
			PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp );

			//
			//  Setup the Stack location to describe our read.
			//
			PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
			if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
			{
				PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
					PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}
			else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
			{
				PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = 
					PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}

			//	PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
			//	PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock;


			//
			//	Setup a completion routine...
			//
			IoSetCompletionRoutine( PtrAssociatedIrp, 
						SynchronousIo ?	
						Ext2MultiSyncCompletionRoutine : 
						Ext2MultiAsyncCompletionRoutine,
						PtrIoContext, TRUE, TRUE, TRUE );

			//
			//	Initialise the next stack location for the driver below us to use...
			//
			PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp );
			PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
			if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
			{
				PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}
			else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
			{
				PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}

			//	PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
			//	PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
			//	 	PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
		}

		for( i = 0; i < Count; i++ ) {
                    // DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i);
                    IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp );
                }

		if( SynchronousIo )
		{
			//
			//	Synchronous IO 
			//	Wait for the IO to complete...
			//
			DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql());
			KeWaitForSingleObject( PtrSyncEvent,
				Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
                        DbgPrint("DEADLY WAIT DONE\n");
			try_return();
		}
		else
		{
			//	Asynchronous IO...
			RC = STATUS_PENDING;
			try_return();
		}
	
		try_exit:	NOTHING;
	}
	finally 
	{
		if( PtrSyncEvent )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrSyncEvent );
			ExFreePool( PtrSyncEvent );
		}
		if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
		{
			//
			//	This means we are getting out of 
			//	this function without doing a read
			//	due to an error, maybe...
			//
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrIoContext);
			ExFreePool( PtrIoContext );
		}
	}
	return(RC);
}
Ejemplo n.º 2
0
void * hax_map_user_pages(hax_memdesc_user *memdesc, uint64 uva_offset,
                          uint64 size, hax_kmap_user *kmap)
{
    ULONG base_size;
    uint64 uva_offset_low, uva_offset_high;
    uint64 base_uva, start_uva;
    PMDL pmdl;
    PVOID kva;

    if (!memdesc) {
        hax_error("%s: memdesc == NULL\n", __func__);
        return NULL;
    }
    if (!memdesc->pmdl) {
        hax_error("%s: memdesc->pmdl == NULL\n", __func__);
        return NULL;
    }
    if (!kmap) {
        hax_error("%s: kmap == NULL\n", __func__);
        return NULL;
    }

    // Size of the underlying UVA range
    base_size = MmGetMdlByteCount(memdesc->pmdl);
    // Align the lower bound of the UVA subrange to 4KB
    uva_offset_low = uva_offset & pgmask(PG_ORDER_4K);
    // Align the upper bound of the UVA subrange to 4KB
    uva_offset_high = (uva_offset + size + PAGE_SIZE_4K - 1) &
                      pgmask(PG_ORDER_4K);
    if (uva_offset_high > base_size) {
        hax_error("%s: Invalid UVA subrange: uva_offset=0x%llx, size=0x%llx,"
                  " base_size=0x%llx\n", __func__, uva_offset, size, base_size);
        return NULL;
    }

    // Start of the underlying UVA range
    base_uva = (uint64)MmGetMdlVirtualAddress(memdesc->pmdl);
    // Start of the UVA subrange
    start_uva = base_uva + uva_offset_low;
    // Recalculate the size of the UVA subrange
    size = uva_offset_high - uva_offset_low;
    // Create a new MDL for the UVA subrange
    pmdl = IoAllocateMdl((PVOID)start_uva, size, FALSE, FALSE, NULL);
    if (!pmdl) {
        hax_error("%s: Failed to create MDL for UVA subrange: start_uva=0x%llx,"
                  " size=0x%llx\n", __func__, start_uva, size);
        return NULL;
    }
    // Associate the new MDL with the existing MDL
    IoBuildPartialMdl(memdesc->pmdl, pmdl, (PVOID)start_uva, size);
    kva = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority);
    if (!kva) {
        hax_error("%s: Failed to create KVA mapping for UVA subrange:"
                  " start_uva=0x%llx, size=0x%llx\n", __func__, start_uva,
                  size);
        IoFreeMdl(pmdl);
        return NULL;
    }
    kmap->pmdl = pmdl;
    return kva;
}
Ejemplo n.º 3
0
/*++
Routine Description:

This is the completion routine for reads/writes
If the irp completes with success, we check if we
need to recirculate this irp for another stage of
transfer.

Arguments:

Context - Driver supplied context
Device - Device handle
Request - Request handle
Params - request completion params

Return Value:
None
--*/
VOID ReadWriteCompletion(IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context)
{
    PMDL                    requestMdl;
    WDFUSBPIPE              pipe;
    ULONG                   stageLength;
    NTSTATUS                status;
    PREQUEST_CONTEXT        rwContext;
    PURB                    urb;
    PCHAR                   operation;
    ULONG                   bytesReadWritten;

    UNREFERENCED_PARAMETER(Context);
    rwContext = GetRequestContext(Request);

    PSDrv_DbgPrint(3, ("ReadWriteCompletion - begins\n"));

    if (rwContext->Read)
	{
        operation = "Read";
    }
	else
	{
        operation = "Write";
    }

    pipe = (WDFUSBPIPE)Target;
    status = CompletionParams->IoStatus.Status;

    if (!NT_SUCCESS(status))
	{
        goto End;
    }

    urb = (PURB)WdfMemoryGetBuffer(rwContext->UrbMemory, NULL);
    bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    rwContext->Numxfer += bytesReadWritten;

    // If there is anything left to transfer.
    if (rwContext->Length == 0)
	{
        // this is the last transfer
        WdfRequestSetInformation(Request, rwContext->Numxfer);
        goto End;
    }

    // Start another transfer
    PSDrv_DbgPrint(3, ("Stage next %s transfer...\n", operation));

    if (rwContext->Length > MAX_TRANSFER_SIZE)
	{
        stageLength = MAX_TRANSFER_SIZE;
    }
    else
	{
        stageLength = rwContext->Length;
    }

    // Following call is required to free any mapping made on the partial MDL and reset internal MDL state.
    MmPrepareMdlForReuse(rwContext->Mdl);

    if (rwContext->Read)
	{
        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
            PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed! (Status = %x)\n", status));
            goto End;
        }
    }
	else
	{
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
            PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed! (Status =  %x)\n", status));
            goto End;
        }
    }

    IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID)rwContext->VirtualAddress, stageLength);

    // Reinitialize the urb
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

    rwContext->VirtualAddress += stageLength;
    rwContext->Length -= stageLength;

    // Format the request to send a URB to a USB pipe.
    status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL);
    if (!NT_SUCCESS(status))
	{
        PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }

    WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL);

    // Send the request asynchronously.
    if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS))
	{
        PSDrv_DbgPrint(1, ("WdfRequestSend for %s failed!\n", operation));
        status = WdfRequestGetStatus(Request);
        goto End;
    }

    // Else when the request completes, this completion routine will be called again.
    PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 1\n"));

    return;

End:
    // Dump the request context, complete the request and return.
	PSDrv_DbgPrint(3, ("rwContext->UrbMemory      = %p\n", rwContext->UrbMemory));
	PSDrv_DbgPrint(3, ("rwContext->Mdl            = %p\n", rwContext->Mdl));
	PSDrv_DbgPrint(3, ("rwContext->Length         = %d\n", rwContext->Length));
	PSDrv_DbgPrint(3, ("rwContext->Numxfer        = %d\n", rwContext->Numxfer));
	PSDrv_DbgPrint(3, ("rwContext->VirtualAddress = %p\n", rwContext->VirtualAddress));

    IoFreeMdl(rwContext->Mdl);

    PSDrv_DbgPrint(3, ("Bulk or Interrupt %s request has finished. (Status = %x)\n", operation, status));

    WdfRequestComplete(Request, status);

    PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 2\n"));

    return;
}
Ejemplo n.º 4
0
/*++
Routine Description:

This callback is invoked when the framework received  WdfRequestTypeRead or
WdfRequestTypeWrite request. This read/write is performed in stages of
MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the
request is circulated again, until the requested length of transfer is
performed.

Arguments:

Queue - Handle to the framework queue object that is associated
with the I/O request.

Request - Handle to a framework request object. This one represents
the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework.

Length - Length of the input/output buffer.

Return Value:

VOID
--*/
VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType)
{
    PMDL						newMdl = NULL;
	PMDL						requestMdl = NULL;
    PURB						urb = NULL;
    WDFMEMORY					urbMemory;
    ULONG						totalLength = Length;
    ULONG						stageLength = 0;
    ULONG						urbFlags = 0;
    NTSTATUS					status;
    ULONG_PTR					virtualAddress = 0;
    PREQUEST_CONTEXT			rwContext = NULL;
    PFILE_CONTEXT				fileContext = NULL;
    WDFUSBPIPE					pipe;
    WDF_USB_PIPE_INFORMATION	pipeInfo;
    WDF_OBJECT_ATTRIBUTES		objectAttribs;
    USBD_PIPE_HANDLE			usbdPipeHandle;
    PDEVICE_CONTEXT				deviceContext;
	WDF_REQUEST_SEND_OPTIONS	sendOptions;

    PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n"));

    // First validate input parameters.
    deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue));

    if (totalLength > deviceContext->MaximumTransferSize)
	{
        PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize));
        status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }

    if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite))
	{
        PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType));
        status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }

    // Get the pipe associate with this request.
    fileContext = GetFileContext(WdfRequestGetFileObject(Request));
    pipe = fileContext->Pipe;
    WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
    WdfUsbTargetPipeGetInformation(pipe, &pipeInfo);

    if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType))
	{
        PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType));
        status = STATUS_INVALID_DEVICE_REQUEST;
        goto Exit;
    }

    rwContext = GetRequestContext(Request);

    if(RequestType == WdfRequestTypeRead)
	{
        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
            PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status));
            goto Exit;
        }

        urbFlags |= USBD_TRANSFER_DIRECTION_IN;
        rwContext->Read = TRUE;
        PSDrv_DbgPrint(3, ("This is a read operation...\n"));
    }
	else
	{
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
			PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status));
            goto Exit;
        }

        urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
        rwContext->Read = FALSE;
        PSDrv_DbgPrint(3, ("This is a write operation...\n"));
    }


    urbFlags |= USBD_SHORT_TRANSFER_OK;

    virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl);

    // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage.
    if (totalLength > MAX_TRANSFER_SIZE)
	{
        stageLength = MAX_TRANSFER_SIZE;
    }
    else
	{
        stageLength = totalLength;
    }

    newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL);
    if (newMdl == NULL)
	{
        PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    // Map the portion of user-buffer described by an mdl to another mdl
    IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength);

    WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs);
    objectAttribs.ParentObject = Request;

    status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb);
    if (!NT_SUCCESS(status))
	{
        PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe);

    UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL);

    status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL);
    if (!NT_SUCCESS(status))
	{
        PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL);

    // Set REQUEST_CONTEXT parameters.
    rwContext->UrbMemory       = urbMemory;
    rwContext->Mdl             = newMdl;
    rwContext->Length          = totalLength - stageLength;
    rwContext->Numxfer         = 0;
    rwContext->VirtualAddress  = virtualAddress + stageLength;

	// Set the timeout
	if (fileContext->nTimeOut != 0)
	{
		WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT);
		WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut));

		PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut));

		if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions))
		{
			status = WdfRequestGetStatus(Request);
			ASSERT(!NT_SUCCESS(status));
		}
	}
	else
	{
		if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS))
		{
			status = WdfRequestGetStatus(Request);
			ASSERT(!NT_SUCCESS(status));
		}
	}

Exit:
    if (!NT_SUCCESS(status))
	{
        WdfRequestCompleteWithInformation(Request, status, 0);

        if (newMdl != NULL)
		{
            IoFreeMdl(newMdl);
        }
    }

    PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n"));

    return;
}
Ejemplo n.º 5
0
NTSTATUS
Ext2ReadWriteBlocks(
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN PEXT2_EXTENT         Chain,
    IN ULONG                Length
    )
{
    PIRP                Irp;
    PIRP                MasterIrp = IrpContext->Irp;
    PIO_STACK_LOCATION  IrpSp;
    PMDL                Mdl;
    PEXT2_RW_CONTEXT    pContext = NULL;
    PEXT2_EXTENT        Extent;
    KEVENT              Wait;
    NTSTATUS            Status = STATUS_SUCCESS;
    BOOLEAN             bMasterCompleted = FALSE;
    BOOLEAN             bBugCheck = FALSE;

    ASSERT(MasterIrp);

    __try {

        pContext = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_RW_CONTEXT), EXT2_RWC_MAGIC);

        if (!pContext) {
            DEBUG(DL_ERR, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            __leave;
        }

        INC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT));
        RtlZeroMemory(pContext, sizeof(EXT2_RW_CONTEXT));
        pContext->Wait = Ext2CanIWait();
        pContext->MasterIrp = MasterIrp;
        pContext->Length = Length;

        if (IrpContext->MajorFunction == IRP_MJ_WRITE) {
            SetFlag(pContext->Flags, EXT2_RW_CONTEXT_WRITE);
        }

        if (pContext->Wait) {

            KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE);

        } else if (IrpContext->Fcb->Identifier.Type == EXT2FCB) {

            if (IsFlagOn(MasterIrp->Flags, IRP_PAGING_IO)) {
                pContext->Resource = &IrpContext->Fcb->PagingIoResource;
            } else {
                pContext->Resource = &IrpContext->Fcb->MainResource;
            }

            pContext->FileObject = IrpContext->FileObject;
            pContext->ThreadId = ExGetCurrentResourceThread();
        }


        if (NULL == Chain->Next && 0 == Chain->Offset) {

            /* we get only 1 extent to dispatch, then don't bother allocating new irps */

            /* setup the Stack location to do a read from the disk driver. */
            IrpSp = IoGetNextIrpStackLocation(MasterIrp);
            IrpSp->MajorFunction = IrpContext->MajorFunction;
            IrpSp->Parameters.Read.Length = Chain->Length;
            IrpSp->Parameters.Read.ByteOffset.QuadPart = Chain->Lba;
            if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
                SetFlag(IrpSp->Flags, SL_WRITE_THROUGH);
            }
            if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
                SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
            }

            IoSetCompletionRoutine(
                    MasterIrp,
                    Ext2CanIWait() ?
                    Ext2ReadWriteBlockSyncCompletionRoutine :
                    Ext2ReadWriteBlockAsyncCompletionRoutine,
                    (PVOID) pContext,
                    TRUE,
                    TRUE,
                    TRUE );

            /* intialize context block */
            Chain->Irp = MasterIrp;
            pContext->Blocks = 1;

        } else {

            for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {

                Irp = IoMakeAssociatedIrp(
                          MasterIrp,
                          (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );

                if (!Irp) {
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    __leave;
                }

                Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
                                     Extent->Offset,
                                     Extent->Length,
                                     FALSE,
                                     FALSE,
                                     Irp );

                if (!Mdl)  {
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    __leave;
                }

                IoBuildPartialMdl( MasterIrp->MdlAddress,
                                   Mdl,
                                   (PCHAR)MasterIrp->UserBuffer +Extent->Offset,
                                   Extent->Length );

                IoSetNextIrpStackLocation(Irp);
                IrpSp = IoGetCurrentIrpStackLocation(Irp);

                IrpSp->MajorFunction = IrpContext->MajorFunction;
                IrpSp->Parameters.Read.Length = Extent->Length;
                IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba;

                IoSetCompletionRoutine(
                    Irp,
                    Ext2CanIWait() ?
                    Ext2ReadWriteBlockSyncCompletionRoutine :
                    Ext2ReadWriteBlockAsyncCompletionRoutine,
                    (PVOID) pContext,
                    TRUE,
                    TRUE,
                    TRUE );

                IrpSp = IoGetNextIrpStackLocation(Irp);

                IrpSp->MajorFunction = IrpContext->MajorFunction;
                IrpSp->Parameters.Read.Length =Extent->Length;
                IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba;

                /* set write through flag */
                if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
                    SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
                }

                /* set verify flag */
                if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
                    SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME);
                }

                Extent->Irp = Irp;
                pContext->Blocks += 1;
            }

            MasterIrp->AssociatedIrp.IrpCount = pContext->Blocks;
            if (Ext2CanIWait()) {
                MasterIrp->AssociatedIrp.IrpCount += 1;
            }
        }
        if (!Ext2CanIWait()) {
            /* mark MasterIrp pending */
            IoMarkIrpPending(pContext->MasterIrp);
        }

        bBugCheck = TRUE;

        for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
            Status = IoCallDriver ( Vcb->TargetDeviceObject,
                                    Extent->Irp);
            Extent->Irp = NULL;
        }

        if (Ext2CanIWait()) {
            KeWaitForSingleObject( &(pContext->Event),
                                   Executive, KernelMode, FALSE, NULL );
            KeClearEvent( &(pContext->Event) );
        } else {
            bMasterCompleted = TRUE;
        }

    } __finally {

        for (Extent = Chain; Extent != NULL; Extent = Extent->Next)  {
            if (Extent->Irp != NULL ) {
                if (Extent->Irp->MdlAddress != NULL) {
                    IoFreeMdl(Extent->Irp->MdlAddress );
                }
                IoFreeIrp(Extent->Irp);
            }
        }

        if (IrpContext->ExceptionInProgress) {

            if (bBugCheck) {
                Ext2BugCheck(EXT2_BUGCHK_BLOCK, 0, 0, 0);
            }

        } else {

            if (Ext2CanIWait()) {
                if (MasterIrp) {
                    Status = MasterIrp->IoStatus.Status;
                }
                if (pContext) {
                    Ext2FreePool(pContext, EXT2_RWC_MAGIC);
                    DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT));
                }
            } else {
                if (bMasterCompleted) {
                    IrpContext->Irp = NULL;
                    Status = STATUS_PENDING;
                }
            }
        }
    }

    return Status;
}
Ejemplo n.º 6
0
NTSTATUS
USBSTOR_SendRequest(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP OriginalRequest,
    IN UCHAR CommandLength,
    IN PUCHAR Command,
    IN ULONG TransferDataLength,
    IN PUCHAR TransferData,
    IN ULONG RetryCount)
{
    PIRP_CONTEXT Context;
    PPDO_DEVICE_EXTENSION PDODeviceExtension;
    PFDO_DEVICE_EXTENSION FDODeviceExtension;
    PIRP Irp;
    PUCHAR MdlVirtualAddress;

    //
    // first allocate irp context
    //
    Context = USBSTOR_AllocateIrpContext();
    if (!Context)
    {
        //
        // no memory
        //
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // get PDO device extension
    //
    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

    //
    // get FDO device extension
    //
    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;

    //
    // now build the cbw
    //
    USBSTOR_BuildCBW((ULONG)Context->cbw,
                     TransferDataLength,
                     PDODeviceExtension->LUN,
                     CommandLength,
                     Command,
                     Context->cbw);

    DPRINT("CBW %p\n", Context->cbw);
    DumpCBW((PUCHAR)Context->cbw);

    //
    // now initialize the urb
    //
    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                           FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
                                           Context->cbw,
                                           NULL,
                                           sizeof(CBW),
                                           USBD_TRANSFER_DIRECTION_OUT,
                                           NULL);

    //
    // initialize rest of context
    //
    Context->Irp = OriginalRequest;
    Context->TransferData = TransferData;
    Context->TransferDataLength = TransferDataLength;
    Context->FDODeviceExtension = FDODeviceExtension;
    Context->PDODeviceExtension = PDODeviceExtension;
    Context->RetryCount = RetryCount;

    //
    // is there transfer data
    //
    if (Context->TransferDataLength)
    {
        //
        // check if the original request already does have an mdl associated
        //
        if (OriginalRequest)
        {
            if ((OriginalRequest->MdlAddress != NULL) &&
                (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
            {
                //
                // Sanity check that the Mdl does describe the TransferData for read/write
                //
                if (CommandLength == UFI_READ_WRITE_CMD_LEN)
                {
                    MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);

                    //
                    // is there an offset
                    //
                    if (MdlVirtualAddress != Context->TransferData)
                    {
                        //
                        // lets build an mdl
                        //
                        Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
                        if (!Context->TransferBufferMDL)
                        {
                            //
                            // failed to allocate MDL
                            //
                            return STATUS_INSUFFICIENT_RESOURCES;
                        }

                        //
                        // now build the partial mdl
                        //
                        IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
                    }
                }

                if (!Context->TransferBufferMDL)
                {
                    //
                    // I/O paging request
                    //
                    Context->TransferBufferMDL = OriginalRequest->MdlAddress;
                }
            }
            else
            {
                //
                // allocate mdl for buffer, buffer must be allocated from NonPagedPool
                //
                Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
                if (!Context->TransferBufferMDL)
                {
                    //
                    // failed to allocate MDL
                    //
                    return STATUS_INSUFFICIENT_RESOURCES;
                }

                //
                // build mdl for nonpaged pool
                //
                MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
            }
        }
        else
        {
            //
            // allocate mdl for buffer, buffer must be allocated from NonPagedPool
            //
            Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
            if (!Context->TransferBufferMDL)
            {
                //
                // failed to allocate MDL
                //
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            //
            // build mdl for nonpaged pool
            //
            MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
        }
    }

    //
    // now allocate the request
    //
    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
    if (!Irp)
    {
        FreeItem(Context->cbw);
        FreeItem(Context);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    if (OriginalRequest)
    {
        //
        // mark orignal irp as pending
        //
        IoMarkIrpPending(OriginalRequest);
    }

    //
    // send request
    //
    USBSTOR_SendCBW(Context, Irp);

    //
    // done
    //
    return STATUS_PENDING;
}
Ejemplo n.º 7
0
VOID
ReadWriteBulkEndPoints(
    _In_ WDFQUEUE         Queue,
    _In_ WDFREQUEST       Request,
    _In_ ULONG            Length,
    _In_ WDF_REQUEST_TYPE RequestType
    )
/*++

Routine Description:

    This callback is invoked when the framework received  WdfRequestTypeRead or
    WdfRequestTypeWrite request. This read/write is performed in stages of
    maximum transfer size. Once a stage of transfer is complete, then the
    request is circulated again, until the requested length of transfer is
    performed.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.

    Request - Handle to a framework request object. This one represents
              the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework.

    Length - Length of the input/output buffer.

Return Value:

   VOID

--*/
{
    PMDL                    newMdl=NULL, requestMdl = NULL;
    PURB                    urb = NULL;
    WDFMEMORY               urbMemory;
    ULONG                   totalLength = Length;
    ULONG                   stageLength = 0;
    ULONG                   urbFlags = 0;
    NTSTATUS                status;
    ULONG_PTR               virtualAddress = 0;
    PREQUEST_CONTEXT        rwContext = NULL;
    PFILE_CONTEXT           fileContext = NULL;
    WDFUSBPIPE              pipe;
    WDF_USB_PIPE_INFORMATION   pipeInfo;
    WDF_OBJECT_ATTRIBUTES   objectAttribs;
    USBD_PIPE_HANDLE        usbdPipeHandle;
    PDEVICE_CONTEXT         deviceContext;
    ULONG                   maxTransferSize;
    PPIPE_CONTEXT           pipeContext;

    UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n"));

    //
    // First validate input parameters.
    //
    deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue));

    if (totalLength > deviceContext->MaximumTransferSize) {
        UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n"));
        status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }

    if ((RequestType != WdfRequestTypeRead) &&
        (RequestType != WdfRequestTypeWrite)) {
        UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n"));
        status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }

    //
    // Get the pipe associate with this request.
    //
    fileContext = GetFileContext(WdfRequestGetFileObject(Request));
    pipe = fileContext->Pipe;
    pipeContext = GetPipeContext(pipe);
    WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
    WdfUsbTargetPipeGetInformation(pipe, &pipeInfo);

    if ((WdfUsbPipeTypeBulk != pipeInfo.PipeType) &&
            (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) {
        UsbSamp_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n"));
        status = STATUS_INVALID_DEVICE_REQUEST;
        goto Exit;

    }

    rwContext = GetRequestContext(Request);

    if (RequestType == WdfRequestTypeRead) {

        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status));
            goto Exit;
        }

        urbFlags |= USBD_TRANSFER_DIRECTION_IN;
        rwContext->Read = TRUE;
        UsbSamp_DbgPrint(3, ("Read operation\n"));

    } 
    else {
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status));
            goto Exit;
        }

        urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
        rwContext->Read = FALSE;
        UsbSamp_DbgPrint(3, ("Write operation\n"));
    }

    urbFlags |= USBD_SHORT_TRANSFER_OK;
    virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl);

    //
    // The transfer request is for totalLength.
    // We can perform a max of maxTransfersize in each stage.
    //
    maxTransferSize = GetMaxTransferSize(pipe, deviceContext);

    if (totalLength > maxTransferSize) {
        stageLength = maxTransferSize;
    }
    else {
        stageLength = totalLength;
    }

    newMdl = IoAllocateMdl((PVOID) virtualAddress,
                           totalLength,
                           FALSE,
                           FALSE,
                           NULL);

    if (newMdl == NULL) {
        UsbSamp_DbgPrint(1, ("Failed to alloc mem for mdl\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    //
    // map the portion of user-buffer described by an mdl to another mdl
    //
    IoBuildPartialMdl(requestMdl,
                      newMdl,
                      (PVOID) virtualAddress,
                      stageLength);

    WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs);
    objectAttribs.ParentObject = Request;

    status = WdfUsbTargetDeviceCreateUrb(deviceContext->WdfUsbTargetDevice,
		                     &objectAttribs,
                             &urbMemory,
                             &urb);

    if (!NT_SUCCESS(status)) {
        UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateUrb failed %x\n", status));
        goto Exit;
    }

#if (NTDDI_VERSION >= NTDDI_WIN8)
    if(WdfUsbPipeTypeBulk == pipeInfo.PipeType &&
        pipeContext->StreamConfigured == TRUE) {
        //
        // For super speed bulk pipe with streams, we specify one of its associated 
        // usbd pipe handles to format an URB for sending or receiving data. 
        // The usbd pipe handle is returned by the HCD via sucessful open-streams request
        //
        usbdPipeHandle = GetStreamPipeHandleFromBulkPipe(pipe);
    }
    else {
        usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe);
    }
#else
    usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe);
#endif

    UsbBuildInterruptOrBulkTransferRequest(urb,
                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                           usbdPipeHandle,
                                           NULL,
                                           newMdl,
                                           stageLength,
                                           urbFlags,
                                           NULL);

    status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL  );
    if (!NT_SUCCESS(status)) {
        UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext);

    //
    // set REQUEST_CONTEXT  parameters.
    //
    rwContext->UrbMemory       = urbMemory;
    rwContext->Mdl             = newMdl;
    rwContext->Length          = totalLength - stageLength;
    rwContext->Numxfer         = 0;
    rwContext->VirtualAddress  = virtualAddress + stageLength;

    if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) {
        status = WdfRequestGetStatus(Request);
        NT_ASSERT(!NT_SUCCESS(status));
    }

Exit:
    if (!NT_SUCCESS(status)) {
        WdfRequestCompleteWithInformation(Request, status, 0);

        if (newMdl != NULL) {
            IoFreeMdl(newMdl);
        }
    }

    UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n"));

    return;
}
void AndroidUsbPipeFileObject::OnCommonReadWriteCompletion(
    WDFREQUEST request,
    PWDF_REQUEST_COMPLETION_PARAMS completion_params,
    AndroidUsbWdfRequestContext* context) {
  ASSERT_IRQL_LOW_OR_DISPATCH();

  NTSTATUS status = completion_params->IoStatus.Status;
  if (!NT_SUCCESS(status)){
    GoogleDbgPrint("\n========== Request completed with failure: %X", status);
    IoFreeMdl(context->mdl);
    // If this was IOCTL-originated write we must unlock and free
    // our transfer MDL.
    if (context->is_ioctl && !context->is_read) {
      MmUnlockPages(context->transfer_mdl);
      IoFreeMdl(context->transfer_mdl);
    }
    WdfRequestComplete(request, status);
    return;
  }

  // Get our URB buffer
  PURB urb
    = reinterpret_cast<PURB>(WdfMemoryGetBuffer(context->urb_mem, NULL));
  ASSERT(NULL != urb);

  // Lets see how much has been transfered and update our counters accordingly
  ULONG bytes_transfered =
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  // We expect writes to transfer entire packet
  ASSERT((bytes_transfered == context->transfer_size) || context->is_read);
  context->num_xfer += bytes_transfered;
  context->length -= bytes_transfered;

  // Is there anything left to transfer? Now, by the protocol we should
  // successfuly complete partial reads, instead of waiting on full set
  // of requested bytes being accumulated in the read buffer.
  if ((0 == context->length) || context->is_read) {
    status = STATUS_SUCCESS;

    // This was the last transfer
    if (context->is_ioctl && !context->is_read) {
      // For IOCTL-originated writes we have to return transfer size through
      // the IOCTL's output buffer.
      ULONG* ret_transfer =
        reinterpret_cast<ULONG*>(OutAddress(request, NULL));
      ASSERT(NULL != ret_transfer);
      if (NULL != ret_transfer)
        *ret_transfer = context->num_xfer;
      WdfRequestSetInformation(request, sizeof(ULONG));

      // We also must unlock / free transfer MDL
      MmUnlockPages(context->transfer_mdl);
      IoFreeMdl(context->transfer_mdl);
    } else {
      // For other requests we report transfer size through the request I/O
      // completion status.
      WdfRequestSetInformation(request, context->num_xfer);
    }
    IoFreeMdl(context->mdl);
    WdfRequestComplete(request, status);
    return;
  }

  // There are something left for the transfer. Prepare for it.
  // Required to free any mapping made on the partial MDL and
  // reset internal MDL state.
  MmPrepareMdlForReuse(context->mdl);

  // Update our virtual address
  context->virtual_address = 
    reinterpret_cast<char*>(context->virtual_address) + bytes_transfered;

  // Calculate size of this transfer
  ULONG stage_len =
    (context->length > GetTransferGranularity()) ? GetTransferGranularity() :
                                                   context->length;

  IoBuildPartialMdl(context->transfer_mdl,
                    context->mdl,
                    context->virtual_address,
                    stage_len);

  // Reinitialize the urb and context
  urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stage_len;
  context->transfer_size = stage_len;

  // Format the request to send a URB to a USB pipe.
  status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(),
                                               request,
                                               context->urb_mem,
                                               NULL);
  ASSERT(NT_SUCCESS(status));
  if (!NT_SUCCESS(status)) {
    if (context->is_ioctl && !context->is_read) {
      MmUnlockPages(context->transfer_mdl);
      IoFreeMdl(context->transfer_mdl);
    }
    IoFreeMdl(context->mdl);
    WdfRequestComplete(request, status);
    return;
  }

  // Reset the completion routine
  WdfRequestSetCompletionRoutine(request,
                                 CommonReadWriteCompletionEntry,
                                 this);

  // Send the request asynchronously.
  if (!WdfRequestSend(request, wdf_pipe_io_target(), WDF_NO_SEND_OPTIONS)) {
    if (context->is_ioctl && !context->is_read) {
      MmUnlockPages(context->transfer_mdl);
      IoFreeMdl(context->transfer_mdl);
    }
    status = WdfRequestGetStatus(request);
    IoFreeMdl(context->mdl);
    WdfRequestComplete(request, status);
  }
}
Ejemplo n.º 9
0
/*
 *  SubmitTransferPacket
 *
 *        Set up the IRP for the TRANSFER_PACKET submission and send it down.
 */
NTSTATUS SubmitTransferPacket(PTRANSFER_PACKET Pkt)
{
    PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
    PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
    PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
    BOOLEAN idleRequest = FALSE;
    PIO_STACK_LOCATION nextSp;

    ASSERT(Pkt->Irp->CurrentLocation == Pkt->Irp->StackCount+1);

    /*
     *  Attach the SRB to the IRP.
     *  The reused IRP's stack location has to be rewritten for each retry
     *  call because IoCompleteRequest clears the stack locations.
     */
    IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED);
    nextSp = IoGetNextIrpStackLocation(Pkt->Irp);
    nextSp->MajorFunction = IRP_MJ_SCSI;
    nextSp->Parameters.Scsi.Srb = &Pkt->Srb;
    Pkt->Srb.ScsiStatus = Pkt->Srb.SrbStatus = 0;
    Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
    if (Pkt->CompleteOriginalIrpWhenLastPacketCompletes){
        /*
         *  Only dereference the "original IRP"'s stack location
         *  if its a real client irp (as opposed to a static irp
         *  we're using just for result status for one of the non-IO scsi commands).
         *
         *  For read/write, propagate the storage-specific IRP stack location flags
         *  (e.g. SL_OVERRIDE_VERIFY_VOLUME, SL_WRITE_THROUGH).
         */
        PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
        nextSp->Flags = origCurSp->Flags;
    }

    //
    // If the request is not split, we can use the original IRP MDL.  If the
    // request needs to be split, we need to use a partial MDL.  The partial MDL
    // is needed because more than one driver might be mapping the same MDL
    // and this causes problems.
    //
    if (Pkt->UsePartialMdl == FALSE) {
        Pkt->Irp->MdlAddress = Pkt->OriginalIrp->MdlAddress;
    } else {
        IoBuildPartialMdl(Pkt->OriginalIrp->MdlAddress, Pkt->PartialMdl, Pkt->Srb.DataBuffer, Pkt->Srb.DataTransferLength);
        Pkt->Irp->MdlAddress = Pkt->PartialMdl;
    }

    DBGLOGSENDPACKET(Pkt);
    HISTORYLOGSENDPACKET(Pkt);

    //
    // Set the original irp here for SFIO.
    //
    Pkt->Srb.SrbExtension = (PVOID) (Pkt->OriginalIrp);

    //
    // No need to lock for IdlePrioritySupported, since it will
    // be modified only at initialization time.
    //
    if (fdoData->IdlePrioritySupported == TRUE) {
        idleRequest = ClasspIsIdleRequest(Pkt->OriginalIrp);
        if (idleRequest) {
            InterlockedIncrement(&fdoData->ActiveIdleIoCount);
        } else {
            InterlockedIncrement(&fdoData->ActiveIoCount);
        }
    }

    IoSetCompletionRoutine(Pkt->Irp, TransferPktComplete, Pkt, TRUE, TRUE, TRUE);
    return IoCallDriver(nextDevObj, Pkt->Irp);
}
Ejemplo n.º 10
0
VOID
UsbSamp_EvtReadWriteCompletion(
    _In_ WDFREQUEST                  Request,
    _In_ WDFIOTARGET                 Target,
    PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
    _In_ WDFCONTEXT                  Context
    )
/*++

Routine Description:

    This is the completion routine for reads/writes
    If the irp completes with success, we check if we
    need to recirculate this irp for another stage of
    transfer.

Arguments:

    Context - Driver supplied context
    Device - Device handle
    Request - Request handle
    Params - request completion params

Return Value:
    None

--*/
{
    PMDL                    requestMdl;
    WDFUSBPIPE              pipe;
    ULONG                   stageLength;
    NTSTATUS               status;
    PREQUEST_CONTEXT        rwContext;
    PURB                    urb;
    PCHAR                   operation;
    ULONG                   bytesReadWritten;
    ULONG                   maxTransferSize;
    PDEVICE_CONTEXT         deviceContext;

    rwContext = GetRequestContext(Request);
    deviceContext = Context;

    if (rwContext->Read) {
        operation = "Read";
    } 
    else {
        operation = "Write";
    }

    pipe = (WDFUSBPIPE) Target   ;
    status = CompletionParams->IoStatus.Status;

    if (!NT_SUCCESS(status)){
        //
        // Queue a workitem to reset the pipe because the completion could be
        // running at DISPATCH_LEVEL.
        //
        QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe);
        goto End;
    }

    urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL);
    bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    rwContext->Numxfer += bytesReadWritten;

    //
    // If there is anything left to transfer.
    //
    if (rwContext->Length == 0) {
        //
        // this is the last transfer
        //
        WdfRequestSetInformation(Request, rwContext->Numxfer);
        goto End;
    }

    //
    // Start another transfer
    //
    UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation));

    //
    // The transfer request is for totalLength. 
    // We can perform a max of maxTransfersize in each stage.
    //
    maxTransferSize = GetMaxTransferSize(pipe, deviceContext);

    if (rwContext->Length > maxTransferSize) {
        stageLength = maxTransferSize;
    }
    else {
        stageLength = rwContext->Length;
    }

    //
    // Following call is required to free any mapping made on the partial MDL
    // and reset internal MDL state.
    //
    MmPrepareMdlForReuse(rwContext->Mdl);

    if (rwContext->Read) {
        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status));
            goto End;
        }
    } 
    else {
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed %x\n", status));
            goto End;
        }
    }

    IoBuildPartialMdl(requestMdl,
                      rwContext->Mdl,
                      (PVOID) rwContext->VirtualAddress,
                      stageLength);

    //
    // reinitialize the urb
    //
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

    rwContext->VirtualAddress += stageLength;
    rwContext->Length -= stageLength;

    //
    // Format the request to send a URB to a USB pipe.
    //
    status = WdfUsbTargetPipeFormatRequestForUrb(pipe,
                                Request,
                                rwContext->UrbMemory,
                                NULL);
    if (!NT_SUCCESS(status)) {
        UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }

    WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext);

    //
    // Send the request asynchronously.
    //
    if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) {
        UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation));
        status = WdfRequestGetStatus(Request);
        goto End;
    }

    //
    // Else when the request completes, this completion routine will be
    // called again.
    //
    return;

End:
    //
    // We are here because the request failed or some other call failed.
    // Dump the request context, complete the request and return.
    //
    DbgPrintRWContext(rwContext);

    IoFreeMdl(rwContext->Mdl);

    UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n",
                                                    operation, status));

    WdfRequestComplete(Request, status);

    return;
}
Ejemplo n.º 11
0
static VOID UsbChief_ReadEndPoint(IN WDFQUEUE Queue, IN WDFREQUEST Request,
			   IN ULONG totalLength)
{
	PMDL                    newMdl=NULL, requestMdl = NULL;
	PURB                    urb = NULL;
	WDFMEMORY               urbMemory;
	ULONG                   stageLength = 0;
	NTSTATUS                status;
	ULONG_PTR               virtualAddress = 0;
	PREQUEST_CONTEXT        rwContext = NULL;
	PFILE_CONTEXT           fileContext = NULL;
	WDFUSBPIPE              pipe;
	WDF_USB_PIPE_INFORMATION   pipeInfo;
	WDF_OBJECT_ATTRIBUTES   objectAttribs;
	USBD_PIPE_HANDLE        usbdPipeHandle;
	PDEVICE_CONTEXT         deviceContext;

	UsbChief_DbgPrint(DEBUG_RW, ("UsbChief_DispatchReadWrite - begins\n"));

	deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue));
	fileContext = GetFileContext(WdfRequestGetFileObject(Request));
	pipe = fileContext->Pipe;

	WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
	WdfUsbTargetPipeGetInformation(pipe, &pipeInfo);

	rwContext = GetRequestContext(Request);

	status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
	if(!NT_SUCCESS(status)){
		UsbChief_DbgPrint(0, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status));
		goto Exit;
	}
	virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl);

	if (totalLength > MAX_TRANSFER_SIZE)
		stageLength = MAX_TRANSFER_SIZE;
	else
		stageLength = totalLength;

	newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength,
			       FALSE, FALSE, NULL);

	if (!newMdl) {
		UsbChief_DbgPrint(0, ("Failed to alloc mem for mdl\n"));
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto Exit;
	}

	IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress,
			  stageLength);

	WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs);
	objectAttribs.ParentObject = Request;

	status = WdfMemoryCreate(&objectAttribs,
				 NonPagedPool,
				 POOL_TAG,
				 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
				 &urbMemory,
				 (PVOID*) &urb);

	if (!NT_SUCCESS(status)) {
		UsbChief_DbgPrint(0, ("Failed to alloc mem for urb\n"));
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto Exit;
	}

	usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe);

	UsbBuildInterruptOrBulkTransferRequest(urb,
					       sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
					       usbdPipeHandle,
					       NULL,
					       newMdl,
					       stageLength,
					       USBD_TRANSFER_DIRECTION_IN |
					       USBD_SHORT_TRANSFER_OK,
					       NULL);

	status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL  );
	if (!NT_SUCCESS(status)) {
		UsbChief_DbgPrint(0, ("Failed to format requset for urb\n"));
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto Exit;
	}
	WdfRequestSetCompletionRoutine(Request, UsbChief_ReadCompletion, NULL);

	rwContext->UrbMemory       = urbMemory;
	rwContext->Mdl             = newMdl;
	rwContext->Length          = totalLength - stageLength;
	rwContext->Numxfer         = 0;
	rwContext->VirtualAddress  = virtualAddress + stageLength;

	if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) {
		status = WdfRequestGetStatus(Request);
		ASSERT(!NT_SUCCESS(status));
	}

Exit:
	if (!NT_SUCCESS(status)) {
		WdfRequestCompleteWithInformation(Request, status, 0);

		if (newMdl != NULL) {
			IoFreeMdl(newMdl);
		}
	}
}
Ejemplo n.º 12
0
static VOID UsbChief_ReadCompletion(IN WDFREQUEST Request, IN WDFIOTARGET Target,
			     PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
			     IN WDFCONTEXT Context)
{
	PMDL requestMdl;
	WDFUSBPIPE pipe;
	ULONG stageLength;
	NTSTATUS status;
	PREQUEST_CONTEXT rwContext;
	PURB urb;
	ULONG bytesRead;

	UNREFERENCED_PARAMETER(Context);
	rwContext = GetRequestContext(Request);

	pipe = (WDFUSBPIPE)Target;
	status = CompletionParams->IoStatus.Status;

	if (!NT_SUCCESS(status)){
		UsbChief_QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe);
		goto End;
	}

	urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL);
	bytesRead = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
	rwContext->Numxfer += bytesRead;

	if (rwContext->Length == 0) {
		WdfRequestSetInformation(Request, rwContext->Numxfer);
		goto End;
	}

	if (rwContext->Length > MAX_TRANSFER_SIZE)
		stageLength = MAX_TRANSFER_SIZE;
	else
		stageLength = rwContext->Length;

	UsbChief_DbgPrint(DEBUG_RW, ("Stage next Read transfer... %d bytes remaing\n", rwContext->Length));
	MmPrepareMdlForReuse(rwContext->Mdl);

	status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
	if(!NT_SUCCESS(status)){
		UsbChief_DbgPrint(0, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status));
		goto End;
	}

	IoBuildPartialMdl(requestMdl, rwContext->Mdl,
			  (PVOID) rwContext->VirtualAddress, stageLength);

	urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

	rwContext->VirtualAddress += stageLength;
	rwContext->Length -= stageLength;

	status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request,
						     rwContext->UrbMemory, NULL);
	if (!NT_SUCCESS(status)) {
		UsbChief_DbgPrint(0, ("Failed to format requset for urb\n"));
		status = STATUS_INSUFFICIENT_RESOURCES;
		goto End;
	}

	WdfRequestSetCompletionRoutine(Request, UsbChief_ReadCompletion, NULL);

	if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) {
		UsbChief_DbgPrint(0, ("WdfRequestSend for Read failed\n"));
		status = WdfRequestGetStatus(Request);
		goto End;
	}
	return;

End:
	IoFreeMdl(rwContext->Mdl);

	UsbChief_DbgPrint(DEBUG_RW, ("Read request completed with status 0x%x\n", status));
	WdfRequestComplete(Request, status);
}
Ejemplo n.º 13
0
NTSTATUS
AWEAllocMapPage(IN POBJECT_CONTEXT Context,
		IN LONGLONG Offset)
{
  LONGLONG page_base = AWEAllocGetPageBaseFromAbsOffset(Offset);
  LONGLONG page_base_within_block;
  ULONG size_to_map = ALLOC_PAGE_SIZE;
  PBLOCK_DESCRIPTOR block;
  NTSTATUS status;

  KdPrint2(("AWEAlloc: MapPage request Offset=%#I64x BaseAddress=%#I64x.\n",
	    Offset,
	    page_base));

  if ((Context->CurrentPageBase == page_base) &
      (Context->CurrentMdl != NULL) &
      (Context->CurrentPtr != NULL))
    {
      KdPrint2(("AWEAlloc: MapPage: Page already mapped.\n"));
      return STATUS_SUCCESS;
    }

  // Find block that contains this page
  for (block = Context->FirstBlock;
       block != NULL;
       block = block->NextBlock)
    if (block->Offset <= page_base)
      break;

  if (block == NULL)
    {
      DbgPrint("AWEAlloc: MapPage: Cannot find blk for BaseAddress=%#I64x.\n",
	       page_base);

      return STATUS_DRIVER_INTERNAL_ERROR;
    }

  page_base_within_block = page_base - block->Offset;

  KdPrint2(("AWEAlloc: MapPage found blk Offset=%#I64x BaseAddress=%#I64x.\n",
	    block->Offset,
	    page_base_within_block));

  status = AWEAllocTryAcquireProtection(Context, TRUE);
  if (!NT_SUCCESS(status))
    {
      DbgPrint("AWEAlloc: Block table busy.\n");
      return status;
    }

  Context->CurrentPtr = NULL;
  Context->CurrentPageBase = (ULONG_PTR)-1;

  try
    {
      try
	{
	  if (Context->CurrentMdl != NULL)
	    IoFreeMdl(Context->CurrentMdl);

	  Context->CurrentMdl = NULL;

	  Context->CurrentMdl =
	    IoAllocateMdl(MmGetMdlVirtualAddress(block->Mdl),
			  size_to_map,
			  FALSE,
			  FALSE,
			  NULL);

	  if (Context->CurrentMdl == NULL)
	    {
	      DbgPrint("AWEAlloc: IoAllocateMdl() FAILED.\n");
	      return STATUS_INSUFFICIENT_RESOURCES;
	    }

	  if ((MmGetMdlByteCount(block->Mdl) - page_base_within_block) <
	      size_to_map)
	    {
	      KdPrint
		(("AWEAlloc: Incomplete page size! Shrinking page size.\n"));
	      size_to_map = 0;  // This will map remaining bytes
	    }

	  IoBuildPartialMdl(block->Mdl,
			    Context->CurrentMdl,
			    (PUCHAR) MmGetMdlVirtualAddress(block->Mdl) +
			    page_base_within_block,
			    size_to_map);

	  Context->CurrentPtr =
	    MmGetSystemAddressForMdlSafe(Context->CurrentMdl,
					 HighPagePriority);

	  if (Context->CurrentPtr == NULL)
	    {
	      DbgPrint("AWEAlloc: MmGetSystemAddressForMdlSafe() FAILED.\n");
	      
	      AWEAllocLogError(AWEAllocDriverObject,
			       0,
			       0,
			       NULL,
			       0,
			       1000,
			       STATUS_INSUFFICIENT_RESOURCES,
			       101,
			       STATUS_INSUFFICIENT_RESOURCES,
			       0,
			       0,
			       NULL,
			       L"MmGetSystemAddressForMdlSafe() failed during "
			       L"page mapping.");

	      IoFreeMdl(Context->CurrentMdl);
	      Context->CurrentMdl = NULL;
	      return STATUS_INSUFFICIENT_RESOURCES;
	    }

	  Context->CurrentPageBase = page_base;

	  KdPrint2(("AWEAlloc: MapPage success BaseAddress=%#I64x.\n",
		    page_base));
	}
      finally
	{
	  AWEAllocReleaseProtection(Context, TRUE);
	}
    }
  except (EXCEPTION_EXECUTE_HANDLER)
    {
      DbgPrint("AWEAlloc: Exception occured during page mapping.\n");

      AWEAllocLogError(AWEAllocDriverObject,
		       0,
		       0,
		       NULL,
		       0,
		       1000,
		       STATUS_INSUFFICIENT_RESOURCES,
		       101,
		       STATUS_INSUFFICIENT_RESOURCES,
		       0,
		       0,
		       NULL,
		       L"Exception occured during page mapping.");

      return STATUS_INSUFFICIENT_RESOURCES;
    }

  return STATUS_SUCCESS;
}
Ejemplo n.º 14
0
NDIS_STATUS
PacketReceiveIndicate (
    IN NDIS_HANDLE ProtocolBindingContext,
    IN NDIS_HANDLE MacReceiveContext,
    IN PVOID       HeaderBuffer,
    IN UINT        HeaderBufferSize,
    IN PVOID       LookAheadBuffer,
    IN UINT        LookaheadBufferSize,
    IN UINT        PacketSize
)
{
	POPEN_INSTANCE      open;
	PIO_STACK_LOCATION  irpSp;
	PIRP                irp;
	PLIST_ENTRY         packetListEntry;
	PNDIS_PACKET        pPacket;
	ULONG               sizeToTransfer;
	NDIS_STATUS         status;
	UINT                bytesTransfered = 0;
	ULONG               bufferLength;
	PPACKET_RESERVED    reserved;
	PMDL                pMdl;

	// DebugPrint(("ReceiveIndicate\n"));

	open= (POPEN_INSTANCE)ProtocolBindingContext;

	if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) {
			return NDIS_STATUS_SUCCESS;
	}

	//  See if there are any pending read that we can satisfy
	packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock );

	if (packetListEntry == NULL) {
		// DebugPrint(("No pending read, dropping packets\n"));
		return NDIS_STATUS_NOT_ACCEPTED;
	}

	reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement);
	pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);

	irp = RESERVED(pPacket)->Irp;
	irpSp = IoGetCurrentIrpStackLocation(irp);

	// We don't have to worry about the situation where the IRP is cancelled
	// after we remove it from the queue and before we reset the cancel
	// routine because the cancel routine has been coded to cancel an IRP
	// only if it's in the queue.

	IoSetCancelRoutine(irp, NULL);

	bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH;

		sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength;

	NdisMoveMappedMemory(
			MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority),
			HeaderBuffer,
			HeaderBufferSize
			);

	pMdl=IoAllocateMdl(
						MmGetMdlVirtualAddress(irp->MdlAddress),
						MmGetMdlByteCount(irp->MdlAddress),
						FALSE,
						FALSE,
						NULL
						);

	if (pMdl == NULL) {
		// DebugPrint(("Packet: Read-Failed to allocate Mdl\n"));
		status = NDIS_STATUS_RESOURCES;
		goto ERROR;
	}

	IoBuildPartialMdl(
			irp->MdlAddress,
			pMdl,
			((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH,
			0
			);

	pMdl->Next = NULL;

	RESERVED(pPacket)->pMdl=pMdl;

	NdisChainBufferAtFront(pPacket,pMdl);

	NdisTransferData(
			&status,
			open->AdapterHandle,
			MacReceiveContext,
			0,
			sizeToTransfer,
			pPacket,
			&bytesTransfered
	);

	if (status == NDIS_STATUS_PENDING) {
		return NDIS_STATUS_SUCCESS;
	}

ERROR:
	PacketTransferDataComplete( open, pPacket, status, bytesTransfered );
	return NDIS_STATUS_SUCCESS;
}
Ejemplo n.º 15
0
NDIS_STATUS
NdisuioReceive(
    IN NDIS_HANDLE                  ProtocolBindingContext,
    IN NDIS_HANDLE                  MacReceiveContext,
    IN PVOID                        pHeaderBuffer,
    IN UINT                         HeaderBufferSize,
    IN PVOID                        pLookaheadBuffer,
    IN UINT                         LookaheadBufferSize,
    IN UINT                         PacketSize
    )
/*++

Routine Description:

    Our protocol receive handler called by NDIS, typically if we have
    a miniport below that doesn't indicate packets.

    We make a local packet/buffer copy of this data, queue it up, and
    kick off the read service routine.

Arguments:

    ProtocolBindingContext - pointer to open context
    MacReceiveContext - for use in NdisTransferData
    pHeaderBuffer - pointer to data header
    HeaderBufferSize - size of the above
    pLookaheadBuffer - pointer to buffer containing lookahead data
    LookaheadBufferSize - size of the above
    PacketSize - size of the entire packet, minus header size.

Return Value:

    NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting
    NDIS_STATUS_SUCCESS - if we processed this successfully

--*/
{
    PNDISUIO_OPEN_CONTEXT   pOpenContext;
    NDIS_STATUS             Status;
    PNDISUIO_ETH_HEADER     pEthHeader;
    PNDIS_PACKET            pRcvPacket;
    PUCHAR                  pRcvData;
    UINT                    BytesTransferred;
    PNDIS_BUFFER            pOriginalNdisBuffer, pPartialNdisBuffer;
    PIRP					pIrp;
    PLIST_ENTRY				pIrpEntry;
    ULONG					BytesRemaining; // at pDst
	PPACKET_GROUP			pGroup;

	//ULONG                   pDst;
	
    pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
    NUIO_STRUCT_ASSERT(pOpenContext, oc);
    pRcvPacket = NULL;
    pRcvData = NULL;
    Status = NDIS_STATUS_SUCCESS;

    DEBUGP(DL_LOUD, ("Receive: Open %p, LookaheadBufferSize %d, PacketSize %d\n",
		pOpenContext, LookaheadBufferSize, PacketSize));
    
	NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->ReceivedPackets, 1);

	do
    {
        if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER))
        {
            Status = NDIS_STATUS_NOT_ACCEPTED;
            break;
        }

        pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer;

		NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);

		//
		// Someone is reading, and this is the first packet.
		//
		if (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
			NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
		{
			//
			//  Get the first pended Read IRP
			//
			pIrpEntry = pOpenContext->PendedReads.Flink;
			pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
			
			//
			// We don't have to worry about the situation where the IRP is cancelled
			// after we remove it from the queue and before we reset the cancel
			// routine because the cancel routine has been coded to cancel an IRP
			// only if it's in the queue.
			//
			IoSetCancelRoutine(pIrp, NULL);

			NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
			
			pOpenContext->PendedReadCount--;

			NUIO_RELEASE_LOCK(&pOpenContext->Lock);

			NUIO_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet

			//
			//  Copy as much data as possible from the receive packet to
			//  the IRP MDL.
			//
#ifndef WIN9X
			pGroup = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
			//NUIO_ASSERT(pDst != NULL);  // since it was already mapped
#else
			pGroup = MmGetSystemAddressForMdl(pIrp->MdlAddress);  // Win9x
#endif
			BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress);
			
			BytesRemaining -= sizeof(PACKET_GROUP);

			//
			//  copy the ethernet header into the actual readbuffer
			//
			NdisMoveMappedMemory(pGroup->Data, pHeaderBuffer, HeaderBufferSize);
			
			if (PacketSize == LookaheadBufferSize)
			{
				BytesTransferred = MIN(LookaheadBufferSize, BytesRemaining);

				NdisCopyLookaheadData(pGroup->Data + HeaderBufferSize,
					pLookaheadBuffer,
					BytesTransferred,
					pOpenContext->MacOptions);

				pGroup->Length = BytesTransferred + HeaderBufferSize;
				
				pIrp->IoStatus.Information = pGroup->Length + sizeof(PACKET_GROUP);
				pIrp->IoStatus.Status = STATUS_SUCCESS;				
		
				DEBUGP(DL_LOUD, ("Receive: %d bytes\n", pIrp->IoStatus.Information));
		
				IoCompleteRequest(pIrp, IO_NO_INCREMENT);
			}
			else
			{
				BytesTransferred = 0;

				NdisAllocatePacket(
					&Status,
					&pRcvPacket,
					pOpenContext->RecvBufferPool
					);
				
				if (Status != NDIS_STATUS_SUCCESS)
					goto ERROR;
				
				//
				//  Allocate an MDL to map the portion of the buffer following the
				//  header
				//
				pPartialNdisBuffer = IoAllocateMdl(pGroup->Data, BytesRemaining, FALSE, FALSE, NULL);
				
				if (pPartialNdisBuffer == NULL)
				{
					NdisFreePacket(pRcvPacket);
					Status = NDIS_STATUS_RESOURCES;
					goto ERROR;
				}
				
				//
				//  Build the mdl to point to the the portion of the buffer following
				//  the header
				//
				IoBuildPartialMdl(
					pIrp->MdlAddress,
					pPartialNdisBuffer,
					pGroup->Data + HeaderBufferSize,
					0);
				
				//
				//  Clear the next link in the new MDL
				//
				
				pPartialNdisBuffer->Next = NULL;
				
				//
				//  Get a pointer to the packet itself.
				//
				
				NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = pIrp;
				NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pPartialNdisBuffer;
				
				//
				//  Attach our partial MDL to the packet
				//
				
				NdisChainBufferAtFront(pRcvPacket, pPartialNdisBuffer);
				
				//
				//  Call the Mac to transfer the packet
				//
				
				NdisTransferData(
					&Status,
					pOpenContext->BindingHandle,
					MacReceiveContext,
					0,  // ByteOffset
					PacketSize,
					pRcvPacket,
					&BytesTransferred);

ERROR:					
				//
				//  If it didn't pend, call the completeion routine now
				//
				if (Status != NDIS_STATUS_PENDING)
				{
					NdisuioTransferDataComplete(
						(NDIS_HANDLE)pOpenContext,
						pRcvPacket,
						Status,
						BytesTransferred);
				}
			}

			break;
		}

		NUIO_RELEASE_LOCK(&pOpenContext->Lock);

		//
        //  Allocate resources for queueing this up.
        //
        pRcvPacket = ndisuioAllocateReceivePacket(
			pOpenContext,
			PacketSize + HeaderBufferSize,
			&pRcvData
			);

        if (pRcvPacket == NULL)
        {
            Status = NDIS_STATUS_NOT_ACCEPTED;
            break;
        }

        NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize);

        //
        //  Check if the entire packet is within the lookahead.
        //
        if (PacketSize == LookaheadBufferSize)
        {
            NdisCopyLookaheadData(pRcvData + HeaderBufferSize,
                                  pLookaheadBuffer,
                                  LookaheadBufferSize,
                                  pOpenContext->MacOptions);
            //
            //  Queue this up for receive processing, and
            //  try to complete some read IRPs.
            //
            ndisuioQueueReceivePacket(pOpenContext, pRcvPacket);
        }
        else
        {
            //
            //  Allocate an NDIS buffer to map the receive area
            //  at an offset "HeaderBufferSize" from the current
            //  start. This is so that NdisTransferData can copy
            //  in at the right point in the destination buffer.
            //

            NdisAllocateBuffer(
                &Status,
                &pPartialNdisBuffer,
                pOpenContext->RecvBufferPool,
                pRcvData + HeaderBufferSize,
                PacketSize);
            
            if (Status == NDIS_STATUS_SUCCESS)
            {
                //
                //  Unlink and save away the original NDIS Buffer
                //  that maps the full receive buffer.
                //
                NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer);
                NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer;
				NUIO_IRP_FROM_RCV_PKT(pRcvPacket) = NULL;

                //
                //  Link in the partial buffer for NdisTransferData to
                //  operate on.
                //
                NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer);

                DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:"
                        " Pkt %p, OriginalBuf %p, PartialBuf %p\n",
                        pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer));

                NdisTransferData(
                    &Status,
                    pOpenContext->BindingHandle,
                    MacReceiveContext,
                    0,  // ByteOffset
                    PacketSize,
                    pRcvPacket,
                    &BytesTransferred);
            }
            else
            {
                //
                //  Failure handled below in TransferDataComplete.
                //
                BytesTransferred = 0;
            }
    
            if (Status != NDIS_STATUS_PENDING)
            {
                NdisuioTransferDataComplete(
                    (NDIS_HANDLE)pOpenContext,
                    pRcvPacket,
                    Status,
                    BytesTransferred);
            }
        }
    } while (FALSE);

	if (Status != NDIS_STATUS_SUCCESS && Status != NDIS_STATUS_PENDING)
		NdisInterlockedAddLargeStatistic((PLARGE_INTEGER)&pOpenContext->DroppedPackets, 1);

    return Status;
}
Ejemplo n.º 16
0
NTSTATUS
VfatWriteDiskPartial(
    IN PVFAT_IRP_CONTEXT IrpContext,
    IN PLARGE_INTEGER WriteOffset,
    IN ULONG WriteLength,
    IN ULONG BufferOffset,
    IN BOOLEAN Wait)
{
    PIRP Irp;
    PIO_STACK_LOCATION StackPtr;
    NTSTATUS Status;
    PVOID Buffer;

    DPRINT("VfatWriteDiskPartial(IrpContext %p, WriteOffset %I64x, WriteLength %u, BufferOffset %x, Wait %u)\n",
           IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait);

    Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;

again:
    DPRINT("Building asynchronous FSD Request...\n");
    Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE);
    if (Irp == NULL)
    {
        DPRINT("IoAllocateIrp failed\n");
        return STATUS_UNSUCCESSFUL;
    }

    Irp->UserIosb = NULL;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();

    StackPtr = IoGetNextIrpStackLocation(Irp);
    StackPtr->MajorFunction = IRP_MJ_WRITE;
    StackPtr->MinorFunction = 0;
    StackPtr->Flags = 0;
    StackPtr->Control = 0;
    StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice;
    StackPtr->FileObject = NULL;
    StackPtr->CompletionRoutine = NULL;
    StackPtr->Parameters.Read.Length = WriteLength;
    StackPtr->Parameters.Read.ByteOffset = *WriteOffset;

    if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp))
    {
        DPRINT("IoAllocateMdl failed\n");
        IoFreeIrp(Irp);
        return STATUS_UNSUCCESSFUL;
    }

    IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength);

    IoSetCompletionRoutine(Irp,
                           VfatReadWritePartialCompletion,
                           IrpContext,
                           TRUE,
                           TRUE,
                           TRUE);

    if (Wait)
    {
        KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
        IrpContext->RefCount = 1;
    }
    else
    {
        InterlockedIncrement((PLONG)&IrpContext->RefCount);
    }

    DPRINT("Calling IO Driver...\n");
    Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, Irp);
    if (Wait && Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
        Status = IrpContext->Irp->IoStatus.Status;
    }

    if (Status == STATUS_VERIFY_REQUIRED)
    {
        PDEVICE_OBJECT DeviceToVerify;

        DPRINT1("Media change detected!\n");

        /* Find the device to verify and reset the thread field to empty value again. */
        DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
        IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
        Status = IoVerifyVolume(DeviceToVerify,
                                 FALSE);
        if (NT_SUCCESS(Status))
        {
            DPRINT1("Volume verification successful; Reissuing write request\n");
            goto again;
        }
    }

    return Status;
}
NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite(
    WDFREQUEST request,
    PMDL transfer_mdl,
    ULONG length,
    bool is_read,
    ULONG time_out,
    bool is_ioctl) {
  ASSERT_IRQL_LOW_OR_DISPATCH();

  ASSERT(IsPipeAttached());
  if (!IsPipeAttached()) {
    WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
    return STATUS_INVALID_DEVICE_STATE;
  }

  // Quick access check. Might be redundant though...
  ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe()));
  if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) {
    WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    return STATUS_ACCESS_DENIED;
  }

  // Set URB flags
  ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ?
                                                USBD_TRANSFER_DIRECTION_IN :
                                                USBD_TRANSFER_DIRECTION_OUT);

  // Calculate transfer length for this stage.
  ULONG stage_len =
    (length > GetTransferGranularity()) ? GetTransferGranularity() : length;

  // Get virtual address that we're gonna use in the transfer.
  // We rely here on the fact that we're in the context of the calling thread.
  void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl);

  // Allocate our private MDL for this address which we will use for the transfer
  PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL);
  ASSERT(NULL != new_mdl);
  if (NULL == new_mdl) {
    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Map the portion of user buffer that we're going to transfer at this stage
  // to our mdl.
  IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len);

  // Allocate memory for URB and associate it with this request
  WDF_OBJECT_ATTRIBUTES mem_attrib;
  WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib);
  mem_attrib.ParentObject = request;

  WDFMEMORY urb_mem = NULL;
  PURB urb = NULL;
  NTSTATUS status =
    WdfMemoryCreate(&mem_attrib,
                    NonPagedPool,
                    GANDR_POOL_TAG_BULKRW_URB,
                    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                    &urb_mem,
                    reinterpret_cast<PVOID*>(&urb));
  ASSERT(NT_SUCCESS(status) && (NULL != urb));
  if (!NT_SUCCESS(status)) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Get USB pipe handle for our pipe and initialize transfer request for it
  USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe();
  ASSERT(NULL != usbd_pipe_hndl);
  if (NULL == usbd_pipe_hndl) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    return STATUS_INTERNAL_ERROR;
  }

  // Initialize URB with request information
  UsbBuildInterruptOrBulkTransferRequest(
    urb,
    sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
    usbd_pipe_hndl,
    NULL,
    new_mdl,
    stage_len,
    urb_flags,
    NULL);

  // Build transfer request
  status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(),
                                               request,
                                               urb_mem,
                                               NULL);
  ASSERT(NT_SUCCESS(status));
  if (!NT_SUCCESS(status)) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, status);
    return status;
  }

  // Initialize our request context.
  AndroidUsbWdfRequestContext* context =
    GetAndroidUsbWdfRequestContext(request);
  ASSERT(NULL != context);
  if (NULL == context) {
    IoFreeMdl(new_mdl);
    WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    return STATUS_INTERNAL_ERROR;
  }

  context->object_type = AndroidUsbWdfObjectTypeRequest;
  context->urb_mem = urb_mem;
  context->transfer_mdl = transfer_mdl;
  context->mdl = new_mdl;
  context->length = length;
  context->transfer_size = stage_len;
  context->num_xfer = 0;
  context->virtual_address = virtual_address;
  context->is_read = is_read;
  context->initial_time_out = time_out;
  context->is_ioctl = is_ioctl;

  // Set our completion routine
  WdfRequestSetCompletionRoutine(request,
                                 CommonReadWriteCompletionEntry,
                                 this);

  // Init send options (our timeout goes here)
  WDF_REQUEST_SEND_OPTIONS send_options;
  if (0 != time_out) {
    WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT);
    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out));
  }

  // Timestamp first WdfRequestSend
  KeQuerySystemTime(&context->sent_at);

  // Send request asynchronously.
  if (WdfRequestSend(request, wdf_pipe_io_target(),
                     (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) {
    return STATUS_SUCCESS;
  }

  // Something went wrong here
  status = WdfRequestGetStatus(request);
  ASSERT(!NT_SUCCESS(status));
  GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X",
           is_read, status);
  WdfRequestCompleteWithInformation(request, status, 0);

  return status;
}