windows-nt/Source/XPSP1/NT/net/1394/nic/sys/util.c

1221 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
//
// util.c
//
// IEEE1394 mini-port/call-manager driver
//
// General utility routines
//
// 12/28/1998 JosephJ Created, adapted from the l2tp sources.
//
#include "precomp.h"
// Debug counts of oddities that should not be happening.
//
ULONG g_ulAllocTwFailures = 0;
//-----------------------------------------------------------------------------
// Local prototypes (alphabetically)
//-----------------------------------------------------------------------------
ULONG
atoul(
IN CHAR* pszNumber );
VOID
ReversePsz(
IN OUT CHAR* psz );
VOID
TunnelWork(
IN NDIS_WORK_ITEM* pWork,
IN VOID* pContext );
VOID
ultoa(
IN ULONG ul,
OUT CHAR* pszBuf );
//-----------------------------------------------------------------------------
// General utility routines (alphabetically)
//-----------------------------------------------------------------------------
CHAR*
nicStrDup(
IN CHAR* psz )
// Return a duplicate of 'psz'. Caller must eventually call FREE_NONPAGED
// on the returned string.
//
{
return nicStrDupSized( psz, strlen( psz ), 0 );
}
CHAR*
nicStrDupNdisString(
IN NDIS_STRING* pNdisString )
// Returns null-terminated ASCII copy of the NDIS_STRING 'pNdisString'
// Caller must eventually call FREE_NONPAGED on the returned string.
//
{
CHAR* pszDup;
pszDup = ALLOC_NONPAGED( pNdisString->Length + 1, MTAG_UTIL );
if (pszDup)
{
NdisZeroMemory( pszDup, pNdisString->Length + 1 );
if (pNdisString->Length)
{
NdisMoveMemory( pszDup, pNdisString->Buffer, pNdisString->Length );
}
// NDIS_STRING is UNICODE_STRING on NT but need the corresponding
// ASCII (not multi-byte ANSI) value from NDIS_STRING on any system.
// If it looks like a Unicode string then "convert" it by picking out
// every other byte, hopefully all the non-zero ones. This is not
// foolproof, but then Unicode doesn't convert to ASCII in any
// foolproof way.
//
if (pNdisString->Length > 1 && pszDup[ 1 ] == '\0')
{
USHORT i;
for (i = 0; i * 2 < pNdisString->Length; ++i)
{
pszDup[ i ] = pszDup[ i * 2 ];
}
pszDup[ i ] = '\0';
}
}
return pszDup;
}
CHAR*
nicStrDupSized(
IN CHAR* psz,
IN ULONG ulLength,
IN ULONG ulExtra )
// Return a duplicate of the first 'ulLength' bytes of 'psz' followed by a
// null character and 'ulExtra' extra bytes, or NULL on error. Caller
// must eventually call FREE_NONPAGED on the returned string.
//
{
CHAR* pszDup;
pszDup = ALLOC_NONPAGED( ulLength + 1 + ulExtra, MTAG_UTIL );
if (pszDup)
{
if (ulLength)
{
NdisMoveMemory( pszDup, psz, ulLength );
}
pszDup[ ulLength ] = '\0';
}
return pszDup;
}
//-----------------------------------------------------------------------------
// Local utility routines (alphabetically)
//-----------------------------------------------------------------------------
ULONG
atoul(
IN CHAR* pszNumber )
// Convert string of digits 'pszNumber' to it's ULONG value.
//
{
ULONG ulResult;
ulResult = 0;
while (*pszNumber && *pszNumber >= '0' && *pszNumber <= '9')
{
ulResult *= 10;
ulResult += *pszNumber - '0';
++pszNumber;
}
return ulResult;
}
#if DBG
VOID
ReversePsz(
IN OUT CHAR* psz )
// Reverse the order of the characters in 'psz' in place.
//
{
CHAR* pchLeft;
CHAR* pchRight;
pchLeft = psz;
pchRight = psz + strlen( psz ) - 1;
while (pchLeft < pchRight)
{
CHAR ch;
ch = *pchLeft;
*pchLeft = *pchRight;
*pchRight = *pchLeft;
++pchLeft;
--pchRight;
}
}
#endif
#if DBG
VOID
ultoa(
IN ULONG ul,
OUT CHAR* pszBuf )
// Convert 'ul' to null-terminated string form in caller's 'pszBuf'. It's
// caller job to make sure 'pszBuf' is long enough to hold the returned
// string.
//
{
CHAR* pch;
pch = pszBuf;
do
{
*pch++ = (CHAR )((ul % 10) + '0');
ul /= 10;
}
while (ul);
*pch = '\0';
ReversePsz( pszBuf );
}
#endif
VOID
nicSetFlags(
IN OUT ULONG* pulFlags,
IN ULONG ulMask )
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
//
{
ULONG ulFlags;
ULONG ulNewFlags;
do
{
ulFlags = *pulFlags;
ulNewFlags = ulFlags | ulMask;
}
while (InterlockedCompareExchange(
pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
}
VOID
nicClearFlags(
IN OUT ULONG* pulFlags,
IN ULONG ulMask )
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
//
{
ULONG ulFlags;
ULONG ulNewFlags;
do
{
ulFlags = *pulFlags;
ulNewFlags = ulFlags & ~(ulMask);
}
while (InterlockedCompareExchange(
pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
}
ULONG
nicReadFlags(
IN ULONG* pulFlags )
// Read the value of '*pulFlags' as an interlocked operation.
//
{
return *pulFlags;
}
//
// Reference And Dereference functions taken directly from Ndis
//
BOOLEAN
nicReferenceRef(
IN PREF RefP
)
/*++
Routine Description:
Adds a reference to an object.
Arguments:
RefP - A pointer to the REFERENCE portion of the object.
Return Value:
TRUE if the reference was added.
FALSE if the object was closing.
--*/
{
BOOLEAN rc = TRUE;
KIRQL OldIrql;
TRACE( TL_V, TM_Ref, ( "nicReferenceRef, %.8x", RefP ) );
// NdisAcquireSpinLock (&RefP->SpinLock);
if (RefP->Closing)
{
rc = FALSE;
}
else
{
NdisInterlockedIncrement (&RefP->ReferenceCount);
}
// NdisReleaseSpinLock (&RefP->SpinLock);
TRACE( TL_V, TM_Ref, ( "nicReferenceRef, Bool %.2x, Ref %d", rc, RefP->ReferenceCount ) );
return(rc);
}
BOOLEAN
nicDereferenceRef(
IN PREF RefP
)
/*++
Routine Description:
Removes a reference to an object.
Arguments:
RefP - A pointer to the REFERENCE portion of the object.
Return Value:
TRUE if the reference count is now 0.
FALSE otherwise.
--*/
{
BOOLEAN rc = FALSE;
KIRQL OldIrql;
TRACE( TL_V, TM_Ref, ( "==>nicDeReferenceRef, %x", RefP ) );
// NdisAcquireSpinLock (&RefP->SpinLock);
NdisInterlockedDecrement (&RefP->ReferenceCount);
if (RefP->ReferenceCount == 0)
{
rc = TRUE;
NdisSetEvent (&RefP->RefZeroEvent);
}
if ((signed long)RefP->ReferenceCount < 0)
{
ASSERT ( !"Ref Has Gone BELOW ZERO");
}
// NdisReleaseSpinLock (&RefP->SpinLock);
TRACE( TL_V, TM_Ref, ( "<==nicDeReferenceRef, %.2x, RefCount %d", rc, RefP->ReferenceCount ) );
return(rc);
}
VOID
nicInitializeRef(
IN PREF RefP
)
/*++
Routine Description:
Initialize a reference count structure.
Arguments:
RefP - The structure to be initialized.
Return Value:
None.
--*/
{
TRACE( TL_V, TM_Ref, ( "==>nicInitializeRef, %.8x", RefP ) );
RefP->Closing = FALSE;
RefP->ReferenceCount = 1;
// NdisAllocateSpinLock (&RefP->SpinLock);
NdisInitializeEvent (&RefP->RefZeroEvent);
TRACE( TL_V, TM_Ref, ( "<==nicInitializeRef, %.8x", RefP ) );
}
BOOLEAN
nicCloseRef(
IN PREF RefP
)
/*++
Routine Description:
Closes a reference count structure.
Arguments:
RefP - The structure to be closed.
Return Value:
FALSE if it was already closing.
TRUE otherwise.
--*/
{
KIRQL OldIrql;
BOOLEAN rc = TRUE;
TRACE( TL_N, TM_Ref, ( "==>ndisCloseRef, %.8x", RefP ) );
// NdisAcquireSpinLock (&RefP->SpinLock);
if (RefP->Closing)
{
rc = FALSE;
}
else RefP->Closing = TRUE;
// NdisReleaseSpinLock (&RefP->SpinLock);
TRACE( TL_N, TM_Ref, ( "<==ndisCloseRef, %.8x, RefCount %.8x", RefP, RefP->ReferenceCount ) );
return(rc);
}
//
//
// These are self expanatory Pdo Reference functions
// which will be turned into macros once we have functionality
// working
//
BOOLEAN
nicReferenceRemoteNode (
IN REMOTE_NODE *pPdoCb,
IN PCHAR pDebugPrint
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOLEAN bRefClosing = FALSE;
bRefClosing = nicReferenceRef (&pPdoCb->Ref);
TRACE( TL_V, TM_RemRef, ( "**nicReferenceRemoteNode pPdoCb %x, to %d, %s, ret %x ",
pPdoCb, pPdoCb->Ref.ReferenceCount, pDebugPrint, bRefClosing ) );
return bRefClosing ;
}
BOOLEAN
nicDereferenceRemoteNode (
IN REMOTE_NODE *pPdoCb,
IN PCHAR pDebugPrint
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
TRACE( TL_V, TM_RemRef, ( "**nicDereferenceRemoteNode %x to %d , %s",
pPdoCb , pPdoCb->Ref.ReferenceCount -1, pDebugPrint ) );
return nicDereferenceRef (&pPdoCb->Ref);
}
VOID
nicInitalizeRefRemoteNode(
IN REMOTE_NODE *pPdoCb
)
/*++
Routine Description:
Closes Ref on the remote node
Arguments:
IN REMOTE_NODE *pPdoCb - RemoteNode
Return Value:
None
--*/
{
TRACE( TL_N, TM_Ref, ( "**nicinitalizeRefPdoCb pPdoCb %.8x", pPdoCb ) );
nicInitializeRef (&pPdoCb->Ref);
}
BOOLEAN
nicCloseRefRemoteNode(
IN REMOTE_NODE *pPdoCb
)
/*++
Routine Description:
Closes Ref on the remote node
Arguments:
IN REMOTE_NODE *pPdoCb - RemoteNode
Return Value:
Return value of nicCloseRef
--*/
{
TRACE( TL_N, TM_Ref, ( "**nicClosePdoCb pPdoCb %.8x", pPdoCb ) );
return nicCloseRef (&pPdoCb->Ref);
}
NDIS_STATUS
NtStatusToNdisStatus (
NTSTATUS NtStatus
)
/*++
Routine Description:
Dumps the packet , if the appropriate Debuglevels are set
Arguments:
NTSTATUS NtStatus - NtStatus to be converted
Return Value:
NdisStatus - NtStatus' corresponding NdisStatus
--*/
{
NDIS_STATUS NdisStatus;
switch (NtStatus)
{
case STATUS_SUCCESS:
{
NdisStatus = NDIS_STATUS_SUCCESS;
break;
}
case STATUS_UNSUCCESSFUL:
{
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
case STATUS_PENDING:
{
NdisStatus = NDIS_STATUS_PENDING;
break;
}
case STATUS_INVALID_BUFFER_SIZE:
{
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
break;
}
case STATUS_INSUFFICIENT_RESOURCES:
{
NdisStatus = NDIS_STATUS_RESOURCES;
break;
}
case STATUS_INVALID_GENERATION:
{
NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
break;
}
case STATUS_ALREADY_COMMITTED:
{
NdisStatus = NDIS_STATUS_RESOURCE_CONFLICT;
break;
}
case STATUS_DEVICE_BUSY:
{
NdisStatus = NDIS_STATUS_MEDIA_BUSY;
break;
}
case STATUS_INVALID_PARAMETER:
{
NdisStatus = NDIS_STATUS_INVALID_DATA;
break;
}
case STATUS_DEVICE_DATA_ERROR:
{
NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
break;
}
case STATUS_TIMEOUT:
{
NdisStatus = NDIS_STATUS_FAILURE;
break;
}
case STATUS_IO_DEVICE_ERROR:
{
NdisStatus = NDIS_STATUS_NETWORK_UNREACHABLE;
break;
}
default:
{
NdisStatus = NDIS_STATUS_FAILURE;
TRACE( TL_A, TM_Send, ( "Cause: Don't know, INVESTIGATE %x", NtStatus ) );
//ASSERT (0);
}
}
return NdisStatus;
}
VOID
PrintNdisPacket (
ULONG TM_Comp,
PNDIS_PACKET pMyPacket
)
/*++
Routine Description:
Dumps the packet , if the appropriate Debuglevels are set
Arguments:
ULONG TM_Comp = Debug Component
PNDIS_PACKET pMyPacket - Packet to be printed
Return Value:
None
--*/
{
PNDIS_BUFFER pPrintNdisBuffer = pMyPacket->Private.Head;
//
// Print out the complete NdisPacket . Change to DEBUG ONLY
//
while (pPrintNdisBuffer != NULL)
{
PVOID pPrintData = NdisBufferVirtualAddress(pPrintNdisBuffer);
ULONG PrintLength = NdisBufferLength (pPrintNdisBuffer);
TRACE( TL_D, TM_Comp, ( " pNdisbuffer %x, pData %x, Len %x", pPrintNdisBuffer, pPrintData, PrintLength) );
if (pPrintData != NULL)
{
DUMPB (TL_D, TM_Recv, pPrintData, PrintLength);
}
pPrintNdisBuffer = pPrintNdisBuffer->Next;
}
}
VOID
nicAllocatePacket(
OUT PNDIS_STATUS pNdisStatus,
OUT PNDIS_PACKET *ppNdisPacket,
IN PNIC_PACKET_POOL pPacketPool
)
/*++
Routine Description:
Calls the ndis API to allocate a packet. On Win9X calls to allocate packets are serialized
Arguments:
pNdisStatus - pointer to NdisStatus
*ppNdisPacket - Ndis packet Allocated by Ndis,
pPacketPool - packet pool from which the packet is allocated
Return Value:
return value of the call to Ndis
--*/
{
KIRQL OldIrql;
#ifdef Win9X
#if PACKETPOOL_LOCK
KeAcquireSpinLock(&pPacketPool->Lock, &OldIrql);
#endif
#endif
NdisAllocatePacket (pNdisStatus,
ppNdisPacket,
pPacketPool->Handle );
#ifdef Win9X
#if PACKETPOOL_LOCK
KeReleaseSpinLock(&pPacketPool->Lock, OldIrql);
#endif
#endif
if (*pNdisStatus == NDIS_STATUS_SUCCESS)
{
PRSVD pRsvd = NULL;
PINDICATE_RSVD pIndicateRsvd = NULL;
pRsvd =(PRSVD)((*ppNdisPacket)->ProtocolReserved);
pIndicateRsvd = &pRsvd->IndicateRsvd;
pIndicateRsvd->Tag = NIC1394_TAG_ALLOCATED;
NdisInterlockedIncrement (&pPacketPool->AllocatedPackets);
}
else
{
*ppNdisPacket = NULL;
nicIncrementMallocFailure();
}
}
VOID
nicFreePacket(
IN PNDIS_PACKET pNdisPacket,
IN PNIC_PACKET_POOL pPacketPool
)
/*++
Routine Description:
Free the packet and decrements the outstanding Packet count.
All calls are serialized on Win9x
Arguments:
IN PNDIS_PACKET pNdisPacket - Packet to be freed
IN PNIC_PACKET_POOL pPacketPool - PacketPool to which the packet belongs
Return Value:
None
--*/
{
KIRQL OldIrql;
PRSVD pRsvd = NULL;
PINDICATE_RSVD pIndicateRsvd = NULL;
pRsvd =(PRSVD)(pNdisPacket->ProtocolReserved);
pIndicateRsvd = &pRsvd->IndicateRsvd;
pIndicateRsvd->Tag = NIC1394_TAG_FREED;
#ifdef Win9X
#if PACKETPOOL_LOCK
KeAcquireSpinLock(&pPacketPool->Lock, &OldIrql);
#endif
#endif
NdisInterlockedDecrement (&pPacketPool->AllocatedPackets);
NdisFreePacket (pNdisPacket);
#ifdef Win9X
#if PACKETPOOL_LOCK
KeReleaseSpinLock(&pPacketPool->Lock, OldIrql);
#endif
#endif
}
VOID
nicFreePacketPool (
IN PNIC_PACKET_POOL pPacketPool
)
/*++
Routine Description:
frees the packet pool after waiting for the outstanding packet count to go to zero
Arguments:
IN PNIC_PACKET_POOL pPacketPool - PacketPool which is to be freed
Return Value:
None
--*/
{
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
while (NdisPacketPoolUsage (pPacketPool->Handle)!=0)
{
TRACE( TL_V, TM_Cm, ( " Waiting PacketPool %x, AllocatedPackets %x",
pPacketPool->Handle, pPacketPool->AllocatedPackets ) );
NdisMSleep (10000);
}
NdisFreePacketPool (pPacketPool->Handle);
pPacketPool->Handle = NULL;
ASSERT (pPacketPool->AllocatedPackets == 0);
}
VOID
nicAcquireSpinLock (
IN PNIC_SPIN_LOCK pNicSpinLock,
IN PUCHAR FileName,
IN UINT LineNumber
)
/*++
Routine Description:
Acquires a spin lock and if the Dbg, then it will spew out the line and file
Arguments:
NIC_SPIN_LOCK - Lock to be acquired
Return Value:
None
--*/
{
PKTHREAD pThread;
TRACE (TL_V, TM_Lock, ("Lock %x, Acquired by File %s, Line %x" , pNicSpinLock, FileName, LineNumber)) ;
NdisAcquireSpinLock(&(pNicSpinLock->NdisLock));
#if TRACK_LOCKS
pThread = KeGetCurrentThread();
pNicSpinLock->OwnerThread = pThread;
NdisMoveMemory(pNicSpinLock->TouchedByFileName, FileName, LOCK_FILE_NAME_LEN);
pNicSpinLock->TouchedByFileName[LOCK_FILE_NAME_LEN - 1] = 0x0;
pNicSpinLock->TouchedInLineNumber = LineNumber;
pNicSpinLock->IsAcquired++;
#endif
}
VOID
nicReleaseSpinLock (
IN PNIC_SPIN_LOCK pNicSpinLock,
IN PUCHAR FileName,
IN UINT LineNumber
)
/*++
Routine Description:
Release a spin lock and if Dbg is On, then it will spew out the line and file
Arguments:
pNicSpinLock - Lock to be Release
FileName - File Name
LineNumber - Line
Return Value:
None
--*/
{
PKTHREAD pThread;
TRACE (TL_V, TM_Lock, ("Lock %x, Released by File %s, Line %x" , pNicSpinLock, FileName, LineNumber)) ;
#if TRACK_LOCKS
pThread = KeGetCurrentThread();
NdisMoveMemory(pNicSpinLock->TouchedByFileName, FileName, LOCK_FILE_NAME_LEN);
pNicSpinLock->TouchedByFileName[LOCK_FILE_NAME_LEN - 1] = 0x0;
pNicSpinLock->TouchedInLineNumber = LineNumber;
pNicSpinLock->IsAcquired--;
pNicSpinLock->OwnerThread = 0;
#endif
NdisReleaseSpinLock(&(pNicSpinLock->NdisLock));
}
VOID
nicInitializeNicSpinLock (
IN PNIC_SPIN_LOCK pNicSpinLock
)
/*++
Routine Description:
Initializes the lock in the SpinLock
Arguments:
pNicSpinLock - SpinLock
Return Value:
None
--*/
{
NdisAllocateSpinLock (&pNicSpinLock->NdisLock);
}
VOID
nicFreeNicSpinLock (
IN PNIC_SPIN_LOCK pNicSpinLock
)
/*++
Routine Description:
Frees the spinlock
Arguments:
pNicSpinLock - SpinLock
Return Value:
None
--*/
{
ASSERT ((ULONG)pNicSpinLock->NdisLock.SpinLock == 0);
NdisFreeSpinLock (&pNicSpinLock->NdisLock);
}
UINT
nicGetSystemTime(
VOID
)
/*++
Returns system time in seconds.
Since it's in seconds, we won't overflow unless the system has been up
for over
a 100 years :-)
--*/
{
LARGE_INTEGER Time;
NdisGetCurrentSystemTime(&Time);
Time.QuadPart /= 10000000; //100-nanoseconds to seconds.
return Time.LowPart;
}
UINT
nicGetSystemTimeMilliSeconds(
VOID
)
/*++
Returns system time in seconds.
Since it's in seconds, we won't overflow unless the system has been up
for over
a 100 years :-)
--*/
{
LARGE_INTEGER Time;
NdisGetCurrentSystemTime(&Time);
Time.QuadPart /= 10000; //10-nanoseconds to seconds.
return Time.LowPart;
}
ULONG
SwapBytesUlong(
IN ULONG Val)
{
return ((((Val) & 0x000000ff) << 24) | (((Val) & 0x0000ff00) << 8) | (((Val) & 0x00ff0000) >> 8) | (((Val) & 0xff000000) >> 24) );
}
void
nicTimeStamp(
char *szFormatString,
UINT Val
)
/*++
Routine Description:
Execute and print a time stamp
Arguments:
Return Value:
--*/
{
UINT Minutes;
UINT Seconds;
UINT Milliseconds;
LARGE_INTEGER Time;
NdisGetCurrentSystemTime(&Time);
Time.QuadPart /= 10000; //10-nanoseconds to milliseconds.
Milliseconds = Time.LowPart; // don't care about highpart.
Seconds = Milliseconds/1000;
Milliseconds %= 1000;
Minutes = Seconds/60;
Seconds %= 60;
DbgPrint( szFormatString, Minutes, Seconds, Milliseconds, Val);
}
VOID
nicDumpPkt (
IN PNDIS_PACKET pPacket,
CHAR * str
)
{
PNDIS_BUFFER pBuffer;
extern BOOLEAN g_ulNicDumpPacket ;
if ( g_ulNicDumpPacket == FALSE)
{
return ;
}
pBuffer = pPacket->Private.Head;
DbgPrint (str);
DbgPrint ("Packet %p TotLen %x", pPacket, pPacket->Private.TotalLength);
do
{
ULONG Length = nicNdisBufferLength (pBuffer);
PUCHAR pVa = nicNdisBufferVirtualAddress (pBuffer);
DbgPrint ("pBuffer %p, Len %x \n", pBuffer, Length);
Dump( pVa, Length, 0, 1 );
pBuffer = pBuffer->Next;
} while (pBuffer != NULL);
}
VOID
nicDumpMdl (
IN PMDL pMdl,
IN ULONG LengthToPrint,
IN CHAR *str
)
{
ULONG MdlLength ;
PUCHAR pVa;
extern BOOLEAN g_ulNicDumpPacket ;
if ( g_ulNicDumpPacket == FALSE )
{
return;
}
MdlLength = MmGetMdlByteCount(pMdl);
//
// if Length is zero then use MdlLength
//
if (LengthToPrint == 0)
{
LengthToPrint = MdlLength;
}
//
// Check for invalid length
//
if (MdlLength < LengthToPrint)
{
return;
}
pVa = MmGetSystemAddressForMdlSafe(pMdl,LowPagePriority );
if (pVa == NULL)
{
return;
}
DbgPrint (str);
DbgPrint ("pMdl %p, Len %x\n", pMdl, LengthToPrint);
Dump( pVa, LengthToPrint, 0, 1 );
}