/*++ Copyright (c) 1996 Microsoft Corporation Module Name: arapdbg.c Abstract: This module implements all debug utilities used by ARAP Author: Shirish Koti Revision History: 26 March 1997 Initial Version --*/ #include #pragma hdrstop // File module number for errorlogging #define FILENUM ARAPDBG #define ALIGN8(Ptr) ( (((ULONG_PTR)(Ptr))+7) & (~7) ) // // The following are debug-only routines. These routines help us catch bad // things before they do damage, and help us sleep better at night. // #if DBG DWORD ArapDbgDumpOnDisconnect = 0; //*** // // Function: ArapProcessSniff // Stores the sniff irp. Next time some connection needs to return // the sniff info, use this irp. // // Parameters: pIrp - the Sniff irp to process // // Return: result of the operation // //***$ NTSTATUS ArapProcessSniff( IN PIRP pIrp ) { KIRQL OldIrql; PARAP_SEND_RECV_INFO pSndRcvInfo; ARAPTRACE(("Entered ArapProcessSniff (%lx)\n",pIrp)); ACQUIRE_SPIN_LOCK(&ArapSpinLock, &OldIrql); // store the irp (we can only have one Sniff irp at a time) ASSERT (ArapSniffIrp == NULL); if (ArapSniffIrp != NULL) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapProcessSniff: Sniff irp %lx already in progress!\n", ArapSniffIrp)); pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer; pSndRcvInfo->StatusCode = ARAPERR_IRP_IN_PROGRESS; RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql); return( STATUS_SUCCESS ); } ArapSniffIrp = pIrp; RELEASE_SPIN_LOCK(&ArapSpinLock, OldIrql); return(STATUS_PENDING); } //*** // // Function: ArapDumpSniffInfo // If we have collected enough sniff info, complete the sniff irp // // Parameters: pArapConn - connection in question // // Return: TRUE if we returned info to dll, FALSE otherwise // //***$ BOOLEAN ArapDumpSniffInfo( IN PARAPCONN pArapConn ) { PIRP pIrp; DWORD dwBytesToDll; NTSTATUS ReturnStatus=STATUS_SUCCESS; // if we don't have a sniff buffer (or no bytes in it), get out if (!pArapConn->pDbgTraceBuffer || pArapConn->SniffedBytes == 0) { return(FALSE); } // // if we have less than 500 bytes in the buffer, and we aren't disconnecting // or disconnected, don't complete the irp as yet // (it's ok not have spinlock here) // if ((pArapConn->SniffedBytes < 500) && (pArapConn->State == MNP_UP )) { return(FALSE); } ARAP_GET_SNIFF_IRP(&pIrp); // no sniff irp available? can't do much, leave if (!pIrp) { return(FALSE); } dwBytesToDll = ArapFillIrpWithSniffInfo(pArapConn,pIrp) + sizeof(ARAP_SEND_RECV_INFO); // ok, complete that irp now! ARAP_COMPLETE_IRP(pIrp, dwBytesToDll, STATUS_SUCCESS, &ReturnStatus); return(TRUE); } //*** // // Function: ArapFillIrpWithSniffInfo // Copy the sniff bytes into the irp // // Parameters: pArapConn - connection in question // pIrp - the irp to fill data in // (except in one case, this irp will be the sniff irp. // The exception case is where disconnect has occured and // and at that time, a sniff irp wasn't available. In that // case, we use the select irp that's carrying the disconnect // info to send the remaining sniff bytes). // // Return: Number of sniff bytes that were copied in // //***$ DWORD ArapFillIrpWithSniffInfo( IN PARAPCONN pArapConn, IN PIRP pIrp ) { PARAP_SEND_RECV_INFO pSndRcvInfo=NULL; KIRQL OldIrql; DWORD SniffedBytes; PBYTE pStartData; DWORD dwBytesToDll; ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql); pSndRcvInfo = (PARAP_SEND_RECV_INFO)pIrp->AssociatedIrp.SystemBuffer; // // if buffer is smaller than how much data we have, adjust by ignoring // bytes in the beginning of the buffer // if (pSndRcvInfo->DataLen < pArapConn->SniffedBytes) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ArapFill...Info: chopping %d bytes in the beginning\n", (pArapConn->SniffedBytes - pSndRcvInfo->DataLen))); pStartData = pArapConn->pDbgTraceBuffer + (pArapConn->SniffedBytes - pSndRcvInfo->DataLen); pArapConn->SniffedBytes = pSndRcvInfo->DataLen; } else { pStartData = pArapConn->pDbgTraceBuffer; } SniffedBytes = pArapConn->SniffedBytes; // ok, copy the data in RtlCopyMemory( &pSndRcvInfo->Data[0], pStartData, SniffedBytes ); pArapConn->pDbgCurrPtr = pArapConn->pDbgTraceBuffer; pArapConn->SniffedBytes = 0; RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql); // set the info (contexts need to be set each time in case of select) pSndRcvInfo->AtalkContext = pArapConn; pSndRcvInfo->pDllContext = pArapConn->pDllContext; pSndRcvInfo->DataLen = SniffedBytes; pSndRcvInfo->StatusCode = ARAPERR_NO_ERROR; return(SniffedBytes); } //*** // // Function: DbgChkRcvQIntegrity // This routine looks at the first buffer on the receive queue and // verifies that things look reasonable // // Parameters: pArapConn - the connection in question // // Return: TRUE if things look reasonable, FALSE otherwise // // NOTES: IMPORTANT: spinlock must be held before calling this routine // //***$ BOOLEAN DbgChkRcvQIntegrity( IN PARAPCONN pArapConn ) { PLIST_ENTRY pList; PARAPBUF pArapBuf; PBYTE packet; USHORT SrpLen; pList = pArapConn->ReceiveQ.Flink; if (pList == &pArapConn->ReceiveQ) { return( TRUE ); } if (!(pArapConn->Flags & ARAP_CONNECTION_UP)) { return( TRUE ); } pArapBuf = CONTAINING_RECORD(pList, ARAPBUF, Linkage); // wait until more bytes show up if (pArapBuf->DataSize < 6) { return( TRUE ); } packet = pArapBuf->CurrentBuffer; GETSHORT2SHORT(&SrpLen, pArapBuf->CurrentBuffer); if (SrpLen > ARAP_MAXPKT_SIZE_INCOMING) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ARAP: packet too big (%d bytes) in %lx)\n",SrpLen,pArapBuf)); return(FALSE); } if ((packet[2] != 0x50) && (packet[2] != 0x10)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ARAP: wrong DGroup byte (%x) in %lx)\n",packet[2],pArapBuf)); return(FALSE); } if (packet[2] == 0x50) { if ((packet[3] != 0) || (packet[4] != 0) || (packet[5] != 2)) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("ARAP (%lx): wrong LAP hdr in %lx)\n",pArapBuf)); return(FALSE); } } return( TRUE ); } //*** // // Function: DbgDumpBytes // This routine dumps first 64 bytes from a buffer to the debugger // // Parameters: pDbgMsg - string to print before the bytes (optional) // pBuffer - buffer from which to dump the bytes // BufLen - how big is the buffer // DumpLevel - if this matches ArapDumpLevel, we dump the bytes // // Return: Nothing // //***$ VOID DbgDumpBytes( IN PBYTE pDbgMsg, IN PBYTE pBuffer, IN DWORD BufLen, IN DWORD DumpLevel ) { BYTE OutBuf[400]; DWORD NextIndex; DWORD dwBytesToDump; if (ArapDumpLevel != DumpLevel) { return; } if (pDbgMsg) { DbgPrint("%s (pkt len = %d)\n",pDbgMsg,BufLen); } else { DbgPrint("Dumping packet (pkt len = %d)\n",BufLen); } // dump the first 64 bytes dwBytesToDump = (BufLen <= 64)? BufLen : 64; dwBytesToDump = (dwBytesToDump < ArapDumpLen)?dwBytesToDump:ArapDumpLen; DbgDumpBytesPart2( pBuffer, OutBuf, dwBytesToDump, &NextIndex ); OutBuf[NextIndex] = '\n'; OutBuf[NextIndex+1] = 0; DbgPrint("%s",OutBuf); } //*** // // Function: DbgDumpBytesPart2 // This is a helper routine for the DbgDumpBytes routine //***$ VOID DbgDumpBytesPart2( IN PBYTE pBuffer, OUT PBYTE OutBuf, IN DWORD BufLen, OUT DWORD *NextIndex ) { BYTE Byte; BYTE nibble; DWORD i, j; j = 0; OutBuf[j++] = ' '; OutBuf[j++] = ' '; OutBuf[j++] = ' '; OutBuf[j++] = ' '; for (i=0; i> 4); OutBuf[j++] = (nibble < 10) ? ('0' + nibble) : ('a' + (nibble-10)); nibble = (Byte & 0x0f); OutBuf[j++] = (nibble < 10) ? ('0' + nibble) : ('a' + (nibble-10)); OutBuf[j++] = ' '; if (((i+1) % 16) == 0) { OutBuf[j++] = '\n'; OutBuf[j++] = ' '; OutBuf[j++] = ' '; OutBuf[j++] = ' '; OutBuf[j++] = ' '; } else if (((i+1) % 8) == 0) { OutBuf[j++] = ' '; } } *NextIndex = j; return; } //*** // // Function: DbgDumpNetworkNumbers // This routine dumps out all the network ranges that exist on the // network. // // Parameters: None // // Return: Nothing // //***$ VOID DbgDumpNetworkNumbers( IN VOID ) { KIRQL OldIrql; PRTE pRte, pNext; int i; ACQUIRE_SPIN_LOCK(&AtalkRteLock, &OldIrql); for (i = 0; i < NUM_RTMP_HASH_BUCKETS; i++) { for (pRte = AtalkRoutingTable[i]; pRte != NULL; pRte = pNext) { pNext = pRte->rte_Next; ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock); DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, (" pRte: %lx LowEnd %lx HighEnd %lx\n", pRte,pRte->rte_NwRange.anr_FirstNetwork,pRte->rte_NwRange.anr_LastNetwork)); RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); } } RELEASE_SPIN_LOCK(&AtalkRteLock, OldIrql); } //*** // // Function: DbgTrackInfo // This routine tracks various information, useful in arriving at // optimum buffer sizes, etc. // // Parameters: pArapConn - the connection in question // Size - size of the buffer (incoming, outgoing, as appropriate) // TrackingWhat - what are we tracking (sends, recvs etc.) // // Return: Nothing // //***$ VOID DbgTrackInfo( IN PARAPCONN pArapConn, IN DWORD Size, IN DWORD TrackingWhat ) { // // track the MNP send sizes (how many are 0-10 bytes, 11-20 bytes, etc.) // if (TrackingWhat == 1) { ArapDbgMnpSendSizes[Size/10]++; return; } } //*** // // Function: ArapDbgTrace // This routine traces (keeps a log) of all the events (data going // in/out, acks going in/out, error conditions etc. // // Parameters: pArapConn - the connection in question // Location - who is logging this event (the location decides what // the other parms are going to be) // Context - depends on Location (e.g.could be data buffer) // dwInfo1 - depends on Location // dwInfo2 - depends on Location // dwInfo3 - depends on Location // // Return: Nothing // // NOTE: Spinlock is assumed to be held // //***$ VOID ArapDbgTrace( IN PARAPCONN pArapConn, IN DWORD Location, IN PVOID Context, IN DWORD dwInfo1, IN DWORD dwInfo2, IN DWORD dwInfo3 ) { LARGE_INTEGER CurrTime; LARGE_INTEGER DiffTime; PBYTE pStartTrace; PBYTE pTrace; PBUFFER_DESC pBuffDesc; PARAPBUF pArapBuf; PMNPSENDBUF pMnpSendBuf; PBYTE pCurrBuff; DWORD BufLenSoFar=0; USHORT Delta; BYTE Priority; DWORD BytesCopied=0; DWORD BytesAvailable; USHORT DbgInfoLen; PSNIFF_INFO pSniff; DWORD i; if (!pArapConn->pDbgTraceBuffer) { return; } KeQuerySystemTime(&CurrTime); DiffTime = RtlLargeIntegerSubtract(CurrTime, ArapDbgLastTraceTime); ArapDbgLastTraceTime = CurrTime; // do the conversion to get ms Delta = (USHORT)(DiffTime.LowPart); pSniff = (PSNIFF_INFO)(pArapConn->pDbgCurrPtr); pTrace = pStartTrace = &pSniff->Frame[0]; // put signature (starting of a "frame") pSniff->Signature = ARAP_SNIFF_SIGNATURE; // time since last event pSniff->TimeStamp = (DWORD)AtalkGetCurrentTick(); // who is logging this info pSniff->Location = (USHORT)Location; // // ok, now see who has called us and log the relevant info // If we can't find the Location, it's ok: we have the Location number // logged and and that's adequate (that's why we can't find Location) // switch (Location) { // data to client is about to be compressed: copy some info case 11205: pBuffDesc = (PBUFFER_DESC)Context; Priority = (BYTE)dwInfo1; while (pBuffDesc) { if (pBuffDesc->bd_Flags & BD_CHAR_BUFFER) { pCurrBuff = pBuffDesc->bd_CharBuffer; BytesAvailable = pBuffDesc->bd_Length; } else { pCurrBuff = MmGetSystemAddressForMdlSafe( pBuffDesc->bd_OpaqueBuffer, NormalPagePriority); if (pCurrBuff == NULL) { goto error_end; } BytesAvailable = MmGetMdlByteCount(pBuffDesc->bd_OpaqueBuffer); } // // if this buffer descriptor contains (usually exclusively) the // ARAP header, then get some info out of it and skip those bytes // if ((pCurrBuff[2] == 0x10 || pCurrBuff[2] == 0x50) && (pCurrBuff[3] == 0) && (pCurrBuff[4] == 0) && (pCurrBuff[5] == 2)) { *pTrace++ = pCurrBuff[0]; // srplen byte 1 *pTrace++ = pCurrBuff[1]; // srplen byte 2 *pTrace++ = pCurrBuff[2]; // ARAP or Atalk packet *pTrace++ = Priority; BytesAvailable -= 6; pCurrBuff += 6; } // copy first 48 bytes of the data packet while (BytesAvailable && BytesCopied < 48) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } pBuffDesc = pBuffDesc->bd_Next; } break; // we are sending out an ack case 11605: *pTrace++ = (BYTE)dwInfo1; // sequence num in our ack *pTrace++ = (BYTE)dwInfo2; // rcv credit in our ack break; // we are queuing compressed send bytes case 21205: *pTrace++ = (BYTE)dwInfo2; // priority of the send *pTrace++ = (BYTE)dwInfo3; // Start sequence for this send *pTrace++ = (BYTE)(pArapConn->MnpState.NextToSend-1); // end sequence BytesAvailable = dwInfo1; // len of compressed data pCurrBuff = (PBYTE)Context; // buffer with compressed data // copy first 24 bytes of the compressed data while (BytesAvailable && BytesCopied < 24) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } break; // ArapExtractSRP: we're handing over 1 srp for routing or to dll case 21105: pArapBuf = (PARAPBUF)Context; pCurrBuff = pArapBuf->CurrentBuffer; BytesAvailable = pArapBuf->DataSize; // copy first 48 bytes of the decompressed data while (BytesAvailable && BytesCopied < 48) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } break; // we just recvd a packet in ArapRcvIndication case 30105: BytesAvailable = dwInfo1-7; // lookahead size, minus start,stop,crc pCurrBuff = ((PBYTE)Context)+3; // lookahead buffer plus 3 start PUTSHORT2SHORT(pTrace,(USHORT)BytesAvailable); pTrace += sizeof(USHORT); // copy first 24 bytes of the compressed data while (BytesAvailable && BytesCopied < 24) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } break; // we recvd a 0-len packet! case 30106: break; // we decompressed the incoming data case 30110: // how much was the decompressed length PUTSHORT2SHORT(pTrace,(USHORT)dwInfo1); pTrace += sizeof(USHORT); if (dwInfo1 == 0) { break; } pArapBuf = (PARAPBUF)Context; BytesAvailable = pArapBuf->DataSize; // len of decompressed data pCurrBuff = pArapBuf->CurrentBuffer; // copy first 48 bytes of the decompressed data while (BytesAvailable && BytesCopied < 48) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } break; // attempting send when state was >= MNP_LDISCONNECTING case 30305: *pTrace = (BYTE)dwInfo1; // store pArapConn->State break; // we just sent out a packet in ArapNdisSend() case 30320: pMnpSendBuf = (PMNPSENDBUF)Context; *pTrace++ = pMnpSendBuf->SeqNum; // how big is the MNP packet PUTSHORT2SHORT(pTrace,pMnpSendBuf->DataSize); pTrace += sizeof(USHORT); *pTrace++ = (BYTE)dwInfo1; // is this a retransmission BytesAvailable = pMnpSendBuf->DataSize; pCurrBuff = (&pMnpSendBuf->Buffer[0]) + 3; // skip start bytes // copy first 24 bytes of the compressed data while (BytesAvailable && BytesCopied < 24) { *pTrace++ = *pCurrBuff++; BytesCopied++; BytesAvailable--; } default: break; } DbgInfoLen = (USHORT)(pTrace - pStartTrace); pSniff->FrameLen = DbgInfoLen; pArapConn->pDbgCurrPtr = (PBYTE)ALIGN8(pTrace); // fill up the round-up space with 0s for (NOTHING; pTrace < pArapConn->pDbgCurrPtr; pTrace++) { *pTrace = 0; } // make sure we haven't overrun this buffer ASSERT(*((DWORD *)&(pArapConn->pDbgTraceBuffer[ARAP_SNIFF_BUFF_SIZE-4])) == 0xcafebeef); // how many more bytes did we add to the sniff buff? pArapConn->SniffedBytes += (DWORD)(pArapConn->pDbgCurrPtr - (PBYTE)pSniff); // // if we are about to overflow, just reset the pointer to beginning // (do it while we have still 200 bytes left) // BufLenSoFar = (DWORD)(pArapConn->pDbgCurrPtr - pArapConn->pDbgTraceBuffer); error_end: if (BufLenSoFar > ARAP_SNIFF_BUFF_SIZE-200) { DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_INFO, ("ArapDbgTrace: resetting debug buffer, Sniff data LOST!\n")); pArapConn->pDbgCurrPtr = pArapConn->pDbgTraceBuffer; pArapConn->SniffedBytes = 0; } } //*** // // Function: ArapDbgTrace // This routine records history of MNP level packet exchange // // Parameters: pArapConn - the connection in question // Seq - sequence number (if applicable) // FrameType - LT, LA etc. // // Return: Nothing // // NOTE: Spinlock is assumed to be held // //***$ VOID ArapDbgMnpHist( IN PARAPCONN pArapConn, IN BYTE Seq, IN BYTE FrameType ) { LARGE_INTEGER TimeNow; DWORD ThisDelta; DWORD DbgMnpIndex; KeQuerySystemTime(&TimeNow); if (TimeNow.HighPart == pArapConn->LastTimeStamp.HighPart) { ThisDelta = (TimeNow.LowPart - pArapConn->LastTimeStamp.LowPart); } else { ThisDelta = (0xffffffff - pArapConn->LastTimeStamp.LowPart + TimeNow.LowPart); } // convert 100's ns to ms ThisDelta = (ThisDelta/10000); pArapConn->LastTimeStamp = TimeNow; pArapConn->DbgMnpHist[pArapConn->DbgMnpIndex].TimeStamp = ThisDelta; pArapConn->DbgMnpHist[pArapConn->DbgMnpIndex].FrameInfo = (FrameType << 16); pArapConn->DbgMnpHist[pArapConn->DbgMnpIndex].FrameInfo |= Seq; // wrap-around if necessary if ((++pArapConn->DbgMnpIndex) >= DBG_MNP_HISTORY_SIZE) { pArapConn->DbgMnpIndex = 0; } } //*** // // Function: ArapDbgDumpMnpHistory // This routine dumps history of MNP level packet exchange // // Parameters: pArapConn - the connection in question // // Return: Nothing // //***$ VOID ArapDbgDumpMnpHist( IN PARAPCONN pArapConn ) { DWORD i; DWORD dwTmp; DWORD dwDelta; BYTE TmpSeq; if (!ArapDbgDumpOnDisconnect) { return; } DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("DerefArapConn: Past history on %lx .....\n", pArapConn)); // dump all info: old info first for (i=pArapConn->DbgMnpIndex; iDbgMnpHist[i].TimeStamp; dwTmp = (pArapConn->DbgMnpHist[i].FrameInfo & 0xffff0000); TmpSeq = (BYTE)(pArapConn->DbgMnpHist[i].FrameInfo & 0x000000ff); switch (dwTmp) { case 0x40000 : DbgPrint(" %6ld NT sends %x\n",dwDelta,TmpSeq);break; case 0x50000 : DbgPrint(" %6ld NT acks %x\n",dwDelta,TmpSeq);break; case 0x140000: DbgPrint(" %6ld Mac sends %x\n",dwDelta,TmpSeq);break; case 0x150000: DbgPrint(" %6ld Mac acks %x\n",dwDelta,TmpSeq);break; default : DbgPrint(" %6ld Unknown: %lx\n",dwDelta,pArapConn->DbgMnpHist[i].FrameInfo); } } // dump the current info for (i=0; iDbgMnpIndex; i++) { dwDelta = pArapConn->DbgMnpHist[i].TimeStamp; dwTmp = (pArapConn->DbgMnpHist[i].FrameInfo & 0xffff0000); TmpSeq = (BYTE)(pArapConn->DbgMnpHist[i].FrameInfo & 0x000000ff); switch (dwTmp) { case 0x40000 : DbgPrint(" %6ld NT sends %x\n",dwDelta,TmpSeq);break; case 0x50000 : DbgPrint(" %6ld NT acks %x\n",dwDelta,TmpSeq);break; case 0x140000: DbgPrint(" %6ld Mac sends %x\n",dwDelta,TmpSeq);break; case 0x150000: DbgPrint(" %6ld Mac acks %x\n",dwDelta,TmpSeq);break; default : DbgPrint(" %6ld Unknown: %lx\n",dwDelta,pArapConn->DbgMnpHist[i].FrameInfo); } } } //*** // // Function: ArapDumpNdisPktInfo // walk the ARAP connections list and find out how many Ndis packets // are in use right now // // Parameters: nothing // // Return: nothing // //***$ VOID ArapDumpNdisPktInfo( IN VOID ) { PARAPCONN pArapConn; PLIST_ENTRY pConnList; PLIST_ENTRY pList; PMNPSENDBUF pMnpSendBuf; KIRQL OldIrql; DWORD GrandTotal; DWORD ReXmit; DWORD ReXmitInNdis; DWORD Fresh; DWORD FreshInNdis; DWORD ThisConn; DWORD NumConns; if (!RasPortDesc) { return; } ACQUIRE_SPIN_LOCK(&RasPortDesc->pd_Lock, &OldIrql); pConnList = RasPortDesc->pd_ArapConnHead.Flink; GrandTotal = 0; NumConns = 0; DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("NdisPacketInfo: counting total number of ndis packets used by ARAP....\n")); // // first, let's find the right connection to work on // while (pConnList != &RasPortDesc->pd_ArapConnHead) { ReXmit = 0; ReXmitInNdis = 0; Fresh = 0; FreshInNdis = 0; ThisConn = 0; pConnList = pConnList->Flink; pArapConn = CONTAINING_RECORD(pConnList, ARAPCONN, Linkage); ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock); pList = pArapConn->RetransmitQ.Flink; // collect all buffers on the retransmit queue first while (pList != &pArapConn->RetransmitQ) { pList = pList->Flink; pMnpSendBuf = CONTAINING_RECORD(pList, MNPSENDBUF, Linkage); ReXmit++; if (pMnpSendBuf->Flags == 1) { ReXmitInNdis++; } } pList = pArapConn->HighPriSendQ.Flink; // collect all buffers on the fresh send while (pList != &pArapConn->HighPriSendQ) { pList = pList->Flink; pMnpSendBuf = CONTAINING_RECORD(pList, MNPSENDBUF, Linkage); Fresh++; if (pMnpSendBuf->Flags == 1) { FreshInNdis++; } } ThisConn = ReXmit+ReXmitInNdis+Fresh+FreshInNdis; DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, (" %ld packets on %lx, %d in Ndis (%d+%d+%d+%d)\n", ThisConn,pArapConn,ReXmitInNdis,ReXmit,ReXmitInNdis,Fresh,FreshInNdis)); GrandTotal += ThisConn; NumConns++; RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock); } RELEASE_SPIN_LOCK(&RasPortDesc->pd_Lock, OldIrql); DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR, ("NdisPacketInfo: total of %ld Ndis Packets on %d connections\n", GrandTotal, NumConns)); } #endif // DBG