Exemplo n.º 1
0
BOOLEAN
AWEAllocAddBlock(IN POBJECT_CONTEXT Context,
		 IN PBLOCK_DESCRIPTOR Block)
{
  ULONG block_size;

  PAGED_CODE();

  if (Block->Mdl == NULL)
    return FALSE;

  block_size = AWEAllocGetPageBaseFromAbsOffset(MmGetMdlByteCount(Block->Mdl));
  if (block_size == 0)
    {
      KdPrint(("AWEAlloc: Got %u bytes which is too small for page size.\n",
	       MmGetMdlByteCount(Block->Mdl)));

      MmFreePagesFromMdl(Block->Mdl);
      ExFreePool(Block->Mdl);
      Block->Mdl = NULL;
      return FALSE;
    }

  Block->Offset = Context->TotalSize;
  Block->NextBlock = Context->FirstBlock;
  Context->FirstBlock = Block;
  Context->TotalSize += block_size;
  return TRUE;
}
Exemplo n.º 2
0
uint64 hax_get_pfn_user(hax_memdesc_user *memdesc, uint64 uva_offset)
{
    PMDL pmdl = NULL;
    PPFN_NUMBER ppfn = NULL;
    uint64 len;

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

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

    pmdl = memdesc->pmdl;

    len = MmGetMdlByteCount(pmdl);
    if (uva_offset >= len) {
        hax_error("The uva_offset 0x%llx exceeds the buffer length 0x%llx.\n",
                  uva_offset, len);
        return INVALID_PFN;
    }

    ppfn = MmGetMdlPfnArray(pmdl);
    if (NULL == ppfn) {
        hax_error("Get MDL pfn array failed. uva_offset: 0x%llx.\n",
                  uva_offset);
        return INVALID_PFN;
    }

    return (uint64)ppfn[uva_offset >> PG_ORDER_4K];
}
Exemplo n.º 3
0
Arquivo: io.c Projeto: GYGit/reactos
/*
 * @implemented
 */
VOID
EXPORT
NdisMCompleteBufferPhysicalMapping(
    IN  NDIS_HANDLE     MiniportAdapterHandle,
    IN  PNDIS_BUFFER    Buffer,
    IN  ULONG           PhysicalMapRegister)
/*
 * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping
 * ARGUMENTS:
 *     - MiniportAdapterHandle: handle originally input to MiniportInitialize
 *     - Buffer: NDIS_BUFFER to complete the mapping on
 *     - PhyscialMapRegister: the chosen map register
 * NOTES:
 *     - May be called at IRQL <= DISPATCH_LEVEL
 */
{
  PLOGICAL_ADAPTER Adapter;
  VOID *CurrentVa;
  ULONG Length;

  ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  ASSERT(MiniportAdapterHandle && Buffer);

  Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
  CurrentVa = MmGetMdlVirtualAddress(Buffer);
  Length = MmGetMdlByteCount(Buffer);

  Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->FlushAdapterBuffers(
      Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer,
      Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister,
      CurrentVa, Length,
      Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice);
}
Exemplo n.º 4
0
/*
 * --------------------------------------------------------------------------
 * FixSegmentHeader
 *
 *    Fix IP length, IP checksum, TCP sequence number and TCP checksum
 *    in the segment.
 * --------------------------------------------------------------------------
 */
static NDIS_STATUS
FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber)
{
    EthHdr *dstEth;
    IPHdr *dstIP;
    TCPHdr *dstTCP;
    PMDL mdl;
    PUINT8 bufferStart;

    mdl = NET_BUFFER_FIRST_MDL(nb);

    bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
    if (!bufferStart) {
        return NDIS_STATUS_RESOURCES;
    }
    dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
    ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
            >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
    dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth);
    dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
    ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
            >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));

    /* Fix IP length and checksum */
    ASSERT(dstIP->protocol == IPPROTO_TCP);
    dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
    dstIP->check = 0;
    dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);

    /* Fix TCP checksum */
    dstTCP->seq = htonl(seqNumber);
    dstTCP->check =
        IPPseudoChecksum((UINT32 *)&dstIP->saddr,
                         (UINT32 *)&dstIP->daddr,
                         IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP));
    dstTCP->check = CalculateChecksumNB(nb,
            (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4),
            sizeof *dstEth + dstIP->ihl * 4);
    return STATUS_SUCCESS;
}
Exemplo n.º 5
0
VOID XNdisGetFirstBufferFromPacket(PNDIS_PACKET Packet,
				   PNDIS_BUFFER *FirstBuffer,
				   PVOID *FirstBufferVA,
				   PUINT FirstBufferLength,
				   PUINT TotalBufferLength)
{
    PNDIS_BUFFER _Buffer;

    _Buffer              = (Packet)->Private.Head;
    *(FirstBuffer)       = _Buffer;
    *(FirstBufferVA)     = MmGetMdlVirtualAddress(_Buffer);
    if (_Buffer != NULL) {
        *(FirstBufferLength) = MmGetMdlByteCount(_Buffer);
        _Buffer = _Buffer->Next;
    } else
        *(FirstBufferLength) = 0;
    *(TotalBufferLength) = *(FirstBufferLength);
    while (_Buffer != NULL) {
        *(TotalBufferLength) += MmGetMdlByteCount(_Buffer);
        _Buffer = _Buffer->Next;
    }
}
Exemplo n.º 6
0
//---------------------------------------------------------------------------
NTSTATUS DriverRead(IN PDEVICE_OBJECT vDeviceObject, IN PIRP vIrp)
{
	Debug("Enter DriverRead");
	if(0 == vIrp->MdlAddress)
	{
		vIrp->IoStatus.Information	= 0;
		vIrp->IoStatus.Status		= STATUS_UNSUCCESSFUL;
		IoCompleteRequest(vIrp,IO_NO_INCREMENT);
		return STATUS_UNSUCCESSFUL;
	}

	PVOID tVirtualAddress = MmGetMdlVirtualAddress(vIrp->MdlAddress);
	ULONG tLength = MmGetMdlByteCount(vIrp->MdlAddress);
	RtlFillMemory(tVirtualAddress,tLength,'A');

	vIrp->IoStatus.Information	= tLength;
	vIrp->IoStatus.Status		= STATUS_SUCCESS;
	IoCompleteRequest(vIrp,IO_NO_INCREMENT);
	Debug("Leave DriverRead");
	return STATUS_SUCCESS;
}
VOID
BalloonLeak(
    IN WDFOBJECT WdfDevice,
    IN size_t num
    )
{
    PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice);
    PPAGE_LIST_ENTRY pPageListEntry;
    PMDL pPageMdl;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);

    pPageListEntry = (PPAGE_LIST_ENTRY)PopEntryList(&ctx->PageListHead);
    if (pPageListEntry == NULL)
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "No list entries.\n");
        return;
    }

    pPageMdl = pPageListEntry->PageMdl;

    num = MmGetMdlByteCount(pPageMdl) / PAGE_SIZE;
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
        "Deflate balloon with %d pages.\n", num);

    ctx->num_pfns = num;
    ctx->num_pages -= ctx->num_pfns;

    RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl),
        ctx->num_pfns * sizeof(PFN_NUMBER));

    MmFreePagesFromMdl(pPageMdl);
    ExFreePool(pPageMdl);
    ExFreeToNPagedLookasideList(&ctx->LookAsideList, pPageListEntry);

    BalloonTellHost(WdfDevice, ctx->DefVirtQueue);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
}
Exemplo n.º 8
0
NTSTATUS USBPcapBufferHandleReadIrp(PIRP pIrp,
                                    PDEVICE_EXTENSION pDevExt,
                                    PUINT32 pBytesRead)
{
    PDEVICE_EXTENSION      pRootExt;
    PUSBPCAP_ROOTHUB_DATA  pRootData;
    PVOID                  buffer;
    UINT32                 bufferLength;
    UINT32                 bytesRead;
    NTSTATUS               status;
    KIRQL                  irql;
    PIO_STACK_LOCATION     pStack = NULL;

    pStack = IoGetCurrentIrpStackLocation(pIrp);

    *pBytesRead = 0;

    if (pStack->Parameters.Read.Length == 0)
    {
        return STATUS_SUCCESS;
    }

    pRootExt = (PDEVICE_EXTENSION)pDevExt->context.control.pRootHubObject->DeviceExtension;
    pRootData = pRootExt->context.usb.pDeviceData->pRootData;

    if (pRootData->buffer == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }

    /*
     * Since control device has DO_DIRECT_IO bit set the MDL is already
     * probed and locked
     */
    buffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,
                                          NormalPagePriority);

    if (buffer == NULL)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    else
    {
        bufferLength = MmGetMdlByteCount(pIrp->MdlAddress);
    }

    /* Get data from data queue, if there is no data we put
     * this IRP to Cancel-Safe queue and return status pending
     * otherwise complete this IRP then return SUCCESS
     */
    KeAcquireSpinLock(&pRootData->bufferLock, &irql);
    bytesRead = USBPcapBufferRead(pRootData,
                                  buffer, bufferLength);
    KeReleaseSpinLock(&pRootData->bufferLock, irql);

    *pBytesRead = bytesRead;
    if (bytesRead == 0)
    {
        IoCsqInsertIrp(&pDevExt->context.control.ioCsq,
                       pIrp, NULL);
        return STATUS_PENDING;
    }

    return STATUS_SUCCESS;
}
Exemplo n.º 9
0
NTSTATUS USBPcapBufferWritePacket(PUSBPCAP_ROOTHUB_DATA pRootData,
                                  PUSBPCAP_BUFFER_PACKET_HEADER header,
                                  PVOID buffer)
{
    UINT32             bytes;
    UINT32             bytesFree;
    KIRQL              irql;
    NTSTATUS           status;
    PDEVICE_EXTENSION  pControlExt;
    PIRP               pIrp = NULL;
    pcaprec_hdr_t      pcapHeader;

    pControlExt = (PDEVICE_EXTENSION)pRootData->controlDevice->DeviceExtension;

    ASSERT(pControlExt->deviceMagic == USBPCAP_MAGIC_CONTROL);

    bytes = header->headerLen + header->dataLength;

    KeAcquireSpinLock(&pRootData->bufferLock, &irql);

    USBPcapInitializePcapHeader(pRootData, &pcapHeader, bytes);

    /* pcapHeader.incl_len contains the number of bytes to write */
    bytes = pcapHeader.incl_len;

    status = STATUS_SUCCESS;

    bytesFree = USBPcapGetBufferFree(pRootData);

    if ((pRootData->buffer == NULL) ||
        (bytesFree < sizeof(pcaprec_hdr_t)) ||
        ((bytesFree - sizeof(pcaprec_hdr_t)) < bytes))
    {
        DkDbgStr("No enough free space left.");
        status = STATUS_INSUFFICIENT_RESOURCES;
    }
    else
    {
        UINT32 tmp;

        /* Write Packet Header */
        USBPcapBufferWriteUnsafe(pRootData,
                                 (PVOID) &pcapHeader,
                                 (UINT32) sizeof(pcaprec_hdr_t));

        /* Write USBPCAP_BUFFER_PACKET_HEADER */
        tmp = min(bytes, (UINT32)header->headerLen);
        if (tmp > 0)
        {
            USBPcapBufferWriteUnsafe(pRootData,
                                     (PVOID) header,
                                     tmp);
        }
        bytes -= tmp;

        if (bytes > 0 && header->dataLength > 0)
        {
            /* Write data */
            tmp = min(bytes, header->dataLength);
            USBPcapBufferWriteUnsafe(pRootData,
                                     buffer,
                                     tmp);
        }
    }
    KeReleaseSpinLock(&pRootData->bufferLock, irql);

    if (NT_SUCCESS(status))
    {
        pIrp = IoCsqRemoveNextIrp(&pControlExt->context.control.ioCsq,
                                  NULL);
        if (pIrp != NULL)
        {
            PVOID   buffer;
            UINT32  bufferLength;
            UINT32  bytesRead;

            /*
             * Only IRPs with non-zero buffer are being queued.
             *
             * Since control device has DO_DIRECT_IO bit set the MDL is already
             * probed and locked
             */
            buffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,
                                                  NormalPagePriority);

            if (buffer == NULL)
            {
                pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                bytes = 0;
            }
            else
            {
                UINT32 bufferLength = MmGetMdlByteCount(pIrp->MdlAddress);

                if (bufferLength != 0)
                {
                    KeAcquireSpinLock(&pRootData->bufferLock, &irql);
                    bytes = USBPcapBufferRead(pRootData,
                                              buffer, bufferLength);
                    KeReleaseSpinLock(&pRootData->bufferLock, irql);
                }
                else
                {
                    bytes = 0;
                }

                pIrp->IoStatus.Status = STATUS_SUCCESS;
            }

            pIrp->IoStatus.Information = (ULONG_PTR) bytes;
            IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        }
    }

    return status;
}
Exemplo n.º 10
0
NTSTATUS
NbfTdiReceive(
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the TdiReceive request for the transport provider.

Arguments:

    Irp - I/O Request Packet for this request.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    NTSTATUS status;
    PTP_CONNECTION connection;
    KIRQL oldirql;
    PIO_STACK_LOCATION irpSp;

    //
    // verify that the operation is taking place on a connection. At the same
    // time we do this, we reference the connection. This ensures it does not
    // get removed out from under us. Note also that we do the connection
    // lookup within a try/except clause, thus protecting ourselves against
    // really bogus handles
    //

    irpSp = IoGetCurrentIrpStackLocation (Irp);
    connection = irpSp->FileObject->FsContext;

    //
    // Check that this is really a connection.
    //

    if ((connection->Size != sizeof (TP_CONNECTION)) ||
        (connection->Type != NBF_CONNECTION_SIGNATURE)) {
#if DBG
        NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp);
#endif
        return STATUS_INVALID_CONNECTION;
    }

    //
    // Initialize bytes transferred here.
    //

    Irp->IoStatus.Information = 0;              // reset byte transfer count.

    // This reference is removed by NbfDestroyRequest.

    KeRaiseIrql (DISPATCH_LEVEL, &oldirql);

    ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);

    if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {

        RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);

        Irp->IoStatus.Status = connection->Status;
        IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);

        status = STATUS_PENDING;

    } else {
        KIRQL cancelIrql;

        //
        // Once the reference is in, LinkSpinLock will be valid.
        //

        NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP);
        RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);

        IoAcquireCancelSpinLock(&cancelIrql);
        ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);

        IRP_RECEIVE_IRP(irpSp) = Irp;
        IRP_RECEIVE_REFCOUNT(irpSp) = 1;

