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