www.pudn.com > ntsniff.zip > READ.C


/* 
 *  NtSniff by Davide Libenzi ( To rebuild NtSniff You need Microsoft SDK & DDK ) 
 *  Copyright (C) 1999  Davide Libenzi 
 * 
 *  This program is free software; you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation; either version 2 of the License, or 
 *  (at your option) any later version. 
 * 
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details. 
 * 
 *  You should have received a copy of the GNU General Public License 
 *  along with this program; if not, write to the Free Software 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 * 
 *  Davide Libenzi  
 * 
 */ 
 
 
#include "stdarg.h" 
#include "ntddk.h" 
#include "ntiologc.h" 
#include "ndis.h" 
 
#include "debug.h" 
#include "packet.h" 
 
 
 
 
VOID 
PacketCancelRoutine ( 
    IN PDEVICE_OBJECT   DeviceObject, 
    IN PIRP             Irp 
    ); 
 
NTSTATUS 
PacketRead( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
    ) 
 
/*++ 
 
Routine Description: 
 
    This is the dispatch routine for read requests. 
  
 
Arguments: 
 
    DeviceObject - Pointer to the device object. 
 
    Irp - Pointer to the request packet. 
 
Return Value: 
 
    Status is returned. 
 
--*/ 
 
{ 
    POPEN_INSTANCE      Open; 
    PIO_STACK_LOCATION  IrpSp; 
    PNDIS_PACKET        pPacket; 
    PMDL                pMdl; 
    NDIS_STATUS         Status; 
    NTSTATUS            ntStatus; 
     
 
    IF_LOUD(DbgPrint("Packet: Read\n");) 
 
    IrpSp = IoGetCurrentIrpStackLocation(Irp); 
 
    Open=IrpSp->FileObject->FsContext; 
 
    IoIncrement(Open); 
 
    // 
    //  See if the buffer is atleast big enough to hold the 
    //  ethernet header 
    // 
    if (IrpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) { 
 
        ntStatus = STATUS_BUFFER_TOO_SMALL; 
        goto Error; 
    } 
 
    // 
    //  Allocate an MDL to map the portion of the buffer following the 
    //  header 
    // 
    pMdl=IoAllocateMdl( 
              MmGetMdlVirtualAddress(Irp->MdlAddress), 
              MmGetMdlByteCount(Irp->MdlAddress), 
              FALSE, 
              FALSE, 
              NULL 
              ); 
 
 
    if (pMdl == NULL) { 
        IF_LOUD(DbgPrint("Packet: Read-Failed to allocate Mdl\n");) 
        ntStatus = STATUS_INSUFFICIENT_RESOURCES; 
        goto Error; 
    } 
 
    // 
    //  Build the mdl to point to the the portion of the buffer following 
    //  the header 
    // 
    IoBuildPartialMdl( 
        Irp->MdlAddress, 
        pMdl, 
        ((PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress))+ETHERNET_HEADER_LENGTH, 
        0 
        ); 
 
    // 
    //  Clear the next link in the new MDL 
    // 
    pMdl->Next=NULL; 
 
    // 
    //  Try to get a packet from our list of free ones 
    // 
 
    NdisAllocatePacket( 
        &Status, 
        &pPacket, 
        Open->PacketPool 
        ); 
 
    if (Status != NDIS_STATUS_SUCCESS) { 
        IF_LOUD(DbgPrint("Packet: Read- No free packets\n");) 
 
        IoFreeMdl(pMdl); 
        ntStatus = STATUS_INSUFFICIENT_RESOURCES; 
        goto Error; 
    } 
 
    // 
    //  Get a pointer to the packet itself 
    // 
 
    RESERVED(pPacket)->Irp=Irp; 
    RESERVED(pPacket)->pMdl=pMdl; 
 
    IoMarkIrpPending(Irp); 
 
    // 
    //  Attach our new MDL to the packet 
    // 
    NdisChainBufferAtFront(pPacket,pMdl); 
 
    // 
    //  Put this packet in a list of pending reads. 
    //  The receive indication handler will attempt to remove packets 
    //  from this list for use in transfer data calls 
    // 
    ExInterlockedInsertTailList( 
        &Open->RcvList, 
        &RESERVED(pPacket)->ListElement, 
        &Open->RcvQSpinLock); 
 
    IoSetCancelRoutine(Irp, PacketCancelRoutine); 
 
    return(STATUS_PENDING); 
 
Error: 
    Irp->IoStatus.Status = ntStatus; 
    IoCompleteRequest (Irp, IO_NO_INCREMENT); 
    IoDecrement(Open); 
    return ntStatus; 
 
} 
 
 
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; 
    ULONG               BufferLength; 
 
    PPACKET_RESERVED    Reserved; 
 
    IF_LOUD(DbgPrint("Packet: 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) { 
 
        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); 
    IoSetCancelRoutine(Irp, NULL); 
 
    // 
    //  This is the length of our partial MDL 
    // 
    BufferLength=IrpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH; 
 
    // 
    //  Find out how much to transfer 
    // 
    SizeToTransfer = (PacketSize < BufferLength) ? 
                       PacketSize : BufferLength; 
 
    // 
    //  copy the ethernet header into the actual readbuffer 
    // 
    NdisMoveMappedMemory( 
        MmGetSystemAddressForMdl(Irp->MdlAddress), 
        HeaderBuffer, 
        HeaderBufferSize 
        ); 
 
    // 
    //  Call the Mac to transfer the packet 
    // 
 
    NdisTransferData( 
        &Status, 
        Open->AdapterHandle, 
        MacReceiveContext, 
        0, 
        SizeToTransfer, 
        pPacket, 
        &BytesTransfered); 
 
    if (Status != NDIS_STATUS_PENDING) { 
 
        // 
        //  If it didn't pend, call the completion routine now 
        // 
        PacketTransferDataComplete( 
            Open, 
            pPacket, 
            Status, 
            BytesTransfered 
            ); 
 
 
    } 
 
    return NDIS_STATUS_SUCCESS; 
 
} 
 