#if DBG
        NbfReceives[NbfReceivesNext].Irp = Irp;
        NbfReceives[NbfReceivesNext].Request = NULL;
        NbfReceives[NbfReceivesNext].Connection = (PVOID)connection;
        NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
#endif

        //
        // If this IRP has been cancelled, complete it now.
        //

        if (Irp->Cancel) {

#if DBG
            NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
            NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
            NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
            {
                ULONG i,j,k;
                PUCHAR va;
                PMDL mdl;

                mdl = Irp->MdlAddress;

                NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0;

                i = 1;
                while (i<TRACK_TDI_CAPTURE) {
                    if (mdl == NULL) break;
                    va = MmGetSystemAddressForMdl (mdl);
                    j = MmGetMdlByteCount (mdl);

                    for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
                        NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
                    }
                    mdl = mdl->Next;
                }
            }

            NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
#endif

            //
            // It is safe to do this with locks held.
            //
            NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0);

            RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
            IoReleaseCancelSpinLock(cancelIrql);

        } else {

            //
            // Insert onto the receive queue, and make the IRP
            // cancellable.
            //

            InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry);
            IoSetCancelRoutine(Irp, NbfCancelReceive);

            //
            // Release the cancel spinlock out of order. Since we were
            // already at dpc level when it was acquired, we don't
            // need to swap irqls.
            //
            ASSERT(cancelIrql == DISPATCH_LEVEL);
            IoReleaseCancelSpinLock(cancelIrql);

            //
            // This call releases the link spinlock, and references the
            // connection first if it needs to access it after
            // releasing the lock.
            //

            AwakenReceive (connection);             // awaken if sleeping.

        }

        status = STATUS_PENDING;

    }

    KeLowerIrql (oldirql);

    return status;
} /* TdiReceive */
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
    )
{
    IoFreeMdl(Buffer);
}

VOID
NdisQueryBuffer(
    IN PNDIS_BUFFER Buffer,
    OUT PVOID *VirtualAddress OPTIONAL,
    OUT PUINT Length
    )
{
    if ( ARGUMENT_PRESENT(VirtualAddress) ) {
        *VirtualAddress = MmGetSystemAddressForMdl(Buffer);
    }
    *Length = MmGetMdlByteCount(Buffer);
}

VOID
NdisQueryBufferOffset(
    IN PNDIS_BUFFER Buffer,
    OUT PUINT Offset,
    OUT PUINT Length
    )
{
    *Offset = MmGetMdlByteOffset(Buffer);
    *Length = MmGetMdlByteCount(Buffer);
}

