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); } }