VOID 
PacketTransferDataComplete ( 
    IN NDIS_HANDLE   ProtocolBindingContext, 
    IN PNDIS_PACKET  pPacket, 
    IN NDIS_STATUS   Status, 
    IN UINT          BytesTransfered 
    ) 
 
{ 
    PIO_STACK_LOCATION   IrpSp; 
    POPEN_INSTANCE       Open; 
    PIRP                 Irp; 
    PMDL                 pMdl; 
 
    IF_LOUD(DbgPrint("Packet: TransferDataComplete\n");) 
 
    Open= (POPEN_INSTANCE)ProtocolBindingContext; 
 
    Irp=RESERVED(pPacket)->Irp; 
 
    IrpSp = IoGetCurrentIrpStackLocation(Irp); 
 
    pMdl=RESERVED(pPacket)->pMdl; 
 
    // 
    //  Free the MDL that we allocated 
    // 
    IoFreeMdl(pMdl); 
 
    // 
    //  Put the packet on the free queue 
    // 
    NdisFreePacket(pPacket); 
 
    if(Status == NDIS_STATUS_SUCCESS) 
    { 
        Irp->IoStatus.Status = STATUS_SUCCESS; 
        Irp->IoStatus.Information = BytesTransfered+ETHERNET_HEADER_LENGTH; 
    } else { 
     
        Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 
        Irp->IoStatus.Information = 0; 
    } 
 
    IF_LOUD(DbgPrint("Packet: BytesTransfered:%d\n", Irp->IoStatus.Information);) 
 
    IoCompleteRequest(Irp, IO_NO_INCREMENT); 
    IoDecrement(Open); 
 
    return; 
 
 
} 
 
 
 
VOID 
PacketReceiveComplete( 
    IN NDIS_HANDLE  ProtocolBindingContext 
    ) 
 
{ 
 
    return; 
 
} 
 
VOID 
PacketCancelRoutine ( 
    IN PDEVICE_OBJECT   DeviceObject, 
    IN PIRP             Irp 
    ) 
 
/*++ 
 
Routine Description: 
 
    The cancel routine. It will remove the IRP from the queue  
    and will complete it. The cancel spin lock is already acquired  
    when this routine is called. 
 
Arguments: 
 
    DeviceObject - pointer to the device object. 
     
    Irp - pointer to the IRP to be cancelled. 
     
     
Return Value: 
 
    VOID. 
 
--*/ 
{ 
 
    POPEN_INSTANCE      open;  
    KIRQL               oldIrql; 
    PIRP                irpToComplete = NULL; 
    PLIST_ENTRY         thisEntry, nextEntry, listHead; 
    PIRP                pendingIrp; 
    PNDIS_PACKET        myPacket; 
    PPACKET_RESERVED    reserved; 
    PMDL                mdl; 
    PIO_STACK_LOCATION  irpSp; 
 
    IF_LOUD(DbgPrint("Packet: PacketCancelRoutine\n");) 
 
    irpSp = IoGetCurrentIrpStackLocation(Irp); 
 
    open=irpSp->FileObject->FsContext; 
 
    // 
    // Don't assume that the IRP being cancelled is in the queue. 
    // Only complete the IRP if it IS in the queue. 
    // 
    // 
    // Must acquire the local spinlock before releasing  
    // the global cancel spinlock 
    // 
 
    oldIrql = Irp->CancelIrql; 
     
    KeAcquireSpinLockAtDpcLevel(&open->RcvQSpinLock); 
 
    IoReleaseCancelSpinLock( KeGetCurrentIrql() ); 
 
    // 
    // Remove the IRP from the queue 
    // 
    listHead = &open->RcvList; 
     
    for(thisEntry = listHead->Flink;  
        thisEntry != listHead; 
        thisEntry = thisEntry->Flink) 
    { 
 
        reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); 
        myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); 
        pendingIrp = RESERVED(myPacket)->Irp; 
 
        if (pendingIrp == Irp)  
        { 
                RemoveEntryList(thisEntry); 
                irpToComplete = pendingIrp; 
                break; 
        } 
       
    } 
     
    // 
    // Release the queue spinlock 
    // 
 
    KeReleaseSpinLock(&open->RcvQSpinLock, oldIrql); 
 
    // 
    // Complete the IRP with status canceled 
    // 
     
    if(irpToComplete) { 
     
        mdl=RESERVED(myPacket)->pMdl; 
 
        // 
        //  Free the MDL that we allocated 
        // 
        IoFreeMdl(mdl); 
 
        // 
        //  Put the packet on the free queue 
        // 
        NdisFreePacket(myPacket); 
        IF_LOUD(DbgPrint("Packet: cancelled: 0x%0x\n", irpToComplete);) 
 
        irpToComplete->IoStatus.Status = STATUS_CANCELLED; 
        irpToComplete->IoStatus.Information = 0; 
        IoCompleteRequest(irpToComplete, IO_NO_INCREMENT); 
        IoDecrement(open); 
    } 
 
    return; 
  
} 
 
 
NTSTATUS 
PacketCancelReadIrps( 
    IN POPEN_INSTANCE Open 
) 
{ 
    PLIST_ENTRY         thisEntry; 
    PIRP                pendingIrp; 
    PNDIS_PACKET        myPacket = NULL; 
    PPACKET_RESERVED    reserved; 
    PMDL                mdl; 
 
    IF_LOUD(DbgPrint("PacketCancelReadIrps\n");) 
 
    // 
    // Walk through the RcvList and cancel all read IRPs. 
    // 
 
    while(thisEntry=ExInterlockedRemoveHeadList( 
                        &Open->RcvList, 
                        &Open->RcvQSpinLock 
                        )) 
    { 
        reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement); 
        myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); 
 
        ASSERT(myPacket); 
 
        pendingIrp = RESERVED(myPacket)->Irp; 
 
         
        mdl=RESERVED(myPacket)->pMdl; 
 
        // 
        //  Free the partial MDL that we allocated 
        // 
        IoFreeMdl(mdl); 
 
        // 
        //  Put the packet on the free queue 
        // 
        NdisFreePacket(myPacket); 
         
        IF_LOUD(DbgPrint("Cancelled : 0%0x\n", pendingIrp);) 
 
        IoSetCancelRoutine(pendingIrp, NULL); 
 
        // 
        // Cancel the Irp 
        // 
        pendingIrp->IoStatus.Information = 0; 
        pendingIrp->IoStatus.Status = STATUS_CANCELLED; 
        IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); 
        IoDecrement(Open); 
    } 
 
    return STATUS_SUCCESS; 
}