ULONG
NDIS_BUFFER_TO_SPAN_PAGES(
Exemplo n.º 13
0
NDIS_STATUS
CopyBytesFromNetBuffer(  PNET_BUFFER_KK        NetBuffer,  PULONG             cbDest, PVOID Dest)
/*++

Routine Description:

    Copies the first cbDest bytes from a NET_BUFFER. In order to show how the various data structures fit together, this 
    implementation copies the data by iterating through the MDLs for the NET_BUFFER. The NdisGetDataBuffer API also allows you
    to copy a contiguous block of data from a NET_BUFFER. 

    Runs at IRQL <= DISPATCH_LEVEL.

Arguments:

    NetBuffer                   The NB to read
    cbDest                      On input, the number of bytes in the buffer Dest
                                On return, the number of bytes actually copied
    Dest                        On return, receives the first cbDest bytes of
                                the network frame in NetBuffer

Return Value:

    None.

Notes:

    If the output buffer is larger than the NB's frame size, *cbDest will
    contain the number of bytes in the frame size.

    If the output buffer is smaller than the NB's frame size, only the first
    *cbDest bytes will be copied (the buffer will receive a truncated copy of
    the frame).

--*/
{
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
    //
    // Start copy from current MDL
    //
    PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
    //
    // Data on current MDL may be offset from start of MDL
    //
    ULONG DestOffset = 0;
    while (DestOffset < *cbDest && CurrentMdl)
    {
        //
        // Map MDL memory to System Address Space. LowPagePriority means mapping may fail if 
        // system is low on memory resources. 
        //
        PUCHAR SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority);
        ULONG Length = MmGetMdlByteCount(CurrentMdl);
        if (!SrcMemory)
        {
            Status = NDIS_STATUS_RESOURCES;
            break;
        }

        if(DestOffset==0)
        {
            //
            // The first MDL segment should be accessed from the current MDL offset
            //
            ULONG MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer);
            SrcMemory += MdlOffset;
            Length -= MdlOffset;
        }

        Length = min(Length, *cbDest-DestOffset);

        //
        // Copy Memory
        //
        NdisMoveMemory((PUCHAR)Dest+DestOffset, SrcMemory, Length);
        DestOffset += Length;

        //
        // Get next MDL (if any available) 
        //
        CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl);
    }

    if(Status == NDIS_STATUS_SUCCESS)
    {
        *cbDest = DestOffset;
    }

    return Status;
}
VOID
BalloonFill(
    IN WDFOBJECT WdfDevice,
    IN size_t num)
{
    PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice);
    PHYSICAL_ADDRESS LowAddress;
    PHYSICAL_ADDRESS HighAddress;
    PHYSICAL_ADDRESS SkipBytes;
    PPAGE_LIST_ENTRY pNewPageListEntry;
    PMDL pPageMdl;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);

    ctx->num_pfns = 0;

    if (IsLowMemory(WdfDevice))
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
            "Low memory. Allocated pages: %d\n", ctx->num_pages);
        return;
    }

    num = min(num, PAGE_SIZE / sizeof(PFN_NUMBER));
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
        "Inflate balloon with %d pages.\n", num);

    LowAddress.QuadPart = 0;
    HighAddress.QuadPart = (ULONGLONG)-1;
    SkipBytes.QuadPart = 0;

#if (NTDDI_VERSION < NTDDI_WS03SP1)
    pPageMdl = MmAllocatePagesForMdl(LowAddress, HighAddress, SkipBytes,
        num * PAGE_SIZE);
#else
    pPageMdl = MmAllocatePagesForMdlEx(LowAddress, HighAddress, SkipBytes,
        num * PAGE_SIZE, MmNonCached, MM_DONT_ZERO_ALLOCATION);
#endif

    if (pPageMdl == NULL)
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
            "Failed to allocate pages.\n");
        return;
    }

    if (MmGetMdlByteCount(pPageMdl) != (num * PAGE_SIZE))
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
            "Not all requested memory was allocated (%d/%d).\n",
            MmGetMdlByteCount(pPageMdl), num * PAGE_SIZE);
        MmFreePagesFromMdl(pPageMdl);
        ExFreePool(pPageMdl);
        return;
    }

    pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList(
        &ctx->LookAsideList);

    if (pNewPageListEntry == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS,
            "Failed to allocate list entry.\n");
        MmFreePagesFromMdl(pPageMdl);
        ExFreePool(pPageMdl);
        return;
    }

    pNewPageListEntry->PageMdl = pPageMdl;
    PushEntryList(&ctx->PageListHead, &(pNewPageListEntry->SingleListEntry));

    ctx->num_pfns = num;
    ctx->num_pages += ctx->num_pfns;

    RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl),
        ctx->num_pfns * sizeof(PFN_NUMBER));

    BalloonTellHost(WdfDevice, ctx->InfVirtQueue);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
}
NTSTATUS
WDFEXPORT(WdfDmaTransactionInitializeUsingRequest)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDMATRANSACTION DmaTransaction,
    __in
    WDFREQUEST Request,
    __in
    PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction,
    __in
    WDF_DMA_DIRECTION DmaDirection
    )
{
    NTSTATUS status;
    FxDmaTransactionBase* pDmaTrans;
    FxRequest* pReqObj;
    MDL* mdl = NULL;
    PIO_STACK_LOCATION stack;
    ULONG reqLength;
    PFX_DRIVER_GLOBALS  pFxDriverGlobals;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   DmaTransaction,
                                   FX_TYPE_DMA_TRANSACTION,
                                   (PVOID *) &pDmaTrans,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction);

    if (DmaDirection != WdfDmaDirectionReadFromDevice &&
        DmaDirection != WdfDmaDirectionWriteToDevice) {
        status = STATUS_INVALID_PARAMETER;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
            "Initialization of WDFDMATRANSACTION 0x%p using WDFREQUEST %p, "
            "DmaDirection 0x%x is an invalid value, %!STATUS!",
            DmaTransaction, Request, DmaDirection, status);
        return status;
    }

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         Request,
                         FX_TYPE_REQUEST,
                         (PVOID *) &pReqObj);

    reqLength = 0;

    stack = pReqObj->GetFxIrp()->GetCurrentIrpStackLocation();

    //
    // Get the MDL and Length from the request.
    //
    switch (stack->MajorFunction) {

    case IRP_MJ_READ:

        if (DmaDirection != WdfDmaDirectionReadFromDevice) {
            status = STATUS_INVALID_DEVICE_REQUEST;

            DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                "0x%p doesn't match with the WDFREQUEST 0x%p type "
                                "%!WDF_REQUEST_TYPE! %!STATUS!",
                                DmaDirection, DmaTransaction, Request,
                                stack->MajorFunction, status);

            return status;
        }

        reqLength = stack->Parameters.Read.Length;

        status = pReqObj->GetMdl(&mdl);
        break;

    case IRP_MJ_WRITE:

        if (DmaDirection != WdfDmaDirectionWriteToDevice) {
            status = STATUS_INVALID_DEVICE_REQUEST;

            DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                "0x%p doesn't match with the WDFREQUEST 0x%p type "
                                "%!WDF_REQUEST_TYPE! %!STATUS!",
                                DmaDirection, DmaTransaction, Request,
                                stack->MajorFunction, status);

            return status;
        }

        reqLength = stack->Parameters.Write.Length;

        status = pReqObj->GetMdl(&mdl);
        break;

    case IRP_MJ_DEVICE_CONTROL:
    case IRP_MJ_INTERNAL_DEVICE_CONTROL:

        switch (METHOD_FROM_CTL_CODE(stack->Parameters.DeviceIoControl.IoControlCode)) {
            case METHOD_BUFFERED:

                if (DmaDirection == WdfDmaDirectionWriteToDevice) {
                    reqLength = stack->Parameters.DeviceIoControl.InputBufferLength;
                } else {
                    reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;
                }

                //
                // In this case both input buffer and output buffer map
                // to the same MDL and it's probed for read & write access.
                // So it's okay for DMA transfer in either direction.
                //
                status = pReqObj->GetMdl(&mdl);
                break;

            case METHOD_IN_DIRECT:
                //
                // For this type, the output buffer is probed for read access.
                // So the direction of DMA transfer is WdfDmaDirectionWriteToDevice.
                //
                if (DmaDirection != WdfDmaDirectionWriteToDevice) {

                    status = STATUS_INVALID_DEVICE_REQUEST;

                    DoTraceLevelMessage(pFxDriverGlobals,
                                        TRACE_LEVEL_ERROR, TRACINGDMA,
                                        "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                        "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
                                        "METHOD_IN_DIRECT %!STATUS!",
                                        DmaDirection, DmaTransaction, Request, status);
                    return status;
                }

                reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

                status = pReqObj->GetDeviceControlOutputMdl(&mdl);

                break;

            case METHOD_OUT_DIRECT:
                //
                // For this type, the output buffer is probed for write access.
                // So the direction of DMA transfer is WdfDmaDirectionReadFromDevice.
                //
                if (DmaDirection != WdfDmaDirectionReadFromDevice) {

                    status = STATUS_INVALID_DEVICE_REQUEST;

                    DoTraceLevelMessage(pFxDriverGlobals,
                                        TRACE_LEVEL_ERROR, TRACINGDMA,
                                        "Dma direction %!WDF_DMA_DIRECTION! of WDFTRANSACTION "
                                        "0x%p doesn't match with WDFREQUEST 0x%p ioctl type "
                                        "METHOD_OUT_DIRECT %!STATUS!",
                                        DmaDirection, DmaTransaction, Request, status);

                    return status;
                }

                reqLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

                status = pReqObj->GetDeviceControlOutputMdl(&mdl);

                break;
            default:

                status = STATUS_INVALID_DEVICE_REQUEST;

                DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                                    "Invalid ioctl code in WDFREQUEST 0x%p %!STATUS!",
                                    Request, status);

                FxVerifierDbgBreakPoint(pFxDriverGlobals);
                break;

        }// End of switch(ioctType)
        break;

    default:
        status = STATUS_INVALID_DEVICE_REQUEST;
        break;

    }

    if (!NT_SUCCESS(status)) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                            "Couldn't retrieve mdl from WDFREQUEST 0x%p for "
                            "WDFTRANSACTION 0x%p %!STATUS!",
                            Request, DmaTransaction, status);
        return status;
    }

    if (reqLength == 0) {
        status = STATUS_INVALID_DEVICE_REQUEST;
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
            "Zero length request, %!STATUS!", status);
        return status;
    }

    //
    // If the DMA enabler is packet based, make sure the virtual address and
    // the length of transfer are within bounds. Basically, we are checking
    // to see if the length of data to be transferred doesn't span multiple
    // MDLs, because packet based DMA doesn't support chained MDLs.
    //
    if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) {
        ULONG  length;

        length = MmGetMdlByteCount(mdl);

        if (reqLength > length) {
            status = STATUS_INVALID_PARAMETER;
            DoTraceLevelMessage(
                pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                "WDFREQUEST %p transfer length (%d) is out of bounds of MDL "
                "Byte count (%d), %!STATUS!",
                Request, reqLength, length, status);

            return status;
        }
    }

    //
    // Parms appear OK, so initialize this instance.
    //
    status = pDmaTrans->Initialize(EvtProgramDmaFunction,
                                   DmaDirection,
                                   mdl,
                                   0,
                                   reqLength);

    if (!NT_SUCCESS(status)) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA,
                            "WDFTANSACTION 0x%p initialization failed: "
                            "%!STATUS!", DmaTransaction, status);
        return status;
    }

    //
    // Set this Request in the new DmaTransaction.  The request will 
    // take a reference on this request when it starts executing.
    //
    pDmaTrans->SetRequest(pReqObj);

    return STATUS_SUCCESS;
}
Exemplo n.º 16
0
NTSTATUS
NdisProtWrite(
    IN PDEVICE_OBJECT       pDeviceObject,
    IN PIRP                 pIrp
)
/*++

Routine Description:

    Dispatch routine to handle IRP_MJ_WRITE.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - Pointer to request packet

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    NDIS_STATUS             Status;
    PNDISPROT_OPEN_CONTEXT   pOpenContext;
    PNDIS_PACKET            pNdisPacket;
    PNDIS_BUFFER            pNdisBuffer;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
#ifdef NDIS51
    PVOID                   CancelId;
#endif

    UNREFERENCED_PARAMETER(pDeviceObject);

    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;

    pNdisPacket = NULL;

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

        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        if (pIrp->MdlAddress == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
        //
        // Try to get a virtual address for the MDL.
        //

        pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                              " IRP %p, MDL %p\n",
                              pIrp, pIrp->MdlAddress));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        DataLength = MmGetMdlByteCount(pIrp->MdlAddress);
        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 ((pIrp->RequestorMode == 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);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

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

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        //
        //  Allocate a send packet.
        //
        NPROT_ASSERT(pOpenContext->SendPacketPool != NULL);
        NdisAllocatePacket(
            &Status,
            &pNdisPacket,
            pOpenContext->SendPacketPool);

        if (Status != NDIS_STATUS_SUCCESS)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n",
                              pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        //  Allocate a send buffer if necessary.
        //
        if (pOpenContext->bRunningOnWin9x)
        {
            NdisAllocateBuffer(
                &Status,
                &pNdisBuffer,
                pOpenContext->SendBufferPool,
                pEthHeader,
                DataLength);

            if (Status != NDIS_STATUS_SUCCESS)
            {
                NPROT_RELEASE_LOCK(&pOpenContext->Lock);

                NdisFreePacket(pNdisPacket);

                DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n",
                                  pOpenContext));
                NtStatus = STATUS_INSUFFICIENT_RESOURCES;
                break;
            }
        }
        else
        {
            pNdisBuffer = pIrp->MdlAddress;
        }

        NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount);

        NPROT_REF_OPEN(pOpenContext);  // pended send

        IoMarkIrpPending(pIrp);

        //
        //  Initialize the packet ref count. This packet will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1;

#ifdef NDIS51

        //
        //  NDIS 5.1 supports cancelling sends. We set up a cancel ID on
        //  each send packet (which maps to a Write IRP), and save the
        //  packet pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendPackets() to cancel the packet.
        //

        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId);
        pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
        pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket;

        NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);

        IoSetCancelRoutine(pIrp, NdisProtCancelWrite);

#endif // NDIS51

        NPROT_RELEASE_LOCK(&pOpenContext->Lock);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp;

        NtStatus = STATUS_PENDING;

        pNdisBuffer->Next = NULL;
        NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);

#if SEND_DBG
        {
            PUCHAR      pData;

            pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority);
            NPROT_ASSERT(pEthHeader == pData);

            DEBUGP(DL_VERY_LOUD,
                   ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
                    pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));

            DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
        }
#endif // SEND_DBG

        NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        pIrp->IoStatus.Status = NtStatus;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    }

    return (NtStatus);
}
Exemplo n.º 17
0
Arquivo: sioctl.c Projeto: huyna/GHAST
NTSTATUS
SioctlDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

    This routine is called by the I/O system to perform a device I/O
    control function.

Arguments:

    DeviceObject - a pointer to the object that represents the device
        that I/O is to be done on.

    Irp - a pointer to the I/O Request Packet for this request.

Return Value:

    NT status code

--*/

