/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: drivers/net/afd/afd/lock.c * PURPOSE: Ancillary functions driver * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net) * UPDATE HISTORY: * 20040708 Created */ #include "afd.h" PVOID GetLockedData(PIRP Irp, PIO_STACK_LOCATION IrpSp) { ASSERT(Irp->MdlAddress); ASSERT(Irp->Tail.Overlay.DriverContext[0]); UNREFERENCED_PARAMETER(IrpSp); return Irp->Tail.Overlay.DriverContext[0]; } /* Lock a method_neither request so it'll be available from DISPATCH_LEVEL */ PVOID LockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN Output, KPROCESSOR_MODE *LockMode) { BOOLEAN LockFailed = FALSE; AFD_DbgPrint(1,("(PID %lx) LockRequest: Starting for IRP: %p\n", PsGetCurrentProcessId(), Irp)); ASSERT(!Irp->MdlAddress); switch (IrpSp->MajorFunction) { case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: ASSERT(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer); ASSERT(IrpSp->Parameters.DeviceIoControl.InputBufferLength); Irp->MdlAddress = IoAllocateMdl( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, FALSE, FALSE, NULL ); if( Irp->MdlAddress ) { _SEH2_TRY { MmProbeAndLockPages( Irp->MdlAddress, Irp->RequestorMode, IoModifyAccess ); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { LockFailed = TRUE; } _SEH2_END; if( LockFailed ) { AFD_DbgPrint(1,("(PID %lx) LockRequest: Failed to lock pages, returning NULL.\n", PsGetCurrentProcessId())); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; return NULL; } /* The mapped address goes in index 1 */ Irp->Tail.Overlay.DriverContext[1] = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (!Irp->Tail.Overlay.DriverContext[1]) { AFD_DbgPrint(1,("(PID %lx) LockRequest: Failed to get mapped address, returning NULL.\n", PsGetCurrentProcessId())); MmUnlockPages(Irp->MdlAddress); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; return NULL; } /* The allocated address goes in index 0 */ Irp->Tail.Overlay.DriverContext[0] = ExAllocatePoolWithTag(NonPagedPool, MmGetMdlByteCount(Irp->MdlAddress), TAG_AFD_DATA_BUFFER); if (!Irp->Tail.Overlay.DriverContext[0]) { AFD_DbgPrint(1,("(PID %lx) LockRequest: Failed to allocate memory, returning NULL.\n", PsGetCurrentProcessId())); MmUnlockPages(Irp->MdlAddress); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; return NULL; } RtlCopyMemory(Irp->Tail.Overlay.DriverContext[0], Irp->Tail.Overlay.DriverContext[1], MmGetMdlByteCount(Irp->MdlAddress)); /* If we don't want a copy back, we zero the mapped address pointer */ if (!Output) { Irp->Tail.Overlay.DriverContext[1] = NULL; } /* We're using a user-mode buffer directly */ if (LockMode != NULL) { *LockMode = UserMode; } } else { AFD_DbgPrint(1,("(PID %lx) LockRequest: DEVICECTL falied to allocae Irp->MdlAddress, returning NULL.\n", PsGetCurrentProcessId())); return NULL; } break; case IRP_MJ_READ: case IRP_MJ_WRITE: ASSERT(Irp->UserBuffer); AFD_DbgPrint(1,("(PID %lx) LockRequest: RRP_MJ_READ/WRITE detected, calling IoAllocate() to set Irp->MdlAddress from Irp->UserBuffer: %p length: %lu for IRP: %p\n", PsGetCurrentProcessId(), Irp->UserBuffer, (IrpSp->MajorFunction == IRP_MJ_READ) ? IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length, Irp)); Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer, (IrpSp->MajorFunction == IRP_MJ_READ) ? IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length, FALSE, FALSE, NULL ); if( Irp->MdlAddress ) { PAFD_RECV_INFO AfdInfo; AFD_DbgPrint(1,("(PID %lx) LockRequest: using MmProbeAndLockPages() to lock pages for Irp->MdlAddress, Irp->RequestorMode and IoModifyAccess for IRP: %p\n", PsGetCurrentProcessId(), Irp)); _SEH2_TRY { MmProbeAndLockPages( Irp->MdlAddress, Irp->RequestorMode, IoModifyAccess ); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { LockFailed = TRUE; } _SEH2_END; if( LockFailed ) { AFD_DbgPrint(1,("(PID %lx) LockRequest: MmProbe*() Failed to lock pages, returning NULL for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; return NULL; } AFD_DbgPrint(1,("(PID %lx) LockRequest: calling ExAllocatePoolWithTag() to allocate info structure in NonPagedPool for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); /* We need to create the info struct that AFD expects for all send/recv requests */ AfdInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(AFD_RECV_INFO) + sizeof(AFD_WSABUF), TAG_AFD_DATA_BUFFER); if (!AfdInfo) { AFD_DbgPrint(1,("(PID %lx) LockRequest: Failed to allocate info structure memory, returning NULL.\n", PsGetCurrentProcessId())); MmUnlockPages(Irp->MdlAddress); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; return NULL; } AFD_DbgPrint(1,("(PID %lx) LockRequest: adding reference to BufferArray to info structure in NonPagedPool for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); /* We'll append the buffer array to this struct */ AfdInfo->BufferArray = (PAFD_WSABUF)(AfdInfo + 1); AfdInfo->BufferCount = 1; /* Setup the default flags values */ AfdInfo->AfdFlags = 0; AfdInfo->TdiFlags = 0; AFD_DbgPrint(1,("(PID %lx) LockRequest: adding reference to Irp->MdlAddress to BufferArray ino info structure in NonPagedPool for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); /* Now build the buffer array */ AfdInfo->BufferArray[0].buf = MmGetSystemAddressForMdl(Irp->MdlAddress); AfdInfo->BufferArray[0].len = MmGetMdlByteCount(Irp->MdlAddress); AFD_DbgPrint(1,("(PID %lx) LockRequest: adding reference to structure to Irp->Tail.Overlay.DriverContext[0] for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); /* Store the struct where AFD expects */ Irp->Tail.Overlay.DriverContext[0] = AfdInfo; /* Don't copy anything out */ Irp->Tail.Overlay.DriverContext[1] = NULL; /* We're using a placeholder buffer that we allocated */ if (LockMode != NULL) { AFD_DbgPrint(1,("(PID %lx) LockRequest: Locking mode active, setting *LockMode toKernelMode for IRP: %p.\n", PsGetCurrentProcessId(), Irp)); *LockMode = KernelMode; } } else { AFD_DbgPrint(1,("(PID %lx) LockRequest: IRP_MJ_WRITE/READ failed to allocate Irp->MdlAddress, returning NULL.\n", PsGetCurrentProcessId())); return NULL; } break; default: AFD_DbgPrint(1,("(PID %lx) LockRequest: invalid IRP_ , returning NULL.\n", PsGetCurrentProcessId())); ASSERT(FALSE); return NULL; } AFD_DbgPrint(1,("(PID %lx) LockRequest: completed, returning via GetLockedData().\n", PsGetCurrentProcessId())); return GetLockedData(Irp, IrpSp); } VOID UnlockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp ) { ASSERT(Irp->MdlAddress); ASSERT(Irp->Tail.Overlay.DriverContext[0]); UNREFERENCED_PARAMETER(IrpSp); AFD_DbgPrint(1,("(PID %lx) UnlockRequest: Starting for Irp: %p\n", PsGetCurrentProcessId(), Irp)); /* Check if we need to copy stuff back */ if (Irp->Tail.Overlay.DriverContext[1] != NULL) { RtlCopyMemory(Irp->Tail.Overlay.DriverContext[1], Irp->Tail.Overlay.DriverContext[0], MmGetMdlByteCount(Irp->MdlAddress)); } ExFreePoolWithTag(Irp->Tail.Overlay.DriverContext[0], TAG_AFD_DATA_BUFFER); MmUnlockPages( Irp->MdlAddress ); IoFreeMdl( Irp->MdlAddress ); Irp->MdlAddress = NULL; AFD_DbgPrint(1,("(PID %lx) UnlockRequest: completed(fallthrough at end of code), for Irp: %p\n", PsGetCurrentProcessId(), Irp)); } /* Note: We add an extra buffer if LockAddress is true. This allows us to * treat the address buffer as an ordinary client buffer. It's only used * for datagrams. */ PAFD_WSABUF LockBuffers( PAFD_WSABUF Buf, UINT Count, PVOID AddressBuf, PINT AddressLen, BOOLEAN Write, BOOLEAN LockAddress, KPROCESSOR_MODE LockMode) { UINT i; /* Copy the buffer array so we don't lose it */ UINT Lock = LockAddress ? 2 : 0; UINT Size = (sizeof(AFD_WSABUF) + sizeof(AFD_MAPBUF)) * (Count + Lock); /* <== lock is set to 2 if LockAddress is true making room for another entry */ BOOLEAN LockFailed = FALSE; PAFD_MAPBUF MapBuf; PAFD_WSABUF OurBuf; UINT DataSize = 0; /* if LockAddress is not true we use the original allocation size and just include the buffer array pointer and length structure and the map for it */ /* AFD_DbgPrint(MID_TRACE,("(PID %lx) LockBuffers() Called(%p)\n", PsGetCurrentProcessId(), NewBuf)); */ /* we use a combination of parameters to identify a call to new buffer mode so that existing code can use older method */ if( (LockAddress == TRUE) && (AddressBuf == (VOID *)0xFFFFFFFF) && (AddressLen == (VOID *)0xFFFFFFFF) ) { /* only use new mode if called with this combination of parameters */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() DLB LB HACK starting(%p) ArrayCount %u LockAddress is TRUE AddressBuf and AddressLen are 0xFFFFFFFF.\n", PsGetCurrentProcessId(), Buf, Count)); AFD_DbgPrint(0,("(PID %lx) LockBuffers() using DataGram buffer gather mode.\n", PsGetCurrentProcessId())); DataSize = 0; for( i = 0; i < Count; i++ ) DataSize = DataSize + Buf[i].len; } else { if (LockAddress == TRUE) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() starting standard code for(%p) ArrayCount %u LockAddress=TRUE (magic param combo not found).\n", PsGetCurrentProcessId(), Buf, Count)); } else { AFD_DbgPrint(0,("(PID %lx) LockBuffers() starting standard code for(%p) ArrayCount %u LockAddress=FALSE (magic param combo not found).\n", PsGetCurrentProcessId(), Buf, Count)); } } AFD_DbgPrint(0,("(PID %lx) LockBuffers() allocating NewBuf Buffer from PagedPool with size: %u - calling ExAllocatePoolWithTag(PagedPool, Size, TAG_AFD_WSA_BUFFER).\n", PsGetCurrentProcessId(), Size)); PAFD_WSABUF NewBuf = ExAllocatePoolWithTag(PagedPool, Size, TAG_AFD_WSA_BUFFER); AFD_DbgPrint(0,("(PID %lx) LockBuffers() resumed control for ExAllocatePoolWithTag().\n", PsGetCurrentProcessId())); if( NewBuf ) { /* this code logs lots of redundant information, once tested that can be limited or removed. */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() NewBuf is defined, clearing NewBuf memory.\n", PsGetCurrentProcessId())); /* common code to both modes */ RtlZeroMemory(NewBuf, Size); /* DLB used to be Size here, but we altered size for our special mode. In regular mode the value in DataSize will be from Size */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() initializing MapBuf pointer.\n", PsGetCurrentProcessId())); MapBuf = (PAFD_MAPBUF)(NewBuf + Count + Lock); /* <== lock is set to 2 if LockAddress is true making room for another entry */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() copying BufferArray structure to NewBuf.\n", PsGetCurrentProcessId())); /* code copies the reference structure so we have control of it outside of userland */ _SEH2_TRY { /* DLB the buffer references(adddress/len) themselves are placed at the start of the resulting req buffer structure, THERE IS NOT A ZERO element with total size !!! */ RtlCopyMemory( NewBuf, Buf, sizeof(AFD_WSABUF) * Count ); /* DLB for now we keep the array but not the data, check datagram send code to see what it does */ /* LockAddress is a parameter sent by caller, for the datagram sends it is FALSE so there is NOT an element at the end wrapping entire buffer in a lock */ if( LockAddress ) { /* DLB if these parameters are provided they are used to populate the last item, which only exists if they are non-null. that item is a wrapper item */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() found LockAddress TRUE, expanding Count by two.\n", PsGetCurrentProcessId())); if (AddressBuf && AddressLen && (AddressBuf != (VOID *)0xFFFFFFFF) ) { /* avoid the magic cookie */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() found AddressBuf and AddressLen set, adding wrapper entries in NewBuf structure.\n", PsGetCurrentProcessId())); NewBuf[Count].buf = AddressBuf; NewBuf[Count].len = *AddressLen; NewBuf[Count + 1].buf = (PVOID)AddressLen; NewBuf[Count + 1].len = sizeof(*AddressLen); } Count += 2; /* <=== this makes the loops for buffers include the new entries */ } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() Access violation copying buffer info from userland (%p %p), returning NULL\n", PsGetCurrentProcessId(), Buf, NewBuf)); ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER); _SEH2_YIELD(return NULL); } _SEH2_END; AFD_DbgPrint(0,("(PID %lx) LockBuffers() BufferArray structure setup completed, probing and locking buffers.\n", PsGetCurrentProcessId())); /* DLB this is where active hack code starts, this hack creates a single locked MDL buffer for entire packet */ if( (LockAddress == TRUE) && (AddressBuf == (VOID *)0xFFFFFFFF) && (AddressLen == (VOID *)0xFFFFFFFF) ) { /* DLB if this is true we gather the buffer pieces into a single area for the driver layer and return that */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() DLB LB Hack ACTIVATED - allocating and locking single buffer to recieve complete contiguous packet.\n", PsGetCurrentProcessId(), DataSize)); /* rather than looping and creating parallel MDL buffers we create one big enough to handle all data and set the the other MDL array members as NULL */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() DLB LB Hack - Buf: %p NewBuf: %p MapBuf: %p OurBuf: %p DataSize: %u\n", PsGetCurrentProcessId(), Buf, NewBuf, MapBuf, OurBuf, DataSize )); for( i = 0; i < Count; i++ ) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() loop reached array element %u \n", PsGetCurrentProcessId(), i)); if (i == 0) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() calling IoAllocateMdl() for array element %u with Size %u\n", PsGetCurrentProcessId(), i, DataSize)); MapBuf[i].Mdl = IoAllocateMdl( NewBuf[i].buf, DataSize, FALSE, FALSE, NULL ); /* check if this routine allocates or allocates and copies, just allocates I think */ if( MapBuf[i].Mdl ) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() MDL succesfully allocated, Probe and lock new MDL page %u.\n", PsGetCurrentProcessId(), i)); _SEH2_TRY { MmProbeAndLockPages( MapBuf[i].Mdl, LockMode, Write ? IoModifyAccess : IoReadAccess ); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { LockFailed = TRUE; } _SEH2_END; if( LockFailed ) { AFD_DbgPrint(0,("(PID %lx) LosckBuffers() exception generated calling MmProbeAndLockPages(), Failed to lock page %u, cleaning up and returning NULL.\n", PsGetCurrentProcessId(), i)); IoFreeMdl( MapBuf[i].Mdl ); MapBuf[i].Mdl = NULL; ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER); return NULL; } else { AFD_DbgPrint(0,("(PID %lx) LockBuffers() MmProbeAndLock of MDL page %u finished.\n", PsGetCurrentProcessId(), i)); } } else { ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER); AFD_DbgPrint(0,("(PID %lx) LockBuffers() failed to allocate associated MDL page, returning NULL.\n", PsGetCurrentProcessId())); return NULL; } } else { AFD_DbgPrint(0,("(PID %lx) LockBuffers() set MDL page %u to NULL.\n", PsGetCurrentProcessId(), i)); MapBuf[i].Mdl = NULL; /* this should make unlock skip these silently */ /* continue; */ } AFD_DbgPrint(0,("(PID %lx) LockBuffers() loop completed array element %u \n", PsGetCurrentProcessId(), i)); } /* DLB if we did everything correctly we now have two consolidated packet buffers, one on userland and one in MDL space. We'll pass it back to the caller, but caller needs to reset array count */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() DLB LB Hack - loop completed, IoAllocateMdl() MapBuf[0].Mdl @ %p size: %u \n", PsGetCurrentProcessId(), MapBuf[0].Mdl, DataSize)); } else { /* This is where the original unhacked code is, if our special calling convention is not detected execution comes here and one MDL buffer is allocated for each original buffer in bufferarray and they are allocated with the same size as their matchin buffers in bufferArray, probed and locked */ /* this loop allocates one MDL buffer per userland buffer using the same size and then locks buffer, but makes no effort to make buffers consecutive an copies no content */ AFD_DbgPrint(0,("(PID %lx) LockBuffers() DLB LB Hack INACTIVE - allocating and locking standard paired buffer set.\n", PsGetCurrentProcessId(), DataSize)); for( i = 0; i < Count; i++ ) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() Locking Newbuf[%u] buffer (%p:%u), allocating associated MDL buffer.\n", PsGetCurrentProcessId(), i, NewBuf[i].buf, NewBuf[i].len)); if( NewBuf[i].buf && NewBuf[i].len ) { MapBuf[i].Mdl = IoAllocateMdl( NewBuf[i].buf, NewBuf[i].len, FALSE, FALSE, NULL ); /* check if this routine allocates or allocates and copies */ } else { MapBuf[i].Mdl = NULL; continue; } AFD_DbgPrint(0,("(PID %lx) LockBuffers() call to IoAllocateMdl() returned NewMdl @ %p\n", PsGetCurrentProcessId(), MapBuf[i].Mdl)); if( MapBuf[i].Mdl ) { AFD_DbgPrint(0,("(PID %lx) LockBuffers() Probe and lock new MDL pages.\n", PsGetCurrentProcessId())); _SEH2_TRY { MmProbeAndLockPages( MapBuf[i].Mdl, LockMode, Write ? IoModifyAccess : IoReadAccess ); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { LockFailed = TRUE; } _SEH2_END; if( LockFailed ) { AFD_DbgPrint(0,("(PID %lx) exception calling MmProbeAndLockPages(), Failed to lock pages, cleaning up and returning NULL.\n", PsGetCurrentProcessId())); IoFreeMdl( MapBuf[i].Mdl ); MapBuf[i].Mdl = NULL; ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER); return NULL; } else { AFD_DbgPrint(0,("(PID %lx) LockBuffers() MmProbeAndLock of MDL pages finished.\n", PsGetCurrentProcessId())); } } else { ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER); AFD_DbgPrint(0,("(PID %lx) LockBuffers() failed to allocate associated MDL pages, returning NULL.\n", PsGetCurrentProcessId())); return NULL; } } } } else { AFD_DbgPrint(0,("(PID %lx) LockBuffers() pool allocation for structure failed, returning NULL.\n", PsGetCurrentProcessId())); return NULL; } AFD_DbgPrint(0,("(PID %lx) LockBuffers() completed succesfully NewBuf prepared at - %p for buffer %p\n", PsGetCurrentProcessId(), NewBuf, Buf)); return NewBuf; } VOID UnlockBuffers( PAFD_WSABUF Buf, UINT Count, BOOL Address ) { UINT Lock = Address ? 2 : 0; PAFD_MAPBUF Map = (PAFD_MAPBUF)(Buf + Count + Lock); UINT i; if (Address) { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Starting - Buf: %p, Count: %u Map: %p Address=TRUE.\n", PsGetCurrentProcessId(), Buf, Count, Map)); } else { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Starting - Buf: %p, Count: %u Map: %p Address=FALSE.\n", PsGetCurrentProcessId(), Buf, Count, Map)); } if( !Buf ) { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG received NULL buffer pointer, returning.\n")); return; } /* got BSOD when unlocking, pool validation failed for this entry. the following is same validation and we are repeating it here just to see if the condition ever passes */ for( i = 0; i < Count + Lock; i++ ) { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG checking MDL index# %u\n", PsGetCurrentProcessId(), i)); if( Map[i].Mdl ) { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Map[%u].Mdl == %p, calling MmUnlockages().\n", PsGetCurrentProcessId(), i, Map[i].Mdl )); MmUnlockPages( Map[i].Mdl ); AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Map[%u].Mdl == %p, calling IoFreeMdl().\n", PsGetCurrentProcessId(), i, Map[i].Mdl )); IoFreeMdl( Map[i].Mdl ); AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Map[%u].Mdl == %p, setting Map[%u].Mdl NULL.\n", PsGetCurrentProcessId(), i, Map[i].Mdl, i )); Map[i].Mdl = NULL; } else { AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG Map[%u].Mdl == NULL, skipping this entry.\n", PsGetCurrentProcessId(), i )); } } AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG unlocked pages and freed MDL, releasing buffer - 0x%p.\n", PsGetCurrentProcessId(), Buf)); ExFreePoolWithTag(Buf, TAG_AFD_WSA_BUFFER); /* with new buffer method I get a BSOD here for BAD_POOL_HEADER (ntoskrnl/mm/ARM3/expool.c:276) Entry BlockSize 36, tag AfWb. NextEntry PreviousSize 0, tag */ Buf = NULL; AFD_DbgPrint(0,("(PID %lx) UnlockBuffers() ORIG completed successfully(at end of code), returning.\n", PsGetCurrentProcessId())); } /* RESTORED ORIGINAL FOR TESTING SHOULD WORK ? VOID UnlockBuffers( PAFD_WSABUF Buf, UINT Count, BOOL Address ) { UINT Lock = Address ? 2 : 0; PAFD_MAPBUF Map = (PAFD_MAPBUF)(Buf + Count + Lock); UINT i; if( !Buf ) return; AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() Starting - 0x%p\n", PsGetCurrentProcessId(), Buf)); if (Address) { Map = (PAFD_MAPBUF)(Buf + sizeof(AFD_WSABUF)); AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() DLB LB Hack - calling MUnlockPages() for Map[0].Mdl @ %p\n", PsGetCurrentProcessId(), Map[i].Mdl)); MmUnlockPages( Map[0].Mdl ); AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() DLB LB Hack - calling IoFreeMdl() for Map[0].Mdl @ %p\n", PsGetCurrentProcessId(), Map[i].Mdl)); IoFreeMdl( Map[0].Mdl ); AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() DLB LB Hack - setting Map[0].Mdl to NULL.\n", PsGetCurrentProcessId())); Map[0].Mdl = NULL; } else { for( i = 0; i < Count + Lock; i++ ) { if( Map[i].Mdl ) { MmUnlockPages( Map[i].Mdl ); IoFreeMdl( Map[i].Mdl ); Map[i].Mdl = NULL; } } } AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() calling ExFreePoolWithTag(Buf, TAG_AFD_WSA_BUFFER).\n", PsGetCurrentProcessId())); ExFreePoolWithTag(Buf, TAG_AFD_WSA_BUFFER); AFD_DbgPrint(0,("(PID %lx) UnLockBuffers() completed (end of code), setting Buf=NULL.\n", PsGetCurrentProcessId())); Buf = NULL; } */ /* Produce a kernel-land handle array with handles replaced by object * pointers. This will allow the system to do proper alerting */ PAFD_HANDLE LockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) { UINT i; NTSTATUS Status = STATUS_SUCCESS; PAFD_HANDLE FileObjects = ExAllocatePoolWithTag(NonPagedPool, HandleCount * sizeof(AFD_HANDLE), TAG_AFD_POLL_HANDLE); for( i = 0; FileObjects && i < HandleCount; i++ ) { FileObjects[i].Status = 0; FileObjects[i].Events = HandleArray[i].Events; FileObjects[i].Handle = 0; if( !HandleArray[i].Handle ) continue; if( NT_SUCCESS(Status) ) { Status = ObReferenceObjectByHandle ( (PVOID)HandleArray[i].Handle, FILE_ALL_ACCESS, NULL, KernelMode, (PVOID*)&FileObjects[i].Handle, NULL ); } if( !NT_SUCCESS(Status) ) { AFD_DbgPrint(1,("(PID %lx) Failed to reference handles (0x%x)\n", PsGetCurrentProcessId(), Status)); FileObjects[i].Handle = 0; } } if( !NT_SUCCESS(Status) ) { UnlockHandles( FileObjects, HandleCount ); return NULL; } return FileObjects; } VOID UnlockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) { UINT i; for( i = 0; i < HandleCount; i++ ) { if( HandleArray[i].Handle ) ObDereferenceObject( (PVOID)HandleArray[i].Handle ); } ExFreePoolWithTag(HandleArray, TAG_AFD_POLL_HANDLE); HandleArray = NULL; } BOOLEAN SocketAcquireStateLock( PAFD_FCB FCB ) { if( !FCB ) return FALSE; return !KeWaitForMutexObject(&FCB->Mutex, Executive, KernelMode, FALSE, NULL); } VOID SocketStateUnlock( PAFD_FCB FCB ) { KeReleaseMutex(&FCB->Mutex, FALSE); } NTSTATUS NTAPI UnlockAndMaybeComplete ( PAFD_FCB FCB, NTSTATUS Status, PIRP Irp, UINT Information ) { Irp->IoStatus.Status = Status; Irp->IoStatus.Information = Information; if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) ); (void)IoSetCancelRoutine(Irp, NULL); SocketStateUnlock( FCB ); IoCompleteRequest( Irp, IO_NETWORK_INCREMENT ); return Status; } NTSTATUS LostSocket( PIRP Irp ) { NTSTATUS Status = STATUS_FILE_CLOSED; AFD_DbgPrint(1,("(PID %lx) Starting.\n", PsGetCurrentProcessId())); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = Status; if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) ); IoCompleteRequest( Irp, IO_NO_INCREMENT ); return Status; } NTSTATUS QueueUserModeIrp(PAFD_FCB FCB, PIRP Irp, UINT Function) { NTSTATUS Status; /* Add the IRP to the queue in all cases (so AfdCancelHandler will work properly) */ InsertTailList( &FCB->PendingIrpList[Function], &Irp->Tail.Overlay.ListEntry ); /* Acquire the cancel spin lock and check the cancel bit */ IoAcquireCancelSpinLock(&Irp->CancelIrql); if (!Irp->Cancel) { /* We are not cancelled; we're good to go so * set the cancel routine, release the cancel spin lock, * mark the IRP as pending, and * return STATUS_PENDING to the caller */ (void)IoSetCancelRoutine(Irp, AfdCancelHandler); IoReleaseCancelSpinLock(Irp->CancelIrql); IoMarkIrpPending(Irp); Status = STATUS_PENDING; } else { /* We were already cancelled before we were able to register our cancel routine * so we are to call the cancel routine ourselves right here to cancel the IRP * (which handles all the stuff we do above) and return STATUS_CANCELLED to the caller */ AfdCancelHandler(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp); Status = STATUS_CANCELLED; } return Status; } NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function ) { NTSTATUS Status; Status = QueueUserModeIrp(FCB, Irp, Function); SocketStateUnlock( FCB ); return Status; }