VOID DeferredRxCompleteDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ){ PRX_COMP_DPC_CTX rxCompCtx = DeferredContext; PDEVICE_CONTEXT deviceContext = rxCompCtx->DeviceContext; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2); LpxReceiveComplete2(deviceContext, &rxCompCtx->ReceivedPackets); ExFreeToNPagedLookasideList(&deviceContext->DeferredRxCompContext, rxCompCtx); ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); ClearFlag( deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_DEFFERED_DPC_SET ); RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); LpxReceiveComplete( deviceContext ); LpxDereferenceDeviceContext("RxCompDpc", deviceContext, DCREF_REQUEST); }
PCONNECTION WalkConnectionTable ( IN PENDPOINT Endpoint, IN OUT PCSHORT Index ) { CSHORT i; PTABLE_HEADER tableHeader; PCONNECTION connection; KIRQL oldIrql; ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql ); for ( i = 1; i < ENDPOINT_LOCK_COUNT ; i++ ) { ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) ); } tableHeader = &Endpoint->ConnectionTable; for ( i = *Index + 1; i < tableHeader->TableSize; i++ ) { connection = (PCONNECTION)tableHeader->Table[i].Owner; if ( (connection != NULL) && (GET_BLOCK_STATE(connection) == BlockStateActive) ) { *Index = i; SrvReferenceConnectionLocked( connection ); goto exit; } } connection = NULL; exit: for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) { RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) ); } RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql ); return connection; } // WalkConnectionTable
VOID DeferredLpxReceiveComplete ( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) { PDEVICE_CONTEXT deviceContext = DeferredContext; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SystemArgument1 ); UNREFERENCED_PARAMETER( SystemArgument2 ); LpxReceiveComplete2( deviceContext, &deviceContext->DeferredLpxReceiveCompleteDpcPacketList ); ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); deviceContext->DeferredLpxReceiveCompleteDpcRun = FALSE; RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); LpxReceiveComplete( deviceContext ); LpxDereferenceDeviceContext( "DeferredLpxReceiveComplete", deviceContext, DCREF_REQUEST ); }
VOID LpxReceiveComplete ( IN NDIS_HANDLE BindingContext ) { #if 1 PDEVICE_CONTEXT deviceContext = (PDEVICE_CONTEXT)BindingContext; BOOLEAN queued; ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); IF_LPXDBG(LPX_DEBUG_TEST) ASSERT( FALSE ); if (IsListEmpty(&deviceContext->PacketInProgressList)) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); return; } if (deviceContext->DeferredLpxReceiveCompleteDpcRun == TRUE) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); return; } LPX_ASSERT( IsListEmpty(&deviceContext->DeferredLpxReceiveCompleteDpcPacketList) ); deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Flink = deviceContext->PacketInProgressList.Flink; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Blink = deviceContext->PacketInProgressList.Blink; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Flink->Blink = &deviceContext->DeferredLpxReceiveCompleteDpcPacketList; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Blink->Flink = &deviceContext->DeferredLpxReceiveCompleteDpcPacketList; InitializeListHead( &deviceContext->PacketInProgressList ); // // Perform actual LPX receive completion // If the completion is deferred, queue the DPC. // Some NIC drivers show receiving performance degrade // when receive complete routine consumes much CPU time. // Ex> Broadcom Giga ehternet 3788. driver name = b57nd60x.sys 11/1/2005/11:30 164KB // LpxReferenceDeviceContext( "LpxReceiveComplete", deviceContext, DCREF_REQUEST ); deviceContext->DeferredLpxReceiveCompleteDpcRun = TRUE; queued = KeInsertQueueDpc( &deviceContext->DeferredLpxReceiveCompleteDpc, NULL, NULL ); if (queued) { } else { LPX_ASSERT( FALSE ); deviceContext->DeferredLpxReceiveCompleteDpcRun = FALSE; LpxDereferenceDeviceContext( "LpxReceiveComplete", deviceContext, DCREF_REQUEST ); } if (queued == FALSE) { deviceContext->DeferredLpxReceiveCompleteDpcRun = TRUE; } RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); if (queued == FALSE) { LpxReceiveComplete2( BindingContext, &deviceContext->DeferredLpxReceiveCompleteDpcPacketList ); ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); deviceContext->DeferredLpxReceiveCompleteDpcRun = FALSE; RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); } #else PDEVICE_CONTEXT deviceContext = (PDEVICE_CONTEXT)BindingContext; PRX_COMP_DPC_CTX rxCompDpcCtx; LIST_ENTRY receivedPackets; ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); IF_LPXDBG(LPX_DEBUG_TEST) ASSERT( FALSE ); if (FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_DEFFERED_DPC_SET)) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); return; } if (deviceContext->SendingThreadCount) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); return; } if (IsListEmpty(&deviceContext->PacketInProgressList)) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); return; } // // Allocate a DPC context // rxCompDpcCtx = ExAllocateFromNPagedLookasideList(&deviceContext->DeferredRxCompContext); if (rxCompDpcCtx == NULL) { LPX_ASSERT( FALSE ); RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); return; } // // Move received packets from the in-progress list to the temporary list. // LpxReceiveComplete2() will process only packets in this temporary list. // By doing this, we can spread out time-consume in LpxReceiveComplete2(). // Especially, deferred LpxReceiveComplete2() in DPC routine does not // need to loop and timeout-check because LpxReceiveComplete2() will process // only packets in the temporary list. // if(rxCompDpcCtx) { KeInitializeDpc(&rxCompDpcCtx->Dpc, DeferredRxCompleteDpc, rxCompDpcCtx); rxCompDpcCtx->DeviceContext = deviceContext; rxCompDpcCtx->ReceivedPackets.Flink = deviceContext->PacketInProgressList.Flink; rxCompDpcCtx->ReceivedPackets.Blink = deviceContext->PacketInProgressList.Blink; deviceContext->PacketInProgressList.Flink->Blink = &rxCompDpcCtx->ReceivedPackets; deviceContext->PacketInProgressList.Blink->Flink = &rxCompDpcCtx->ReceivedPackets; } else { receivedPackets.Flink = deviceContext->PacketInProgressList.Flink; receivedPackets.Blink = deviceContext->PacketInProgressList.Blink; deviceContext->PacketInProgressList.Flink->Blink = &receivedPackets; deviceContext->PacketInProgressList.Blink->Flink = &receivedPackets; } InitializeListHead(&deviceContext->PacketInProgressList); // // Perform actual LPX receive completion // If the completion is deferred, queue the DPC. // Some NIC drivers show receiving performance degrade // when receive complete routine consumes much CPU time. // Ex> Broadcom Giga ehternet 3788. driver name = b57nd60x.sys 11/1/2005/11:30 164KB // if(rxCompDpcCtx) { BOOLEAN queued; LpxReferenceDeviceContext("RxCompDpc", deviceContext, DCREF_REQUEST); queued = KeInsertQueueDpc(&rxCompDpcCtx->Dpc, NULL, NULL); ASSERT(queued); if(!queued) { LpxDereferenceDeviceContext("RxCompDpc", deviceContext, DCREF_REQUEST); } else { SetFlag( deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_DEFFERED_DPC_SET ); } RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); } else { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock); // Call actual LPX receive completion directly. LpxReceiveComplete2( BindingContext, &receivedPackets ); } #endif }
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 */
VOID ActivateReceive( PTP_CONNECTION Connection ) /*++ Routine Description: This routine activates the next TdiReceive request on the specified connection object if there is no active request on that connection already. This allows the request to accept data on the connection. NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL. Arguments: Connection - Pointer to a TP_CONNECTION object. Return Value: none. --*/ { PIRP Irp; ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL); IF_NBFDBG (NBF_DEBUG_RCVENG) { NbfPrint0 (" ActivateReceive: Entered.\n"); } // // The ACTIVE_RECEIVE bitflag will be set on the connection if // the receive-fields in the CONNECTION object are valid. If // this flag is cleared, then we try to make the next TdiReceive // request in the ReceiveQueue the active request. // ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) { if (!IsListEmpty (&Connection->ReceiveQueue)) { // // Found a receive, so make it the active one. // Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE; Irp = CONTAINING_RECORD( Connection->ReceiveQueue.Flink, IRP, Tail.Overlay.ListEntry); Connection->MessageBytesReceived = 0; Connection->MessageBytesAcked = 0; Connection->MessageInitAccepted = 0; Connection->CurrentReceiveIrp = Irp; Connection->CurrentReceiveSynchronous = Connection->Provider->MacInfo.SingleReceive; Connection->CurrentReceiveMdl = Irp->MdlAddress; Connection->ReceiveLength = IRP_RECEIVE_LENGTH(IoGetCurrentIrpStackLocation(Irp)); Connection->ReceiveByteOffset = 0; } } RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock); IF_NBFDBG (NBF_DEBUG_RCVENG) { NbfPrint0 (" ActivateReceive: Exiting.\n"); } } /* ActivateReceive */
VOID LpxReceiveComplete ( IN NDIS_HANDLE BindingContext ) { PDEVICE_CONTEXT deviceContext = (PDEVICE_CONTEXT)BindingContext; BOOLEAN queued; ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); IF_LPXDBG (LPX_DEBUG_TEST) { NDAS_ASSERT(FALSE); } if (IsListEmpty(&deviceContext->PacketInProgressList)) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); return; } if (deviceContext->DeferredLpxReceiveCompleteDpcRun == TRUE) { RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); return; } NDAS_ASSERT( IsListEmpty(&deviceContext->DeferredLpxReceiveCompleteDpcPacketList) ); deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Flink = deviceContext->PacketInProgressList.Flink; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Blink = deviceContext->PacketInProgressList.Blink; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Flink->Blink = &deviceContext->DeferredLpxReceiveCompleteDpcPacketList; deviceContext->DeferredLpxReceiveCompleteDpcPacketList.Blink->Flink = &deviceContext->DeferredLpxReceiveCompleteDpcPacketList; InitializeListHead( &deviceContext->PacketInProgressList ); // Perform actual LPX receive completion // If the completion is deferred, queue the DPC. // Some NIC drivers show receiving performance degrade // when receive complete routine consumes much CPU time. // Ex> Broadcom Giga ehternet 3788. driver name = b57nd60x.sys 11/1/2005/11:30 164KB LpxReferenceDeviceContext( "LpxReceiveComplete", deviceContext, DCREF_REQUEST ); NDAS_ASSERT( deviceContext->DeferredLpxReceiveCompleteDpcRun == FALSE ); queued = KeInsertQueueDpc( &deviceContext->DeferredLpxReceiveCompleteDpc, NULL, NULL ); if (queued == FALSE) { NDAS_ASSERT(FALSE); LpxDereferenceDeviceContext( "LpxReceiveComplete", deviceContext, DCREF_REQUEST ); } deviceContext->DeferredLpxReceiveCompleteDpcRun = TRUE; RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); if (queued == FALSE) { LpxReceiveComplete2( BindingContext, &deviceContext->DeferredLpxReceiveCompleteDpcPacketList ); ACQUIRE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); deviceContext->DeferredLpxReceiveCompleteDpcRun = FALSE; RELEASE_DPC_SPIN_LOCK( &deviceContext->PacketInProgressQSpinLock ); } return; }