{
    PIO_STACK_LOCATION  irpSp;// Pointer to current stack location
    NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success
    ULONG               inBufLength; // Input buffer length
    ULONG               outBufLength; // Output buffer length
    PCHAR               inBuf, outBuf; // pointer to Input and output buffer
    PCHAR               data = "This String is from Device Driver !!!";
    size_t              datalen = strlen(data)+1;//Length of data including null
    PMDL                mdl = NULL;
    PCHAR               buffer = NULL;

    UNREFERENCED_PARAMETER(DeviceObject);

    PAGED_CODE();

    irpSp = IoGetCurrentIrpStackLocation( Irp );
    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if (!inBufLength || !outBufLength)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        goto End;
    }

    //
    // Determine which I/O control code was specified.
    //

    switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    {
    case IOCTL_SIOCTL_METHOD_BUFFERED:

        //
        // In this method the I/O manager allocates a buffer large enough to
        // to accommodate larger of the user input buffer and output buffer,
        // assigns the address to Irp->AssociatedIrp.SystemBuffer, and
        // copies the content of the user input buffer into this SystemBuffer
        //

        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n"));
        PrintIrpInfo(Irp);

        //
        // Input buffer and output buffer is same in this case, read the
        // content of the buffer before writing to it
        //

        inBuf = Irp->AssociatedIrp.SystemBuffer;
        outBuf = Irp->AssociatedIrp.SystemBuffer;

        //
        // Read the data from the buffer
        //

        SIOCTL_KDPRINT(("\tData from User :"******"\tData to User : "******"Called IOCTL_SIOCTL_METHOD_NEITHER\n"));

        PrintIrpInfo(Irp);

        //
        // A driver may access these buffers directly if it is a highest level
        // driver whose Dispatch routine runs in the context
        // of the thread that made this request. The driver should always
        // check the validity of the user buffer's address range and check whether
        // the appropriate read or write access is permitted on the buffer.
        // It must also wrap its accesses to the buffer's address range within
        // an exception handler in case another user thread deallocates the buffer
        // or attempts to change the access rights for the buffer while the driver
        // is accessing memory.
        //

        inBuf = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
        outBuf =  Irp->UserBuffer;

        //
        // Access the buffers directly if only if you are running in the
        // context of the calling process. Only top level drivers are
        // guaranteed to have the context of process that made the request.
        //

        try {
            //
            // Before accessing user buffer, you must probe for read/write
            // to make sure the buffer is indeed an userbuffer with proper access
            // rights and length. ProbeForRead/Write will raise an exception if it's otherwise.
            //
            ProbeForRead( inBuf, inBufLength, sizeof( UCHAR ) );

            //
            // Since the buffer access rights can be changed or buffer can be freed
            // anytime by another thread of the same process, you must always access
            // it within an exception handler.
            //

            SIOCTL_KDPRINT(("\tData from User :"******"Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n",
                            ntStatus));
            break;
        }


        //
        // If you are accessing these buffers in an arbitrary thread context,
        // say in your DPC or ISR, if you are using it for DMA, or passing these buffers to the
        // next level driver, you should map them in the system process address space.
        // First allocate an MDL large enough to describe the buffer
        // and initilize it. Please note that on a x86 system, the maximum size of a buffer
        // that an MDL can describe is 65508 KB.
        //

        mdl = IoAllocateMdl(inBuf, inBufLength,  FALSE, TRUE, NULL);
        if (!mdl)
        {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        try
        {

            //
            // Probe and lock the pages of this buffer in physical memory.
            // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess
            // Always perform this operation in a try except block.
            //  MmProbeAndLockPages will raise an exception if it fails.
            //
            MmProbeAndLockPages(mdl, UserMode, IoReadAccess);
        }
        except(EXCEPTION_EXECUTE_HANDLER)
        {

            ntStatus = GetExceptionCode();
            SIOCTL_KDPRINT((
                "Exception while locking inBuf 0X%08X in METHOD_NEITHER\n",
                    ntStatus));
            IoFreeMdl(mdl);
            break;
        }

        //
        // Map the physical pages described by the MDL into system space.
        // Note: double mapping the buffer this way causes lot of
        // system overhead for large size buffers.
        //

        buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );

        if (!buffer) {
                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                MmUnlockPages(mdl);
                IoFreeMdl(mdl);
                break;
        }

        //
        // Now you can safely read the data from the buffer.
        //
        SIOCTL_KDPRINT(("\tData from User (SystemAddress) : "));
        PrintChars(buffer, inBufLength);

        //
        // Once the read is over unmap and unlock the pages.
        //

        MmUnlockPages(mdl);
        IoFreeMdl(mdl);

        //
        // The same steps can be followed to access the output buffer.
        //

        mdl = IoAllocateMdl(outBuf, outBufLength,  FALSE, TRUE, NULL);
        if (!mdl)
        {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }


        try {
            //
            // Probe and lock the pages of this buffer in physical memory.
            // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess.
            //

            MmProbeAndLockPages(mdl, UserMode, IoWriteAccess);
        }
        except(EXCEPTION_EXECUTE_HANDLER)
        {

            ntStatus = GetExceptionCode();
            SIOCTL_KDPRINT((
                "Exception while locking outBuf 0X%08X in METHOD_NEITHER\n",
                    ntStatus));
            IoFreeMdl(mdl);
            break;
        }


        buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );

        if (!buffer) {
            MmUnlockPages(mdl);
            IoFreeMdl(mdl);
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        //
        // Write to the buffer
        //

        RtlCopyBytes(buffer, data, outBufLength);

        SIOCTL_KDPRINT(("\tData to User : %s\n", buffer));
        PrintChars(buffer, datalen);

        MmUnlockPages(mdl);

        //
        // Free the allocated MDL
        //

        IoFreeMdl(mdl);

        //
        // Assign the length of the data copied to IoStatus.Information
        // of the Irp and complete the Irp.
        //

        Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);

        break;

    case IOCTL_SIOCTL_METHOD_IN_DIRECT:

        //
        // In this type of transfer,  the I/O manager allocates a system buffer
        // large enough to accommodatethe User input buffer, sets the buffer address
        // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
        // into the SystemBuffer. For the user output buffer, the  I/O manager
        // probes to see whether the virtual address is readable in the callers
        // access mode, locks the pages in memory and passes the pointer to
        // MDL describing the buffer in Irp->MdlAddress.
        //

        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_IN_DIRECT\n"));

        PrintIrpInfo(Irp);

        inBuf = Irp->AssociatedIrp.SystemBuffer;

        SIOCTL_KDPRINT(("\tData from User in InputBuffer: "));
        PrintChars(inBuf, inBufLength);

        //
        // To access the output buffer, just get the system address
        // for the buffer. For this method, this buffer is intended for transfering data
        // from the application to the driver.
        //

        buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

        if (!buffer) {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        SIOCTL_KDPRINT(("\tData from User in OutputBuffer: "));
        PrintChars(buffer, outBufLength);

        //
        // Return total bytes read from the output buffer.
        // Note OutBufLength = MmGetMdlByteCount(Irp->MdlAddress)
        //

        Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress);

        //
        // NOTE: Changes made to the  SystemBuffer are not copied
        // to the user input buffer by the I/O manager
        //

      break;

    case IOCTL_SIOCTL_METHOD_OUT_DIRECT:

        //
        // In this type of transfer, the I/O manager allocates a system buffer
        // large enough to accommodate the User input buffer, sets the buffer address
        // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
        // into the SystemBuffer. For the output buffer, the I/O manager
        // probes to see whether the virtual address is writable in the callers
        // access mode, locks the pages in memory and passes the pointer to MDL
        // describing the buffer in Irp->MdlAddress.
        //


        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_OUT_DIRECT\n"));

        PrintIrpInfo(Irp);


        inBuf = Irp->AssociatedIrp.SystemBuffer;

        SIOCTL_KDPRINT(("\tData from User : "******"\tData to User : "******"ERROR: unrecognized IOCTL %x\n",
            irpSp->Parameters.DeviceIoControl.IoControlCode));
        break;
    }

