VOID NdisprotCancelRead( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Cancel a pending read IRP. We unlink the IRP from the open context queue and complete it. Arguments: pDeviceObject - pointer to our device object pIrp - IRP to be cancelled Return Value: None --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; UNREFERENCED_PARAMETER(pDeviceObject); IoReleaseCancelSpinLock(pIrp->CancelIrql); pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0]; NPROT_STRUCT_ASSERT(pOpenContext, oc); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); pOpenContext->PendedReadCount--; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp)); pIrp->IoStatus.Status = STATUS_CANCELLED; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); NPROT_DEREF_OPEN(pOpenContext); // Cancel removed pended Read }
VOID NdisProtSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET pNdisPacket, IN NDIS_STATUS Status ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. NDIS 5.1: Arguments: ProtocolBindingContext - pointer to open context pNdisPacket - packet that completed send Status - status of send Return Value: None --*/ { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PNDISPROT_OPEN_CONTEXT pOpenContext; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); pIrp = NPROT_IRP_FROM_SEND_PKT(pNdisPacket); if (pOpenContext->bRunningOnWin9x) { // // We would have attached our own NDIS_BUFFER. Take it out // and free it. // #ifndef NDIS51 PNDIS_BUFFER pNdisBuffer; PVOID VirtualAddr; UINT BufferLength; UINT TotalLength; #endif #ifdef NDIS51 NPROT_ASSERT(FALSE); // NDIS 5.1 not on Win9X! #else NdisGetFirstBufferFromPacket( pNdisPacket, &pNdisBuffer, &VirtualAddr, &BufferLength, &TotalLength); NPROT_ASSERT(pNdisBuffer != NULL); NdisFreeBuffer(pNdisBuffer); #endif } #ifdef NDIS51 IoSetCancelRoutine(pIrp, NULL); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); NPROT_RELEASE_LOCK(&pOpenContext->Lock); #endif // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_PKT(pNdisPacket); // // Complete the Write IRP with the right status. // pIrpSp = IoGetCurrentIrpStackLocation(pIrp); if (Status == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } DEBUGP(DL_INFO, ("SendComplete: packet %p/IRP %p/Length %d " "completed with status %x\n", pNdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); NdisInterlockedDecrement((PLONG)&pOpenContext->PendedSendCount); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP }
VOID ndisprotQueueReceiveNetBufferList( IN PNDISPROT_OPEN_CONTEXT pOpenContext, IN PNET_BUFFER_LIST pRcvNetBufList, IN BOOLEAN DispatchLevel ) /*++ Routine Description: Queue up a received net buffer list on the open context structure. If the queue size goes beyond a water mark, discard a Net Buffer list at the head of the queue. Finally, run the queue service routine. Arguments: pOpenContext - pointer to open context pRcvPacket - the received packet DipatchLevel - the irql level Return Value: None --*/ { PLIST_ENTRY pEnt; PLIST_ENTRY pDiscardEnt; PNET_BUFFER_LIST pDiscardNetBufList; do { NPROT_REF_OPEN(pOpenContext); // queued rcv net buffer list NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); if ((pOpenContext->State == NdisprotPaused) || (pOpenContext->State == NdisprotPausing)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel); break; } // // Check if the binding is in the proper state to receive // this net buffer list. // if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE) && (pOpenContext->PowerState == NetDeviceStateD0)) { // // Queue the net buffer list // pEnt = NPROT_RCV_NBL_TO_LIST_ENTRY(pRcvNetBufList); NPROT_INSERT_TAIL_LIST(&pOpenContext->RecvNetBufListQueue, pEnt); NPROT_RCV_NBL_FROM_LIST_ENTRY(pEnt) = pRcvNetBufList; pOpenContext->RecvNetBufListCount++; DEBUGP(DL_VERY_LOUD, ("QueueReceiveNetBufferList: open %p," " queued nbl %p, queue size %d\n", pOpenContext, pRcvNetBufList, pOpenContext->RecvNetBufListCount)); } else { // // Received this net buffer list when the binding is going away. // Drop this. // NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // dropped rcv packet - bad state break; } // // Trim the queue if it has grown too big. // if (pOpenContext->RecvNetBufListCount > MAX_RECV_QUEUE_SIZE) { // // Remove the head of the queue. // pDiscardEnt = pOpenContext->RecvNetBufListQueue.Flink; NPROT_REMOVE_ENTRY_LIST(pDiscardEnt); pOpenContext->RecvNetBufListCount --; NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); pDiscardNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt); NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt) = NULL; ndisprotFreeReceiveNetBufferList(pOpenContext, pDiscardNetBufList, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // dropped rcv packet - queue too long DEBUGP(DL_INFO, ("QueueReceiveNetBufferList: open %p queue" " too long, discarded %p\n", pOpenContext, pDiscardNetBufList)); } else { NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); } // // Run the receive queue service routine now. // ndisprotServiceReads(pOpenContext); } while (FALSE); }
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 }
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; PNDIS_PACKET pRcvPacket; PLIST_ENTRY pRcvPacketEntry; PUCHAR pSrc, pDst; ULONG BytesRemaining; // at pDst PNDIS_BUFFER pNdisBuffer; ULONG BytesAvailable; BOOLEAN FoundPendingIrp; 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); while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) && !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue)) { 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 no pending IRP // if (FoundPendingIrp == FALSE) { break; } // // Get the first queued receive packet // pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink; NPROT_REMOVE_ENTRY_LIST(pRcvPacketEntry); pOpenContext->RecvPktCount --; NPROT_RELEASE_LOCK(&pOpenContext->Lock); NPROT_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet pRcvPacket = NPROT_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry); // // Copy as much data as possible from the receive packet to // the IRP MDL. // pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); __analysis_assume(pDst); NPROT_ASSERT(pDst != NULL); // since it was already mapped BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress); pNdisBuffer = NDIS_PACKET_FIRST_NDIS_BUFFER(pRcvPacket); // // 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. // while (BytesRemaining && (pNdisBuffer != NULL)) { #ifndef WIN9X NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority); if (pSrc == NULL) { DEBUGP(DL_FATAL, ("ServiceReads: Open %p, QueryBuffer failed for buffer %p\n", pOpenContext, pNdisBuffer)); break; } #else NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable); #endif if (BytesAvailable) { ULONG BytesToCopy = MIN(BytesAvailable, BytesRemaining); NPROT_COPY_MEM(pDst, pSrc, BytesToCopy); BytesRemaining -= BytesToCopy; pDst += BytesToCopy; } NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer); } // // 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, pIrp->IoStatus.Information)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); // // Free up the receive packet - back to the miniport if it // belongs to it, else reclaim it (local copy). // if (NdisGetPoolFromPacket(pRcvPacket) != pOpenContext->RecvPacketPool) { NdisReturnPackets(&pRcvPacket, 1); } else { ndisprotFreeReceivePacket(pOpenContext, pRcvPacket); } NPROT_DEREF_OPEN(pOpenContext); // took out pended Read NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); pOpenContext->PendedReadCount--; } NPROT_RELEASE_LOCK(&pOpenContext->Lock); NPROT_DEREF_OPEN(pOpenContext); // temp ref - service reads }
VOID NdisProtCancelRead( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Cancel a pending read IRP. We unlink the IRP from the open context queue and complete it. Arguments: pDeviceObject - pointer to our device object pIrp - IRP to be cancelled Return Value: None --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; PLIST_ENTRY pIrpEntry; BOOLEAN Found; UNREFERENCED_PARAMETER(pDeviceObject); IoReleaseCancelSpinLock(pIrp->CancelIrql); Found = FALSE; pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0]; NPROT_STRUCT_ASSERT(pOpenContext, oc); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock); // // Locate the IRP in the pended read queue and remove it if found. // for (pIrpEntry = pOpenContext->PendedReads.Flink; pIrpEntry != &pOpenContext->PendedReads; pIrpEntry = pIrpEntry->Flink) { if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry)) { NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); pOpenContext->PendedReadCount--; Found = TRUE; break; } } NPROT_RELEASE_LOCK(&pOpenContext->Lock); if (Found) { DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp)); pIrp->IoStatus.Status = STATUS_CANCELLED; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); NPROT_DEREF_OPEN(pOpenContext); // Cancel removed pended Read } }
VOID NdisprotSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_BUFFER_LIST pNetBufferList, IN ULONG SendCompleteFlags ) /*++ Routine Description: NDIS entry point called to signify completion of a packet send. We pick up and complete the Write IRP corresponding to this packet. Arguments: ProtocolBindingContext - pointer to open context pNetBufferList - NetBufferList that completed send SendCompleteFlags - Specifies if the caller is at DISPATCH level Return Value: None --*/ { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST CurrNetBufferList = NULL; PNET_BUFFER_LIST NextNetBufferList; NDIS_STATUS CompletionStatus; BOOLEAN DispatchLevel; pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext; NPROT_STRUCT_ASSERT(pOpenContext, oc); DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags); for (CurrNetBufferList = pNetBufferList; CurrNetBufferList != NULL; CurrNetBufferList = NextNetBufferList) { NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList); pIrp = NPROT_IRP_FROM_SEND_NBL(CurrNetBufferList); IoAcquireCancelSpinLock(&pIrp->CancelIrql); IoSetCancelRoutine(pIrp, NULL); pIrp->Tail.Overlay.DriverContext[0] = NULL; pIrp->Tail.Overlay.DriverContext[1] = NULL; IoReleaseCancelSpinLock(pIrp->CancelIrql); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry); NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList); // // We are done with the NDIS_PACKET: // NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel); // // Complete the Write IRP with the right status. // pIrpSp = IoGetCurrentIrpStackLocation(pIrp); if (CompletionStatus == NDIS_STATUS_SUCCESS) { pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length; pIrp->IoStatus.Status = STATUS_SUCCESS; } else { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; } DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d " "completed with status %x\n", CurrNetBufferList, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status)); IoCompleteRequest(pIrp, IO_NO_INCREMENT); NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel); pOpenContext->PendedSendCount--; if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING)) && (pOpenContext->PendedSendCount == 0)) { ASSERT(pOpenContext->ClosingEvent != NULL); NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent); pOpenContext->ClosingEvent = NULL; } NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel); NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP } }