示例#1
0
VOID
NdisProtEvtIoWrite(
    IN WDFQUEUE         Queue,
    IN WDFREQUEST       Request,
    IN size_t           Length
    )
/*++

Routine Description:

    Dispatch routine to handle Request_MJ_WRITE.

Arguments:

    Queue - Default queue handle
    Request - Handle to the read/write request
    Lenght - Length of the data buffer associated with the request.
                 The default property of the queue is to not dispatch
                 zero lenght read & write requests to the driver and
                 complete is with status success. So we will never get
                 a zero length request.

Return Value:

    VOID

--*/
{
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    PNET_BUFFER_LIST        pNetBufferList;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
    PVOID                   CancelId;
    ULONG                   SendFlags = 0;
    PMDL                    pMdl = NULL;
    WDFFILEOBJECT           fileObject;
    PREQUEST_CONTEXT        reqContext;
    WDF_OBJECT_ATTRIBUTES   attributes;

    UNREFERENCED_PARAMETER(Queue);

    fileObject = WdfRequestGetFileObject(Request);
    pOpenContext = GetFileObjectContext(fileObject)->OpenContext;

    do
    {
        //
        // Create a context to track the length of transfer and NDIS packet
        // associated with this request.
        //
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);

        NtStatus = WdfObjectAllocateContext(Request, &attributes, &reqContext);
        if(!NT_SUCCESS(NtStatus)){
            DEBUGP(DL_WARN, ("Write: WdfObjectAllocateContext failed: %x\n", NtStatus));
            NtStatus = STATUS_INVALID_HANDLE;
            break;

        }

        reqContext->Length = (ULONG) Length;

        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
                fileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        NtStatus = WdfRequestRetrieveInputWdmMdl(Request, &pMdl);
        if (!NT_SUCCESS(NtStatus))
        {
            DEBUGP(DL_FATAL, ("Write: WdfRequestRetrieveInputWdmMdl failed %x\n", NtStatus));
            break;
        }

        //
        // Try to get a virtual address for the MDL.
        //
        pEthHeader = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority | MdlMappingNoExecute);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                    " Request %p, MDL %p\n",
                    Request, pMdl));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        DataLength = MmGetMdlByteCount(pMdl);
        if (DataLength < sizeof(NDISPROT_ETH_HEADER))
        {
            DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
                DataLength));
            NtStatus = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
        {
            DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
                    " larger than max frame size (%d)\n",
                    pOpenContext, DataLength, pOpenContext->MaxFrameSize));

            NtStatus = STATUS_INVALID_BUFFER_SIZE;
            break;
        }

        //
        // To prevent applications from sending packets with spoofed
        // mac address, we will do the following check to make sure the source
        // address in the packet is same as the current MAC address of the NIC.
        //
        if ((WdfRequestGetRequestorMode(Request) == UserMode) &&
            !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
        {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
            " or in low power state\n", pOpenContext));

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        if ((pOpenContext->State == NdisprotPaused)
            || (pOpenContext->State == NdisprotPausing))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_INFO, ("Device is paused.\n"));
            NtStatus = STATUS_UNSUCCESSFUL;
            break;
        }

        NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL);
        pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
                                pOpenContext->SendNetBufferListPool,
                                sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta
                                0,           // back fill size
                                pMdl,
                                0,          // Data offset
                                DataLength);

        if (pNetBufferList == NULL)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n",
                    pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        pOpenContext->PendedSendCount++;

        NPROT_REF_OPEN(pOpenContext);  // pended send

        //
        //  Initialize the NetBufferList ref count. This NetBufferList will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1;

        //
        //  We set up a cancel ID on each send NetBufferList (which maps to a Write IRP),
        //  and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendNetBufferLists() to cancel the NetBufferList.
        //
        //  Note that this sample code does not implement the cancellation logic. An actual
        //  driver may find value in implementing this.
        //

        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId);
        reqContext->NetBufferList = (PVOID)pNetBufferList;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_REQUEST_FROM_SEND_NBL(pNetBufferList) = Request;

        NtStatus = STATUS_PENDING;

        pNetBufferList->SourceHandle = pOpenContext->BindingHandle;
        NPROT_ASSERT (pMdl->Next == NULL);

        SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

        NdisSendNetBufferLists(
                        pOpenContext->BindingHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        SendFlags);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        WdfRequestComplete(Request, NtStatus);
    }

    return;
}
void AndroidUsbPipeFileObject::OnCtlBulkWrite(WDFREQUEST request,
                                              size_t output_buf_len,
                                              size_t input_buf_len) {
  ASSERT_IRQL_LOW_OR_DISPATCH();

  // Make sure that this is an output pipe
  if (is_input_pipe()) {
    GoogleDbgPrint("\n!!!! Attempt to IOCTL write to input pipe %p", this);
    WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    return;
  }

  // Verify buffers
  ASSERT(input_buf_len >= sizeof(AdbBulkTransfer));
  // Output buffer points to ULONG that receives number of transferred bytes
  ASSERT(output_buf_len >= sizeof(ULONG));
  if ((input_buf_len < sizeof(AdbBulkTransfer)) ||
      (output_buf_len < sizeof(ULONG))) {
    WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE);
    return;
  }

  // Get the input buffer
  NTSTATUS status = STATUS_SUCCESS;
  AdbBulkTransfer* transfer_param =
    reinterpret_cast<AdbBulkTransfer*>(InAddress(request, &status));
  ASSERT(NT_SUCCESS(status) && (NULL != transfer_param));
  if (!NT_SUCCESS(status)) {
    WdfRequestComplete(request, status);
    return;
  }

  // Get the output buffer
  ULONG* ret_transfer =
    reinterpret_cast<ULONG*>(OutAddress(request, &status));
  ASSERT(NT_SUCCESS(status) && (NULL != ret_transfer));
  if (!NT_SUCCESS(status)) {
    WdfRequestComplete(request, status);
    return;
  }

  // Cache these param to prevent us from sudden change after we've chacked it.
  // This is common practice in protecting ourselves from malicious code:
  // 1. Never trust anything that comes from the User Mode.
  // 2. Never assume that anything that User Mode buffer has will remain
  // unchanged.
  void* transfer_buffer = transfer_param->GetWriteBuffer();
  ULONG transfer_size = transfer_param->transfer_size;

  // Make sure zero length I/O doesn't go through
  if (0 == transfer_size) {
    *ret_transfer = 0;
    WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, sizeof(ULONG));
    return;
  }

  // Make sure that buffer is not NULL
  ASSERT(NULL != transfer_buffer);
  if (NULL == transfer_buffer) {
    WdfRequestComplete(request, STATUS_INVALID_PARAMETER);
    return;
  }

  // At this point we are ready to build MDL for the user buffer.
  PMDL write_mdl =
    IoAllocateMdl(transfer_buffer, transfer_size, FALSE, FALSE, NULL);
  ASSERT(NULL != write_mdl);
  if (NULL == write_mdl) {
    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    return;
  }

  // Now we need to probe/lock this mdl
  __try {
    MmProbeAndLockPages(write_mdl,
                        WdfRequestGetRequestorMode(request),
                        IoReadAccess);
    status = STATUS_SUCCESS;
  } __except (EXCEPTION_EXECUTE_HANDLER) {
    status = GetExceptionCode();
    ASSERTMSG("\n!!!!! AndroidUsbPipeFileObject::OnCtlBulkWrite exception",
              false);
  }

  if (!NT_SUCCESS(status)) {
    IoFreeMdl(write_mdl);
    WdfRequestComplete(request, status);
    return;
  }

  // Perform the write
  status = CommonBulkReadWrite(request,
                               write_mdl,
                               transfer_size,
                               false,
                               transfer_param->time_out,
                               true);
  if (!NT_SUCCESS(status)) {
    // If CommonBulkReadWrite failed we need to unlock and free MDL here
    MmUnlockPages(write_mdl);
    IoFreeMdl(write_mdl);
  }
}