End:
    //
    // Finish the I/O operation by simply completing the packet and returning
    // the same status as in the packet itself.
    //

    Irp->IoStatus.Status = ntStatus;

    IoCompleteRequest( Irp, IO_NO_INCREMENT );

    return ntStatus;
}
Exemplo n.º 18
0
VOID
ndisprotServiceReads(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext
    )
/*++

Routine Description:

    Utility routine to copy received data into user buffers and
    complete READ IRPs.

Arguments:

    pOpenContext - pointer to open context

Return Value:

    None

--*/
{
    PIRP                pIrp = NULL;
    PLIST_ENTRY         pIrpEntry;
    PNET_BUFFER_LIST    pRcvNetBufList;
    PLIST_ENTRY         pRcvNetBufListEntry;
    PUCHAR              pSrc, pDst;
    ULONG               BytesRemaining; // at pDst
    PMDL                pMdl;
    ULONG               BytesAvailable;
    BOOLEAN             FoundPendingIrp = FALSE;
    ULONG               SrcTotalLength = 0; // Source NetBuffer DataLenght
    ULONG               Offset = 0;         // CurrentMdlOffset
    ULONG               BytesToCopy = 0;

    DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
            pOpenContext, pOpenContext->Flags));

    NPROT_REF_OPEN(pOpenContext);  // temp ref - service reads

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
           !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
    {
        FoundPendingIrp = FALSE;

        //
        //  Get the first pended Read IRP
        //
        pIrpEntry = pOpenContext->PendedReads.Flink;
        while (pIrpEntry != &pOpenContext->PendedReads)
        {
            pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);

            //
            //  Check to see if it is being cancelled.
            //
            if (IoSetCancelRoutine(pIrp, NULL))
            {
                //
                //  It isn't being cancelled, and can't be cancelled henceforth.
                //
                NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
                FoundPendingIrp = TRUE;
                break;

                //
                //  NOTE: we decrement PendedReadCount way below in the
                //  while loop, to avoid letting through a thread trying
                //  to unbind.
                //
            }
            else
            {
                //
                //  The IRP is being cancelled; let the cancel routine handle it.
                //
                DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
                        pOpenContext, pIrp));

                pIrpEntry = pIrpEntry->Flink;
            }
        }

        if (FoundPendingIrp == FALSE)
        {
            break;
        }
        //
        //  Get the first queued receive packet
        //
        pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
        NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);

        pOpenContext->RecvNetBufListCount --;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

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

        pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
        NPROT_ASSERT(pRcvNetBufList != NULL);
        _Analysis_assume_(pRcvNetBufList != NULL);
        NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;

        //
        //  Copy as much data as possible from the receive packet to
        //  the IRP MDL.
        //
        
        pDst = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority);
        NPROT_ASSERT(pDst != NULL);  // since it was already mapped
        _Analysis_assume_(pDst != NULL);

        pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        //
        // Copy the data in the received packet into the buffer provided by the client.
        // If the length of the receive packet is greater than length of the given buffer,
        // we just copy as many bytes as we can. Once the buffer is full, we just discard
        // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
        //

        SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
        Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        while (BytesRemaining && (pMdl != NULL) && SrcTotalLength)
        {
            pSrc = NULL;
            NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority);

            if (pSrc == NULL)
            {
                DEBUGP(DL_FATAL,
                    ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n",
                            pOpenContext, pMdl));
                break;
            }

            NPROT_ASSERT(BytesAvailable > Offset);

            BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining);
            BytesToCopy = MIN(BytesToCopy, SrcTotalLength);

            NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy);
            BytesRemaining -= BytesToCopy;
            pDst += BytesToCopy;
            SrcTotalLength -= BytesToCopy;

            //
            // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0.
            //
            Offset = 0;

            NdisGetNextMdl(pMdl, &pMdl);
        }

        //
        //  Complete the IRP.
        //
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;

        DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
            pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE);


        NPROT_DEREF_OPEN(pOpenContext);    // took out pended Read

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
        pOpenContext->PendedReadCount--;

    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    NPROT_DEREF_OPEN(pOpenContext);    // temp ref - service reads
}
Exemplo n.º 19
0
NTSTATUS
NICWrite(
    __in  PFDO_DATA     FdoData,
    __in  PIRP          Irp
)
/*++

Routine Description:

    This routine handles the hardware specific write request.
    If the device is not ready, fail the request. Otherwise
    get scatter-gather list for the request buffer and send the
    list to the hardware for DMA.

Arguments:

    FdoData - Pointer to the device context.
    Irp     - Pointer to the write request.

Return Value:

    NT Status code.

--*/
{
    NTSTATUS     returnStatus, status;
    PVOID        virtualAddress;
    ULONG        pageCount = 0, length = 0;
    PMDL         tempMdl, mdl;
    KIRQL        oldIrql;
#if defined(DMA_VER2)
    PVOID        sgListBuffer;
#endif

    DebugPrint(TRACE, DBG_WRITE, "--> PciDrvWrite %p\n", Irp);

    Irp->Tail.Overlay.DriverContext[3] = NULL;
    Irp->Tail.Overlay.DriverContext[2] = NULL;
    returnStatus = status = STATUS_SUCCESS;

    //
    // Is this adapter ready for sending?
    //
    if (MP_SHOULD_FAIL_SEND(FdoData))
    {
        DebugPrint(ERROR, DBG_WRITE, "Device not ready %p\n", Irp);
        returnStatus = status = STATUS_DEVICE_NOT_READY;
        goto Error;
    }

    tempMdl = mdl = Irp->MdlAddress;

    //
    // Check for zero length buffer
    //
    if (mdl == NULL || MmGetMdlByteCount(mdl) == 0)
     {
        DebugPrint(ERROR, DBG_WRITE, "Zero length buffer %p\n", Irp);
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }

    //
    // Calculate the total packet length and the number of pages
    // spanned by all the buffers by walking the MDL chain.
    // NOTE: If this driver is used in the miniport configuration, it will
    // not get chained MDLs because the upper filter (NDISEDGE.SYS)
    // coalesces the fragements to a single contiguous buffer before presenting
    // the packet to us.
    //
    while(tempMdl != NULL)
    {
        virtualAddress = MmGetMdlVirtualAddress(tempMdl);
        length += MmGetMdlByteCount(tempMdl);
        pageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, length);
        tempMdl = tempMdl->Next;
    }

    if (length < NIC_MIN_PACKET_SIZE)
    {
        //
        // This will never happen in our case because the ndis-edge
        // pads smaller size packets with zero to make it NIC_MIN_PACKET_SIZE
        // long.
        //
        DebugPrint(ERROR, DBG_WRITE, "Packet size is less than %d\n", NIC_MIN_PACKET_SIZE);
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }

    //
    // Check to see if the packet spans more than the physical pages
    // our hardware can handle or the pageCount exceeds the total number of
    // map registers allocated. If so, we should coalesce the scattered
    // buffers to fit the limit. We can't really break the transfers and
    // DMA in small chunks because each packets has to be DMA'ed in one shot.
    // The code on how to colesce the packet for this hardware is present
    // in the original E100BEX sample.
    //
    if (pageCount > NIC_MAX_PHYS_BUF_COUNT ||
            pageCount > FdoData->AllocatedMapRegisters)
    {
        // TODO: Packet needs to be coalesced
        DebugPrint(ERROR, DBG_WRITE, "Packet needs to be coalesced\n");
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }
    //
    // Build a scatter-gather list of the packet buffer and send the packet.
    //
    // If DMA_VER2 is not defined, use GetScatterGatherList. If the driver
    // is meant to work on XP and above, define DMA_VER2, so that you can
    // use BuildScatterGatherList.
    //
    // Since Build/GetScatterGatherList should be called at DISPATCH_LEVEL
    // let us raise the IRQL.
    //

    KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

    //
    // Let us mark the IRP pending, because NICProcessSGList is an asynchronous
    // callback and we wouldn't know the status of the IRP. This IRP may either
    // get completed by the DPC handler after the DMA transfer or may
    // get queued if we are low on resources. So the safest thing
    // to do for us here is return STATUS_PENDING irrespective of what happens
    // to the IRP.
    //
    IoMarkIrpPending(Irp);
    returnStatus = STATUS_PENDING;

#if defined(DMA_VER2)

    sgListBuffer = ExAllocateFromNPagedLookasideList(
                            &FdoData->SGListLookasideList);
    if (sgListBuffer)
    {
        Irp->Tail.Overlay.DriverContext[2] =  sgListBuffer;
        status = FdoData->DmaAdapterObject->DmaOperations->BuildScatterGatherList(
                        FdoData->DmaAdapterObject,
                        FdoData->Self,
                        mdl,
                        MmGetMdlVirtualAddress(mdl),
                        length,
                        NICProcessSGList,
                        Irp,
                        TRUE,
                        sgListBuffer,
                        FdoData->ScatterGatherListSize);

        if (!NT_SUCCESS(status))
        {
            DebugPrint(ERROR, DBG_WRITE, "BuildScatterGatherList %x\n", status);
            ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sgListBuffer);
            Irp->Tail.Overlay.DriverContext[2] =  NULL;
        }
    }

#else

    status = FdoData->DmaAdapterObject->DmaOperations->GetScatterGatherList(
                    FdoData->DmaAdapterObject,
                    FdoData->Self,
                    mdl,
                    MmGetMdlVirtualAddress(mdl),
                    length,
                    NICProcessSGList,
                    Irp,
                    TRUE);

    if (!NT_SUCCESS(status))
    {
        DebugPrint(ERROR, DBG_WRITE, "GetScatterGatherList %x\n", status);
    }

#endif

    KeLowerIrql(oldIrql);

Error:
    if(!NT_SUCCESS(status)){
        //
        // Our call to get the scatter-gather list failed. We know the
        // NICProcessSGList is not called for sure in that case. So let us
        // complete the IRP here with failure status. Since we marked the
        // IRP pending, we have no choice but to return status-pending
        // even though we are completing the IRP in the incoming thread
        // context.
        //
        NICCompleteSendRequest(FdoData, Irp, status, 0, FALSE);
    }

    DebugPrint(LOUD, DBG_WRITE, "<-- PciDrvWrite %x\n", returnStatus);

    return returnStatus;
}
Exemplo n.º 20
0
VOID
NICWritePacket(
    __in  PFDO_DATA   FdoData,
    __in  PIRP        Irp,
    __in  BOOLEAN     bFromQueue
    )
/*++
Routine Description:

    Do the work to send a packet
    Assumption: Send spinlock has been acquired

Arguments:

    FdoData     Pointer to our FdoData
    Packet      The packet
    bFromQueue  TRUE if it's taken from the send wait queue

Return Value:

--*/
{
    PMP_TCB         pMpTcb = NULL;
    ULONG           packetLength;
    PVOID           virtualAddress;

    DebugPrint(TRACE, DBG_WRITE, "--> NICWritePacket, Irp= %p\n", Irp);

    //
    // Get the next free TCB and initialize it to represent the
    // request buffer.
    //
    pMpTcb = FdoData->CurrSendTail;
    ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));

    //
    // If the adapter is not ready, fail the request.
    //
    if(MP_IS_NOT_READY(FdoData)) {
        MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_DEVICE_NOT_READY);
        return;
    }

    pMpTcb->FirstBuffer = Irp->MdlAddress;
    virtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress);
    pMpTcb->BufferCount = 1;
    pMpTcb->PacketLength = packetLength = MmGetMdlByteCount(Irp->MdlAddress);
    pMpTcb->PhysBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress,
                                            packetLength);
    pMpTcb->Irp = Irp;
    MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);

    //
    // Call the send handler, it only needs to deal with the frag list
    //
    NICSendPacket(FdoData, pMpTcb, Irp->Tail.Overlay.DriverContext[3]);

    FdoData->nBusySend++;
    ASSERT(FdoData->nBusySend <= FdoData->NumTcb);
    FdoData->CurrSendTail = FdoData->CurrSendTail->Next;

    DebugPrint(TRACE, DBG_WRITE, "<-- NICWritePacket\n");
    return;

}
Exemplo n.º 21
0
NTSTATUS
NbfTdiAction(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PIRP Irp
)

