397 lines
7.6 KiB
C
397 lines
7.6 KiB
C
// Copyright (c) 1997, Microsoft Corporation, all rights reserved
|
|
// Copyright (c) 1997, Parallel Technologies, Inc., all rights reserved
|
|
//
|
|
// util.c
|
|
// DirectParallel WAN mini-port/call-manager driver
|
|
// General utility routines
|
|
//
|
|
// 01/07/97 Steve Cobb
|
|
// 09/15/97 Jay Lowe, Parallel Technologies, Inc.
|
|
|
|
#include "ptiwan.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Local prototypes (alphabetically)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ULONG
|
|
atoul(
|
|
IN CHAR* pszNumber );
|
|
|
|
VOID
|
|
ReversePsz(
|
|
IN OUT CHAR* psz );
|
|
|
|
VOID
|
|
ultoa(
|
|
IN ULONG ul,
|
|
OUT CHAR* pszBuf );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// General utility routines (alphabetically)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
ClearFlags(
|
|
IN OUT ULONG* pulFlags,
|
|
IN ULONG ulMask )
|
|
|
|
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
|
|
//
|
|
{
|
|
ULONG ulFlags;
|
|
ULONG ulNewFlags;
|
|
|
|
do
|
|
{
|
|
ulFlags = ReadFlags( pulFlags );
|
|
ulNewFlags = ulFlags & ~(ulMask);
|
|
}
|
|
while (InterlockedCompareExchange(
|
|
pulFlags, ulNewFlags, ulFlags ) != (LONG)ulFlags);
|
|
}
|
|
|
|
VOID
|
|
IndicateLinkStatus(
|
|
IN VCCB* pVc )
|
|
|
|
// Indicate new WAN_CO_LINKPARAMS settings for 'pVc' to NDISWAN.
|
|
//
|
|
{
|
|
ADAPTERCB* pAdapter;
|
|
WAN_CO_LINKPARAMS params;
|
|
|
|
pAdapter = pVc->pAdapter;
|
|
|
|
params.TransmitSpeed = pVc->ulConnectBps;
|
|
params.ReceiveSpeed = params.TransmitSpeed;
|
|
params.SendWindow = 1;
|
|
TRACE( TL_N, TM_Mp, ( "NdisMCoIndStatus(LINK) cid=%d bps=%d sw=%d",
|
|
pVc->usCallId, params.TransmitSpeed, params.SendWindow ) );
|
|
NdisMCoIndicateStatus(
|
|
pAdapter->MiniportAdapterHandle,
|
|
pVc->NdisVcHandle,
|
|
NDIS_STATUS_WAN_CO_LINKPARAMS,
|
|
¶ms,
|
|
sizeof(params) );
|
|
TRACE( TL_N, TM_Mp, ( "NdisMCoIndStatus done" ) );
|
|
}
|
|
|
|
ULONG
|
|
ReadFlags(
|
|
IN ULONG* pulFlags )
|
|
|
|
// Read the value of '*pulFlags' as an interlocked operation.
|
|
//
|
|
{
|
|
return InterlockedExchangeAdd( pulFlags, 0 );
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ScheduleWork(
|
|
IN ADAPTERCB* pAdapter,
|
|
IN NDIS_PROC pProc,
|
|
IN PVOID pContext )
|
|
|
|
// Schedules a PASSIVE IRQL callback to routine 'pProc' which will be
|
|
// passed 'pContext'. 'PAdapter' is the adapter control block from which
|
|
// the work item is allocated. This routine takes an adapter reference
|
|
// that should be removed by the called 'pProc'.
|
|
//
|
|
// Returns NDIS_STATUS_SUCCESS or an error code.
|
|
//
|
|
{
|
|
NDIS_STATUS status;
|
|
NDIS_WORK_ITEM* pWork;
|
|
|
|
pWork = ALLOC_NDIS_WORK_ITEM( pAdapter );
|
|
if (!pWork)
|
|
{
|
|
ASSERT( !"Alloc work?" );
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
NdisInitializeWorkItem( pWork, pProc, pContext );
|
|
|
|
ReferenceAdapter( pAdapter );
|
|
status = NdisScheduleWorkItem( pWork );
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ASSERT( !"SchedWork?" );
|
|
FREE_NDIS_WORK_ITEM( pAdapter, pWork );
|
|
DereferenceAdapter( pAdapter );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
SetFlags(
|
|
IN OUT ULONG* pulFlags,
|
|
IN ULONG ulMask )
|
|
|
|
// Set 'ulMask' bits in '*pulFlags' flags as an interlocked operation.
|
|
//
|
|
{
|
|
ULONG ulFlags;
|
|
ULONG ulNewFlags;
|
|
|
|
do
|
|
{
|
|
ulFlags = ReadFlags( pulFlags );
|
|
ulNewFlags = ulFlags | ulMask;
|
|
}
|
|
while (InterlockedCompareExchange(
|
|
pulFlags, ulNewFlags, ulFlags ) != (LONG )ulFlags);
|
|
}
|
|
|
|
|
|
ULONG
|
|
StrCmp(
|
|
IN LPSTR cs,
|
|
IN LPSTR ct,
|
|
ULONG n
|
|
)
|
|
// Return 0 if string cs = string ct for length n
|
|
//
|
|
{
|
|
char ret;
|
|
|
|
while (n--)
|
|
{
|
|
ret = *cs - *ct;
|
|
|
|
if (ret)
|
|
break;
|
|
|
|
cs++;
|
|
ct++;
|
|
}
|
|
|
|
return (ULONG)ret;
|
|
}
|
|
|
|
|
|
ULONG
|
|
StrCmpW(
|
|
IN WCHAR* psz1,
|
|
IN WCHAR* psz2 )
|
|
|
|
// Returns 0 if 'psz1' matches 'psz2'.
|
|
//
|
|
{
|
|
WCHAR pch;
|
|
|
|
pch = (WCHAR )0;
|
|
while (*psz1 && *psz2)
|
|
{
|
|
pch = *psz1 - *psz2;
|
|
if (pch)
|
|
{
|
|
break;
|
|
}
|
|
|
|
psz1++;
|
|
psz2++;
|
|
}
|
|
|
|
return (ULONG )pch;
|
|
}
|
|
|
|
|
|
VOID
|
|
StrCpyW(
|
|
IN WCHAR* psz1,
|
|
IN WCHAR* psz2 )
|
|
|
|
// Copies 'psz2' to 'psz1'.
|
|
//
|
|
{
|
|
while (*psz2)
|
|
{
|
|
*psz1++ = *psz2++;
|
|
}
|
|
|
|
*psz1 = L'\0';
|
|
}
|
|
|
|
|
|
CHAR*
|
|
StrDup(
|
|
IN CHAR* psz )
|
|
|
|
// Return a duplicate of 'psz'. Caller must eventually call FREE_NONPAGED
|
|
// on the returned string.
|
|
//
|
|
{
|
|
return StrDupSized( psz, strlen( psz ), 0 );
|
|
}
|
|
|
|
|
|
CHAR*
|
|
StrDupNdisString(
|
|
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*
|
|
StrDupSized(
|
|
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;
|
|
}
|
|
|
|
|
|
ULONG
|
|
StrLenW(
|
|
IN WCHAR* psz )
|
|
|
|
// Returns number of characters in a null-terminated Unicode string.
|
|
//
|
|
{
|
|
ULONG ul;
|
|
|
|
ul = 0;
|
|
while (*psz++)
|
|
{
|
|
++ul;
|
|
}
|
|
|
|
return ul;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
VOID
|
|
ultoa(
|
|
IN ULONG ul,
|
|
OUT CHAR* pszBuf )
|
|
|
|
// Convert 'ul' to null-terminated string form in caller's 'pszBuf'.
|
|
//
|
|
{
|
|
CHAR* pch;
|
|
|
|
pch = pszBuf;
|
|
do
|
|
{
|
|
*pch++ = (CHAR )((ul % 10) + '0');
|
|
ul /= 10;
|
|
}
|
|
while (ul);
|
|
*pch = '\0';
|
|
|
|
ReversePsz( pszBuf );
|
|
}
|
|
#endif
|