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 }
NDIS_STATUS LpxReceiveIndication ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: This routine receives control from the physical provider as an indication that a frame has been received on the physical link. This routine is time critical, so we only allocate a buffer and copy the packet into it. We also perform minimal validation on this packet. It gets queued to the device context to allow for processing later. Arguments: BindingContext - The Adapter Binding specified at initialization time. ReceiveContext - A magic cookie for the MAC. HeaderBuffer - pointer to a buffer containing the packet header. HeaderBufferSize - the size of the header. LookaheadBuffer - pointer to a buffer containing the negotiated minimum amount of buffer I get to look at (not including header). LookaheadBufferSize - the size of the above. May be less than asked for, if that's all there is. PacketSize - Overall size of the packet (not including header). Return Value: NDIS_STATUS - status of operation, one of: NDIS_STATUS_SUCCESS if packet accepted, NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol, NDIS_any_other_thing if I understand, but can't handle. --*/ { PDEVICE_CONTEXT deviceContext; USHORT protocol; PNDIS_PACKET packet; NDIS_STATUS status; UINT bytesTransfered = 0; UINT startOffset = 0; DebugPrint( 4, ("LpxReceiveIndication, Entered\n") ); deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; // // validation // if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) { DebugPrint( 4, ("HeaderBufferSize = %x\n", HeaderBufferSize) ); return NDIS_STATUS_NOT_ACCEPTED; } RtlCopyMemory( (PUCHAR)&protocol, &((PUCHAR)HeaderBuffer)[12], sizeof(USHORT) ); // // Discard 802.2 LLC SNAP field. // // if Ether Type less than 0x0600 ( 1536 ) // if (NTOHS(protocol) < 0x0600 && protocol != HTONS(0x0060) && // LOOP: Ethernet Loopback protocol != HTONS(0x0200) && // PUP : Xerox PUP packet protocol != HTONS(0x0201)) { // PUPAP: Xerox PUP address trans packet #ifdef __LPX__ NdisCopyLookaheadData( (PUCHAR)&protocol, &((PUCHAR)LookAheadBuffer)[LENGTH_8022LLCSNAP - 2], sizeof(USHORT), deviceContext->MacOptions ); #endif PacketSize -= LENGTH_8022LLCSNAP; LookAheadBufferSize -= LENGTH_8022LLCSNAP; startOffset = LENGTH_8022LLCSNAP; } if (protocol != HTONS(ETH_P_LPX)) { DebugPrint( 4, ("Type = %x\n", protocol) ); return NDIS_STATUS_NOT_ACCEPTED; } // // Check to see if the device context is initialized. // //ACQUIRE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) { //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); DebugPrint( 4,("Device is not initialized. Drop packet\n") ); return NDIS_STATUS_NOT_ACCEPTED; } ASSERT( deviceContext->NdisBindingHandle ); //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); // // DROP PACKET for DEBUGGING!!!! // #if 1 //DBG // Enabled for testing if (PacketRxDropRate) { PacketRxCountForDrop++; if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) { PLPX_HEADER lpxHeader = (PLPX_HEADER)LookAheadBuffer; #if 0 if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) DebugPrint( 1, ("[Drop(%x,%x,%x))]\n", NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) ); #endif DebugPrint( 1, ("D") ); return NDIS_STATUS_NOT_ACCEPTED; } } #endif ASSERT( startOffset == 0 ); DebugPrint( 4, ("LpxReceiveIndication, PacketSize = %d, LookAheadBufferSize = %d, LPX_HEADER size = %d\n", PacketSize, LookAheadBufferSize, sizeof(LPX_HEADER)) ); if (LookAheadBufferSize - startOffset >= sizeof(LPX_HEADER)) { PNDIS_BUFFER firstBuffer; PUCHAR packetData; PLPX_HEADER lpxHeader; USHORT lpxHeaderSize; lpxHeader = (PLPX_HEADER)((PBYTE)LookAheadBuffer + startOffset); lpxHeaderSize = sizeof(LPX_HEADER); if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) == lpxHeaderSize) { status = RcvPacketAlloc( deviceContext, 0, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = 0; RESERVED(packet)->PacketRawDataOffset = 0; LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else if (LookAheadBufferSize - startOffset >= NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) { status = RcvPacketAlloc( deviceContext, NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize; RESERVED(packet)->PacketRawDataOffset = 0; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); packetData = MmGetMdlVirtualAddress( firstBuffer ); NdisCopyLookaheadData( packetData, (PBYTE)LookAheadBuffer + startOffset + lpxHeaderSize, RESERVED(packet)->PacketRawDataLength, deviceContext->MacOptions ); LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else { status = RcvPacketAlloc( deviceContext, startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK), &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(packet)->PacketRawDataOffset = startOffset + lpxHeaderSize; } } } else { PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; ASSERT( FALSE ); status = RcvPacketAlloc( deviceContext, PacketSize, &packet ); if (status == STATUS_SUCCESS) { RtlCopyMemory( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RESERVED(packet)->PacketRawDataLength = PacketSize; RESERVED(packet)->PacketRawDataOffset = startOffset; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(packet)->PacketRawDataOffset); RtlZeroMemory( lpxHeader, sizeof(LPX_HEADER) ); RESERVED(packet)->HeaderCopied = FALSE; } } if (status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_NOT_ACCEPTED; } ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (deviceContext->NdisBindingHandle) { //ASSERT( FALSE ); NdisTransferData( &status, deviceContext->NdisBindingHandle, MacReceiveContext, 0, //RESERVED(packet)->PacketRawDataOffset, RESERVED(packet)->PacketRawDataLength, packet, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { status = NDIS_STATUS_SUCCESS; } else if (status == NDIS_STATUS_SUCCESS) { LpxTransferDataComplete( deviceContext, packet, status, bytesTransfered ); } else { ASSERT( FALSE ); status = NDIS_STATUS_NOT_ACCEPTED; DebugPrint( 1, ("NdisTransferData() failed. STATUS=%08lx\n", status) ); } } else { RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); status = NDIS_STATUS_NOT_ACCEPTED; DebugPrint( 1, ("Invalid device status. STATUS=%08lx\n", status) ); } return status; }
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; }