/*++

Routine Description:

    This routine performs the TdiAction request for the transport
    provider.

Arguments:

    DeviceContext - The device context for the operation

    Irp - the Irp for the requested operation.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    NTSTATUS status;
    PIO_STACK_LOCATION irpSp;
    PTDI_ACTION_HEADER ActionHeader;
    LARGE_INTEGER timeout = {0,0};
    PTP_REQUEST tpRequest;
    KIRQL oldirql, cancelirql;
    ULONG BytesRequired;

    //
    // what type of status do we want?
    //

    irpSp = IoGetCurrentIrpStackLocation (Irp);

    if ((!Irp->MdlAddress) ||
            (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(TDI_ACTION_HEADER))) {
        return STATUS_INVALID_PARAMETER;
    }

    ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

    if (!ActionHeader) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Make sure we have required number of bytes for this type of request
    //

    switch (ActionHeader->ActionCode) {

    case QUERY_INDICATION_CODE:
        BytesRequired = sizeof(ACTION_QUERY_INDICATION);
        break;

    case DATAGRAM_INDICATION_CODE:
        BytesRequired = sizeof(ACTION_DATAGRAM_INDICATION);
        break;

    default:
        return STATUS_NOT_IMPLEMENTED;
    }

    if (MmGetMdlByteCount(Irp->MdlAddress) < BytesRequired) {
        return STATUS_INVALID_PARAMETER;
    }

    //
    // Here the request is one of QUERY_INDICATION or DATAGRAM_INDICATION
    //

    //
    // These two requests are sent by RAS to "MABF"
    //

    if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
        return STATUS_NOT_SUPPORTED;
    }

    //
    // They should be sent on the control channel
    //

    if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) {
        return STATUS_NOT_SUPPORTED;
    }


    //
    // Create a request to describe this.
    //

    status = NbfCreateRequest (
                 Irp,                           // IRP for this request.
                 DeviceContext,                 // context.
                 REQUEST_FLAGS_DC,              // partial flags.
                 Irp->MdlAddress,
                 MmGetMdlByteCount(Irp->MdlAddress),
                 timeout,
                 &tpRequest);

    if (NT_SUCCESS (status)) {

        NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
        tpRequest->Owner = DeviceContextType;
        tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;

        IoAcquireCancelSpinLock(&cancelirql);
        ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);

        //
        // Disallow these requests on a stopping device.
        //

        if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {

            RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
            IoReleaseCancelSpinLock(cancelirql);
            NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);

        } else {

            if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {

                InsertTailList (
                    &DeviceContext->QueryIndicationQueue,
                    &tpRequest->Linkage);

            } else {

                InsertTailList (
                    &DeviceContext->DatagramIndicationQueue,
                    &tpRequest->Linkage);

            }

            DeviceContext->IndicationQueuesInUse = TRUE;


            //
            // If this IRP has been cancelled, then call the
            // cancel routine.
            //

            if (Irp->Cancel) {
                RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
                Irp->CancelIrql = cancelirql;
                NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
                return STATUS_PENDING;
            }

            IoSetCancelRoutine(Irp, NbfCancelAction);

            RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
            IoReleaseCancelSpinLock(cancelirql);

        }

        status = STATUS_PENDING;

    }

    return status;

}
Exemplo n.º 22
0
NTSTATUS DispTdiQueryInformation(
  PDEVICE_OBJECT DeviceObject,
  PIRP Irp)
/*
 * FUNCTION: TDI_QUERY_INFORMATION handler
 * ARGUMENTS:
 *     DeviceObject = Pointer to device object structure
 *     Irp          = Pointer to an I/O request packet
 * RETURNS:
 *     Status of operation
 */
{
  PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
  PTRANSPORT_CONTEXT TranContext;
  PIO_STACK_LOCATION IrpSp;

  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));

  IrpSp = IoGetCurrentIrpStackLocation(Irp);
  Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;

  TranContext = IrpSp->FileObject->FsContext;
  if (!TranContext) {
    TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
    return STATUS_INVALID_PARAMETER;
  }

  switch (Parameters->QueryType)
  {
    case TDI_QUERY_ADDRESS_INFO:
      {
        PTDI_ADDRESS_INFO AddressInfo;
        PADDRESS_FILE AddrFile;
        PTA_IP_ADDRESS Address;
        PCONNECTION_ENDPOINT Endpoint = NULL;


        if (MmGetMdlByteCount(Irp->MdlAddress) <
            (FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) +
             sizeof(TDI_ADDRESS_IP))) {
          TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
          return STATUS_BUFFER_TOO_SMALL;
        }

        AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress);
		Address = (PTA_IP_ADDRESS)&AddressInfo->Address;

        switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
          case TDI_TRANSPORT_ADDRESS_FILE:
            AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;

			Address->TAAddressCount = 1;
			Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
			Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
			Address->Address[0].Address[0].sin_port = AddrFile->Port;
			Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address;
			RtlZeroMemory(
				&Address->Address[0].Address[0].sin_zero,
				sizeof(Address->Address[0].Address[0].sin_zero));
			return STATUS_SUCCESS;

          case TDI_CONNECTION_FILE:
            Endpoint =
				(PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;

            Address->TAAddressCount = 1;
            Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
            Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
            Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port;
            Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address;
			RtlZeroMemory(
				&Address->Address[0].Address[0].sin_zero,
				sizeof(Address->Address[0].Address[0].sin_zero));
            return STATUS_SUCCESS;

          default:
            TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
            return STATUS_INVALID_PARAMETER;
        }
      }

    case TDI_QUERY_CONNECTION_INFO:
      {
        PTDI_CONNECTION_INFO ConnectionInfo;
        //PCONNECTION_ENDPOINT Endpoint;

        if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) {
          TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
          return STATUS_BUFFER_TOO_SMALL;
        }

        ConnectionInfo = (PTDI_CONNECTION_INFO)
          MmGetSystemAddressForMdl(Irp->MdlAddress);

        switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
          case TDI_CONNECTION_FILE:
            //Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
            RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo));
            return STATUS_SUCCESS;

          default:
            TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
            return STATUS_INVALID_PARAMETER;
        }
      }

      case TDI_QUERY_MAX_DATAGRAM_INFO:
      {
          PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo;

          if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) {
              TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
              return STATUS_BUFFER_TOO_SMALL;
          }

          MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO)
            MmGetSystemAddressForMdl(Irp->MdlAddress);

          MaxDatagramInfo->MaxDatagramSize = 0xFFFF;

          return STATUS_SUCCESS;
     }
  }

  return STATUS_NOT_IMPLEMENTED;
}
Exemplo n.º 23
0
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
    AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */

    /*
     * Try see if we get lucky first...
     * (We could probably just assume we're lucky on NT4.)
     */
    int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable);
    if (RT_SUCCESS(rc))
    {
        size_t iPage = cb >> PAGE_SHIFT;
        while (iPage-- > 0)
            if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G)
            {
                rc = VERR_NO_LOW_MEMORY;
                break;
            }
        if (RT_SUCCESS(rc))
            return rc;

        /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */
        RTR0MemObjFree(*ppMem, false);
        *ppMem = NULL;
    }

#ifndef IPRT_TARGET_NT4
    /*
     * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use.
     */
    PHYSICAL_ADDRESS Zero;
    Zero.QuadPart = 0;
    PHYSICAL_ADDRESS HighAddr;
    HighAddr.QuadPart = _4G - 1;
    PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
    if (pMdl)
    {
        if (MmGetMdlByteCount(pMdl) >= cb)
        {
            __try
            {
                void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */,
                                                        FALSE /* no bug check on failure */, NormalPagePriority);
                if (pv)
                {
                    PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb);
                    if (pMemNt)
                    {
                        pMemNt->fAllocatedPagesForMdl = true;
                        pMemNt->cMdls = 1;
                        pMemNt->apMdls[0] = pMdl;
                        *ppMem = &pMemNt->Core;
                        return VINF_SUCCESS;
                    }
                    MmUnmapLockedPages(pv, pMdl);
                }
            }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
                NTSTATUS rcNt = GetExceptionCode();
                Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt));
                /* nothing */
            }
        }
        MmFreePagesFromMdl(pMdl);
        ExFreePool(pMdl);
    }
Exemplo n.º 24
0
VOID
BalloonFill(
    IN WDFOBJECT WdfDevice,
    IN size_t num)
{
    PMDL                pPageMdl;
    PHYSICAL_ADDRESS    LowAddress;
    PHYSICAL_ADDRESS    HighAddress;
    PPAGE_LIST_ENTRY    pNewPageListEntry;
    PDEVICE_CONTEXT     devCtx = GetDeviceContext(WdfDevice);
    ULONG               pages_per_request = PAGE_SIZE/sizeof(PFN_NUMBER);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);

    LowAddress.QuadPart = 0;
    HighAddress.QuadPart = (ULONGLONG)-1;

    num = min(num, pages_per_request);
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> BalloonFill num = %d\n", num);

    for (devCtx->num_pfns = 0; devCtx->num_pfns < num; devCtx->num_pfns++)
    {
        if(IsLowMemory(WdfDevice))
        {
           TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
                "LowMemoryCondition event was set to signaled,allocations stops, BalPageCount=%d\n", devCtx->num_pages);
           break;
        }
        pPageMdl = MmAllocatePagesForMdl(
                                        LowAddress,
                                        HighAddress,
                                        LowAddress,
                                        PAGE_SIZE
                                        );
        if (pPageMdl == NULL)
        {
            TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
                 "Balloon MDL Page Allocation Failed!!!, BalPageCount=%d\n", devCtx->num_pages);
            break;
        }

        if (MmGetMdlByteCount(pPageMdl) != PAGE_SIZE)
        {
            TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS,
                 "Balloon MDL Page Allocation < PAGE_SIZE =%d, Failed!!!, BalPageCount=%d\n",MmGetMdlByteCount(pPageMdl), devCtx->num_pages);
            MmFreePagesFromMdl(pPageMdl);
            ExFreePool(pPageMdl);
            break;
        }

        pNewPageListEntry = (PPAGE_LIST_ENTRY)ExAllocateFromNPagedLookasideList(&devCtx->LookAsideList);
        if (pNewPageListEntry == NULL)
        {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "List Entry Allocation Failed!!!\n");
            MmFreePagesFromMdl(pPageMdl);
            ExFreePool(pPageMdl);
            break;
        }

        pNewPageListEntry->PageMdl = pPageMdl;
        pNewPageListEntry->PagePfn = devCtx->pfns_table[devCtx->num_pfns] = *MmGetMdlPfnArray(pPageMdl);

        PushEntryList(&devCtx->PageListHead, &(pNewPageListEntry->SingleListEntry));
        devCtx->num_pages++;
    }

    if (devCtx->num_pfns > 0)
    {
        BalloonTellHost(WdfDevice, devCtx->InfVirtQueue);
    }
}
Exemplo n.º 25
0
NTSTATUS DispTdiQueryInformationEx(
    PIRP Irp,
    PIO_STACK_LOCATION IrpSp)
/*
 * FUNCTION: TDI QueryInformationEx handler
 * ARGUMENTS:
 *     Irp   = Pointer to I/O request packet
 *     IrpSp = Pointer to current stack location of Irp
 * RETURNS:
 *     Status of operation
 */
{
    PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
    PTRANSPORT_CONTEXT TranContext;
    PTI_QUERY_CONTEXT QueryContext;
    PVOID OutputBuffer;
    TDI_REQUEST Request;
    UINT Size;
    UINT InputBufferLength;
    UINT OutputBufferLength;
    BOOLEAN InputMdlLocked  = FALSE;
    BOOLEAN OutputMdlLocked = FALSE;
    PMDL InputMdl           = NULL;
    PMDL OutputMdl          = NULL;
    NTSTATUS Status         = STATUS_SUCCESS;

    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));

    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;

    switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
    case TDI_TRANSPORT_ADDRESS_FILE:
        Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
        break;

    case TDI_CONNECTION_FILE:
        Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
        break;

    case TDI_CONTROL_CHANNEL_FILE:
        Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
        break;

    default:
        TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
        return STATUS_INVALID_PARAMETER;
    }

    InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
    OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    /* Validate parameters */
    if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
        (OutputBufferLength != 0)) {

        InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
            IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
        OutputBuffer = Irp->UserBuffer;

        QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
        if (QueryContext) {
	    _SEH2_TRY {
                InputMdl = IoAllocateMdl(InputBuffer,
                    sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
                    FALSE, TRUE, NULL);

                OutputMdl = IoAllocateMdl(OutputBuffer,
                    OutputBufferLength, FALSE, TRUE, NULL);

                if (InputMdl && OutputMdl) {

                    MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
                        IoModifyAccess);

                    InputMdlLocked = TRUE;

                    MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
                        IoWriteAccess);

                    OutputMdlLocked = TRUE;

                    RtlCopyMemory(&QueryContext->QueryInfo,
                        InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
                } else
                    Status = STATUS_INSUFFICIENT_RESOURCES;
            } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
                Status = _SEH2_GetExceptionCode();
            } _SEH2_END;

            if (NT_SUCCESS(Status)) {
                Size = MmGetMdlByteCount(OutputMdl);

                QueryContext->Irp       = Irp;
                QueryContext->InputMdl  = InputMdl;
                QueryContext->OutputMdl = OutputMdl;

                Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
                Request.RequestContext      = QueryContext;
                Status = InfoTdiQueryInformationEx(&Request,
                    &QueryContext->QueryInfo.ID, OutputMdl,
                    &Size, &QueryContext->QueryInfo.Context);
                DispTdiQueryInformationExComplete(QueryContext, Status, Size);

                TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));

                return Status;
            }

            /* An error occurred if we get here */

            if (InputMdl) {
                if (InputMdlLocked)
                    MmUnlockPages(InputMdl);
                IoFreeMdl(InputMdl);
            }

            if (OutputMdl) {
                if (OutputMdlLocked)
                    MmUnlockPages(OutputMdl);
                IoFreeMdl(OutputMdl);
            }

            ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
        } else
Exemplo n.º 26
0
VOID
LoopCopyData (
    IN PMDL Destination,
    IN PMDL Source,
    IN ULONG Length
    )

/*++

Routine Description:

    This routine copies data from the storage described by one MDL chain
    into the storage described by another MDL chain.

Arguments:

    Destination - Pointer to first MDL in Destination chain

    Source - Pointer to first MDL in Source chain

    Length - Amount of data to copy.  Caller must ensure that the Source
        and Destination chains are at least this long.

Return Value:

    None.

--*/

{
    PCHAR sourceAddress;
    ULONG sourceLength;

    PCHAR destinationAddress;
    ULONG destinationLength;

    ULONG copyLength;

    //
    // Get the virtual address of the first source buffer, mapping it
    // if necessary.  Also get the length of the buffer.
    //

    sourceAddress = MmGetSystemAddressForMdl( Source );
    sourceLength = MmGetMdlByteCount( Source );

    //
    // Get the virtual address of the first destination buffer, mapping
    // it if necessary.  Also get the length of the buffer.
    //

    destinationAddress = MmGetSystemAddressForMdl( Destination );
    destinationLength = MmGetMdlByteCount( Destination );

    //
    // Loop copying data.
    //

    do {

        //
        // The amount to copy in this pass is the minimum of 1) the
        // amount remaining in the current source buffer, 2) the amount
        // remaining in the current destination buffer, and 3) the
        // amount remaining in the overall copy operation.
        //

        copyLength = sourceLength;
        if ( copyLength > destinationLength ) copyLength = destinationLength;
        if ( copyLength > Length ) copyLength = Length;

        //
        // Copy from the source buffer into the destination buffer.
        //

#ifndef TIMING
        IF_DEBUG(LOOP4) {
            DbgPrint( "      copying %lx bytes from %lx to %lx\n",
                        copyLength, sourceAddress, destinationAddress );
            DbgPrint( "      source data: %lx, %lx\n",
                        *(PULONG)sourceAddress, *((PULONG)sourceAddress + 1) );
        }
        RtlMoveMemory( destinationAddress, sourceAddress, copyLength );
#else
        if ( (NtGlobalFlag & 0x20000000) == 0 ) {
            RtlMoveMemory( destinationAddress, sourceAddress, copyLength );
        } else {
            RtlMoveMemory(
                destinationAddress,
                sourceAddress,
                (copyLength > 200) ? 200 : copyLength
                );
        }
#endif

        //
        // If all of the requested data has been copied, leave.
        //

        Length -= copyLength;

        if ( Length == 0 ) {

            return;

        }

        //
        // If we have used up all of the current source buffer, move to
        // the next buffer.  Get the virtual address of the next buffer,
        // mapping it if necessary.  Also get the length of the buffer.
        // If we haven't used up the current source buffer, simply
        // update the source pointer and the remaining length.
        //

        if ( copyLength == sourceLength ) {

            Source = Source->Next;

            sourceAddress = MmGetSystemAddressForMdl( Source );
            sourceLength = MmGetMdlByteCount( Source );

        } else {

            sourceAddress += copyLength;
            sourceLength -= copyLength;

        }

        //
        // If we have used up all of the current destination buffer,
        // move to the next buffer.  Get the virtual address of the next
        // buffer, mapping it if necessary.  Also get the length of the
        // buffer.  If we haven't used up the current destination
        // buffer, simply update the destination pointer and the
        // remaining length.
        //

        if ( copyLength == destinationLength ) {

            Destination = Destination->Next;

            destinationAddress = MmGetSystemAddressForMdl( Destination );
            destinationLength = MmGetMdlByteCount( Destination );

        } else {

            destinationAddress += copyLength;
            destinationLength -= copyLength;

        }

    } while ( TRUE );

    //
    // Can't get here.
    //

    ASSERTMSG( FALSE, "Can't get here!" );

} // LoopCopyData
Exemplo n.º 27
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;
}
Exemplo n.º 28
0
static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEGER diskWriteOffset, PMDL writeMdl)
{
	ULONG dataLength = MmGetMdlByteCount (writeMdl);
	uint64 offset = DumpPartitionOffset.QuadPart + diskWriteOffset->QuadPart;
	uint64 intersectStart;
	uint32 intersectLength;
	PVOID writeBuffer;
	CSHORT origMdlFlags;

	if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER)
		TC_BUG_CHECK (STATUS_CRC_ERROR);

	if (BootDriveFilterExtension->Queue.EncryptedAreaEndUpdatePending)	// Hibernation should always abort the setup thread
		TC_BUG_CHECK (STATUS_INVALID_PARAMETER);

	if (BootDriveFilterExtension->Queue.EncryptedAreaStart == -1 || BootDriveFilterExtension->Queue.EncryptedAreaEnd == -1)
		return STATUS_SUCCESS;

	if (dataLength > WriteFilterBufferSize)
		TC_BUG_CHECK (STATUS_BUFFER_OVERFLOW);	// Bug check is required as returning an error does not prevent data from being written to disk

	if ((dataLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
		TC_BUG_CHECK (STATUS_INVALID_PARAMETER);

	if ((offset & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
		TC_BUG_CHECK (STATUS_INVALID_PARAMETER);

	writeBuffer = MmGetSystemAddressForMdlSafe (writeMdl, HighPagePriority);
	if (!writeBuffer)
		TC_BUG_CHECK (STATUS_INSUFFICIENT_RESOURCES);

	memcpy (WriteFilterBuffer, writeBuffer, dataLength);

	GetIntersection (offset,
		dataLength,
		BootDriveFilterExtension->Queue.EncryptedAreaStart,
		BootDriveFilterExtension->Queue.EncryptedAreaEnd,
		&intersectStart,
		&intersectLength);

	if (intersectLength > 0)
	{
		UINT64_STRUCT dataUnit;
		dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;

		if (BootDriveFilterExtension->Queue.RemapEncryptedArea)
		{
			diskWriteOffset->QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset;
			dataUnit.Value += BootDriveFilterExtension->Queue.RemappedAreaDataUnitOffset;
		}

		EncryptDataUnitsCurrentThread (WriteFilterBuffer + (intersectStart - offset),
			&dataUnit,
			intersectLength / ENCRYPTION_DATA_UNIT_SIZE,
			BootDriveFilterExtension->Queue.CryptoInfo);
	}

	origMdlFlags = writeMdl->MdlFlags;

	MmInitializeMdl (writeMdl, WriteFilterBuffer, dataLength);
	MmBuildMdlForNonPagedPool (writeMdl);

	// Instead of using MmGetSystemAddressForMdlSafe(), some buggy custom storage drivers may directly test MDL_MAPPED_TO_SYSTEM_VA flag,
	// disregarding the fact that other MDL flags may be set by the system or a dump filter (e.g. MDL_SOURCE_IS_NONPAGED_POOL flag only).
	// Therefore, to work around this issue, the original flags will be restored even if they do not match the new MDL.
	// MS BitLocker also uses this hack/workaround (it should be safe to use until the MDL structure is changed).

	writeMdl->MdlFlags = origMdlFlags;

	return STATUS_SUCCESS;
}
Exemplo n.º 29
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;
}
Exemplo n.º 30
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;
}