mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1181 lines
29 KiB
1181 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fake.c
|
|
|
|
Abstract:
|
|
|
|
Fake versions of various external calls (ndis, ip...).
|
|
Used for debugging and component testing only.
|
|
|
|
To enable, define ARPDBG_FAKE_APIS in ccdefs.h
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
josephj 03-22-98 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include <precomp.h>
|
|
|
|
|
|
#if ARPDBG_FAKE_APIS
|
|
|
|
//
|
|
// File-specific debugging defaults.
|
|
//
|
|
#define TM_CURRENT TM_FAKE
|
|
|
|
|
|
//=========================================================================
|
|
// L O C A L P R O T O T Y P E S
|
|
//=========================================================================
|
|
|
|
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
#define LOCKROOTOBJ(_pHdr, _pSR) \
|
|
RmWriteLockObject( \
|
|
(_pHdr)->pRootObject, \
|
|
0, \
|
|
(_pSR) \
|
|
)
|
|
#else // !RM_EXTRA_CHECKING
|
|
#define LOCKROOTOBJ(_pHdr, _pSR) \
|
|
RmWriteLockObject( \
|
|
(_pHdr)->pRootObject, \
|
|
(_pSR) \
|
|
)
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
#define UNLOCKROOTOBJ(_pHdr, _pSR) \
|
|
RmUnlockObject( \
|
|
(_pHdr)->pRootObject, \
|
|
(_pSR) \
|
|
)
|
|
|
|
typedef
|
|
VOID
|
|
(*PFN_FAKE_COMPLETIONCALLBACK)(
|
|
struct _FAKETASK *pFTask
|
|
);
|
|
|
|
|
|
// This task structure holds a union of the information required for the completions
|
|
// of the various apis that are being faked.
|
|
//
|
|
typedef struct _FAKETASK
|
|
{
|
|
RM_TASK TskHdr;
|
|
|
|
// Client's context to pass back
|
|
//
|
|
PVOID pClientContext;
|
|
|
|
// Client object the call is associated.
|
|
//
|
|
PRM_OBJECT_HEADER pOwningObject;
|
|
|
|
// The status to report in the asynchronous completion fn.
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
// Milliseconds to delay before calling the async completion fn.
|
|
//
|
|
UINT DelayMs;
|
|
|
|
// Wheather to call the completion fn at DPC or PASSIVE IRQL level.
|
|
//
|
|
INT fDpc;
|
|
|
|
// This is used solely to switch to DPC level when asynchronously
|
|
// calling the completion callback.
|
|
//
|
|
NDIS_SPIN_LOCK NdisLock;
|
|
|
|
// This is used solely to wait DelayMs ms if required.
|
|
//
|
|
NDIS_TIMER Timer;
|
|
|
|
// This is used solely to switch to a different (and PASSIVE) context.
|
|
//
|
|
NDIS_WORK_ITEM WorkItem;
|
|
|
|
// This is used only for fake NdisClMakeCall
|
|
//
|
|
PCO_CALL_PARAMETERS CallParameters;
|
|
|
|
// This is used only for fake NdisCoSendPackets
|
|
//
|
|
PNDIS_PACKET pNdisPacket;
|
|
|
|
// The actual completion callback function;
|
|
//
|
|
PFN_FAKE_COMPLETIONCALLBACK pfnCompletionCallback;
|
|
|
|
} FAKETASK;
|
|
|
|
|
|
VOID
|
|
arpFakeMakeCallCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
);
|
|
|
|
|
|
VOID
|
|
arpFakeCloseCallCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
);
|
|
|
|
|
|
VOID
|
|
arpFakeSendPacketsCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
);
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgAllocateFakeTask(
|
|
IN PRM_OBJECT_HEADER pParentObject,
|
|
IN PFN_RM_TASK_HANDLER pfnHandler,
|
|
IN UINT Timeout,
|
|
IN const char * szDescription,
|
|
OUT PRM_TASK *ppTask,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpDbgFakeTaskDelete(
|
|
PRM_OBJECT_HEADER pObj,
|
|
PRM_STACK_RECORD psr
|
|
);
|
|
|
|
RM_STATIC_OBJECT_INFO
|
|
FakeTasks_StaticInfo =
|
|
{
|
|
0, // TypeUID
|
|
0, // TypeFlags
|
|
"FAKE Task", // TypeName
|
|
0, // Timeout
|
|
|
|
NULL, // pfnCreate
|
|
arpDbgFakeTaskDelete, // pfnDelete
|
|
NULL, // pfnVerifier
|
|
|
|
0, // length of resource table
|
|
NULL // Resource Table
|
|
};
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgFakeCompletionTask(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam, // Unused
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
|
|
//=========================================================================
|
|
// F A K E N D I S E N T R Y P O I N T S
|
|
//=========================================================================
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgFakeNdisClMakeCall(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
OUT PNDIS_HANDLE NdisPartyHandle, OPTIONAL
|
|
IN PRM_OBJECT_HEADER pOwningObject,
|
|
IN PVOID pClientContext,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fake version of NdisClMakeCall.
|
|
|
|
--*/
|
|
{
|
|
ENTER("FakeNdisClMakeCall", 0x3d4195ae)
|
|
NDIS_STATUS Status;
|
|
NDIS_STATUS AsyncStatus;
|
|
UINT DelayMs;
|
|
|
|
DBGMARK(0xced41a61);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
ASSERT(NdisPartyHandle==NULL);
|
|
ASSERT(ProtocolPartyContext==NULL);
|
|
ASSERT(NdisVcHandle != NULL);
|
|
|
|
|
|
do
|
|
{
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
StatusOutcomes[] =
|
|
{
|
|
{NDIS_STATUS_SUCCESS, 1}, // Return NDIS_STATUS_SUCCESS
|
|
{NDIS_STATUS_FAILURE, 1} // Return NDIS_STATUS_FAILURE
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DelayMsOutcomes[] =
|
|
{
|
|
{0, 5}, // Delay 0ms, etc...
|
|
{10, 5},
|
|
{100, 5},
|
|
{1000, 1},
|
|
{10000, 1}
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
AsyncOutcomes[] =
|
|
{
|
|
{TRUE, 1}, // Complete Async
|
|
{FALSE, 1} // Complete Sync
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DpcOutcomes[] =
|
|
{
|
|
{TRUE, 1}, // Complete at DPC level
|
|
{FALSE, 1} // Complete at PASSIVE level
|
|
};
|
|
|
|
FAKETASK *pMCTask;
|
|
|
|
|
|
// We serialize calls to arpGenRandomInt by claiming the root object's
|
|
// lock...
|
|
//
|
|
LOCKROOTOBJ(pOwningObject, pSR);
|
|
|
|
// Get the status we're supposed to return.
|
|
//
|
|
Status =
|
|
AsyncStatus = (NDIS_STATUS) arpGenRandomInt(
|
|
StatusOutcomes,
|
|
ARRAY_LENGTH(StatusOutcomes)
|
|
);
|
|
|
|
// Determine if we're to return synchronously or complete
|
|
// asynchronously...
|
|
//
|
|
if (!arpGenRandomInt(AsyncOutcomes, ARRAY_LENGTH(AsyncOutcomes)))
|
|
{
|
|
// We're to return synchronously.
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We're to complete asynchronously...
|
|
//
|
|
|
|
DelayMs = arpGenRandomInt(
|
|
DelayMsOutcomes,
|
|
ARRAY_LENGTH(DelayMsOutcomes)
|
|
);
|
|
|
|
if (DelayMs == 0)
|
|
{
|
|
// We're to immediately indicatie async completion...
|
|
// (we don't mess with IRQ levels if we're returning here..)
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
ArpCoMakeCallComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
NULL,
|
|
CallParameters
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
// We're to indicate status sometime in the future -- in a different context.
|
|
// Start a task to do this...
|
|
//
|
|
|
|
Status = arpDbgAllocateFakeTask(
|
|
pOwningObject, // pParentObject,
|
|
arpDbgFakeCompletionTask, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task:Fake NdisClMakeCall", // szDescription,
|
|
&(PRM_TASK) pMCTask,
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
// Couldn't allocate task. Call callback right away...
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
ArpCoMakeCallComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
NULL,
|
|
CallParameters
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
|
|
// Initialize pMCTask...
|
|
//
|
|
pMCTask->pClientContext = pClientContext;
|
|
pMCTask->pOwningObject = pOwningObject;
|
|
pMCTask->Status = AsyncStatus;
|
|
pMCTask->DelayMs = DelayMs;
|
|
pMCTask->fDpc = arpGenRandomInt(
|
|
DpcOutcomes,
|
|
ARRAY_LENGTH(DpcOutcomes)
|
|
);
|
|
pMCTask->CallParameters = CallParameters;
|
|
pMCTask->pfnCompletionCallback = arpFakeMakeCallCompletionCallback;
|
|
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
|
|
(void) RmStartTask(
|
|
&pMCTask->TskHdr,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgFakeNdisClCloseCall(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PVOID Buffer OPTIONAL,
|
|
IN UINT Size, OPTIONAL
|
|
IN PRM_OBJECT_HEADER pOwningObject,
|
|
IN PVOID pClientContext,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fake version of NdisClCloseCall.
|
|
|
|
--*/
|
|
{
|
|
ENTER("FakeNdisClCloseCall", 0x7d8bbd3c)
|
|
NDIS_STATUS Status;
|
|
NDIS_STATUS AsyncStatus;
|
|
UINT DelayMs;
|
|
|
|
DBGMARK(0x228fac3a);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
ASSERT(NdisPartyHandle==NULL);
|
|
ASSERT(NdisVcHandle != NULL);
|
|
|
|
|
|
do
|
|
{
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DelayMsOutcomes[] =
|
|
{
|
|
{0, 5}, // Delay 0ms, etc...
|
|
{10, 5},
|
|
{100, 5},
|
|
{1000, 1},
|
|
{10000, 1}
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
AsyncOutcomes[] =
|
|
{
|
|
{TRUE, 1}, // Complete Async
|
|
{FALSE, 1} // Complete Sync
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DpcOutcomes[] =
|
|
{
|
|
{TRUE, 1}, // Complete at DPC level
|
|
{FALSE, 1} // Complete at PASSIVE level
|
|
};
|
|
|
|
FAKETASK *pCCTask;
|
|
|
|
|
|
// We serialize calls to arpGenRandomInt by claiming the root object's
|
|
// lock...
|
|
//
|
|
LOCKROOTOBJ(pOwningObject, pSR);
|
|
|
|
// Get the status we're supposed to return.
|
|
//
|
|
Status =
|
|
AsyncStatus = NDIS_STATUS_SUCCESS; // We never fail this call.
|
|
|
|
// Determine if we're to return synchronously or complete
|
|
// asynchronously...
|
|
//
|
|
if (!arpGenRandomInt(AsyncOutcomes, ARRAY_LENGTH(AsyncOutcomes)))
|
|
{
|
|
// We're to return synchronously.
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We're to complete asynchronously...
|
|
//
|
|
|
|
DelayMs = arpGenRandomInt(
|
|
DelayMsOutcomes,
|
|
ARRAY_LENGTH(DelayMsOutcomes)
|
|
);
|
|
|
|
if (DelayMs == 0)
|
|
{
|
|
// We're to immediately indicatie async completion...
|
|
// (we don't mess with IRQ levels if we're returning here..)
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
ArpCoCloseCallComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
NULL
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
Status = arpDbgAllocateFakeTask(
|
|
pOwningObject, // pParentObject,
|
|
arpDbgFakeCompletionTask, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task:Fake NdisClCloseCall", // szDescription,
|
|
&(PRM_TASK) pCCTask,
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
// Couldn't alloc task; lets call callback right now and return pending.
|
|
//
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
ArpCoCloseCallComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
NULL
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
|
|
// Initialize pCCTask...
|
|
//
|
|
pCCTask->pClientContext = pClientContext;
|
|
pCCTask->pOwningObject = pOwningObject;
|
|
pCCTask->Status = AsyncStatus;
|
|
pCCTask->DelayMs = DelayMs;
|
|
pCCTask->fDpc = arpGenRandomInt(
|
|
DpcOutcomes,
|
|
ARRAY_LENGTH(DpcOutcomes)
|
|
);
|
|
pCCTask->pfnCompletionCallback = arpFakeCloseCallCompletionCallback;
|
|
|
|
UNLOCKROOTOBJ(pOwningObject, pSR);
|
|
|
|
(void) RmStartTask(
|
|
&pCCTask->TskHdr,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
arpDbgFakeNdisCoSendPackets(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets,
|
|
IN PRM_OBJECT_HEADER pOwningObject,
|
|
IN PVOID pClientContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fake version of NdisCoSendPackets.
|
|
|
|
--*/
|
|
{
|
|
ENTER("FakeNdisCoSendPackets", 0x98c6a8aa)
|
|
NDIS_STATUS Status;
|
|
NDIS_STATUS AsyncStatus;
|
|
UINT DelayMs;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
DBGMARK(0x3be1b902);
|
|
ASSERT(NumberOfPackets==1);
|
|
|
|
do
|
|
{
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
StatusOutcomes[] =
|
|
{
|
|
{NDIS_STATUS_SUCCESS, 1}, // Return NDIS_STATUS_SUCCESS
|
|
{NDIS_STATUS_FAILURE, 1} // Return NDIS_STATUS_FAILURE
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DelayMsOutcomes[] =
|
|
{
|
|
{0, 5}, // Delay 0ms, etc...
|
|
{10, 5},
|
|
{100, 5},
|
|
{1000, 1},
|
|
{10000, 1}
|
|
};
|
|
|
|
static
|
|
OUTCOME_PROBABILITY
|
|
DpcOutcomes[] =
|
|
{
|
|
{TRUE, 1}, // Complete at DPC level
|
|
{FALSE, 1} // Complete at PASSIVE level
|
|
};
|
|
|
|
FAKETASK *pSPTask;
|
|
|
|
|
|
// We serialize calls to arpGenRandomInt by claiming the root object's
|
|
// lock...
|
|
//
|
|
LOCKROOTOBJ(pOwningObject, &sr);
|
|
|
|
// Get the status we're supposed to return.
|
|
//
|
|
Status =
|
|
AsyncStatus = (NDIS_STATUS) arpGenRandomInt(
|
|
StatusOutcomes,
|
|
ARRAY_LENGTH(StatusOutcomes)
|
|
);
|
|
|
|
// Compute the delay amount.
|
|
//
|
|
DelayMs = arpGenRandomInt(
|
|
DelayMsOutcomes,
|
|
ARRAY_LENGTH(DelayMsOutcomes)
|
|
);
|
|
if (DelayMs == 0)
|
|
{
|
|
UNLOCKROOTOBJ(pOwningObject, &sr);
|
|
// We're to immediately indicatie async completion...
|
|
// (we don't mess with IRQ levels if we're returning here..)
|
|
//
|
|
ArpCoSendComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
*PacketArray
|
|
);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Nonzero delay -- start task to complete this.
|
|
//
|
|
|
|
Status = arpDbgAllocateFakeTask(
|
|
pOwningObject, // pParentObject,
|
|
arpDbgFakeCompletionTask, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task:Fake NdisCoSendPackets", // szDescription,
|
|
&(PRM_TASK) pSPTask,
|
|
&sr
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
UNLOCKROOTOBJ(pOwningObject, &sr);
|
|
// Fail...
|
|
//
|
|
ArpCoSendComplete(
|
|
AsyncStatus,
|
|
pClientContext,
|
|
*PacketArray
|
|
);
|
|
break;
|
|
}
|
|
|
|
|
|
// Initialize pSPTask...
|
|
//
|
|
pSPTask->pClientContext = pClientContext;
|
|
pSPTask->pOwningObject = pOwningObject;
|
|
pSPTask->Status = AsyncStatus;
|
|
pSPTask->DelayMs = DelayMs;
|
|
pSPTask->fDpc = arpGenRandomInt(
|
|
DpcOutcomes,
|
|
ARRAY_LENGTH(DpcOutcomes)
|
|
);
|
|
pSPTask->pNdisPacket = *PacketArray;
|
|
pSPTask->pfnCompletionCallback = arpFakeSendPacketsCompletionCallback;
|
|
|
|
UNLOCKROOTOBJ(pOwningObject, &sr);
|
|
|
|
(void) RmStartTask(
|
|
&pSPTask->TskHdr,
|
|
0, // UserParam (unused)
|
|
&sr
|
|
);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
} while (FALSE);
|
|
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
EXIT();
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgFakeCompletionTask(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This task is to complete the fake api asynchronously after the
|
|
specified delay, with the specified status, and at the specified
|
|
IRQL (passive/dpc).
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : unused
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
FAKETASK * pFTask = (FAKETASK *) pTask;
|
|
ENTER("FakeCompletionTask", 0xc319c5c2)
|
|
|
|
// Following are the list of pending states for this task.
|
|
//
|
|
enum
|
|
{
|
|
PEND_ResumedAfterDelay,
|
|
PEND_SwitchedToAsync,
|
|
};
|
|
|
|
switch(Code)
|
|
{
|
|
|
|
case RM_TASKOP_START:
|
|
{
|
|
|
|
TR_WARN((
|
|
"START: Delay=%lu; fDpc=%lu; Status=%lu\n",
|
|
pFTask->DelayMs,
|
|
pFTask->fDpc,
|
|
pFTask->Status
|
|
));
|
|
|
|
if (pFTask->DelayMs!=0)
|
|
{
|
|
// Non-zero delay -- let's resume after the delay...
|
|
//
|
|
RmSuspendTask(pTask, PEND_ResumedAfterDelay, pSR);
|
|
|
|
RmResumeTaskDelayed(
|
|
pTask,
|
|
0,
|
|
pFTask->DelayMs,
|
|
&pFTask->Timer,
|
|
pSR
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// No delay is requested. Switch to async right away...
|
|
//
|
|
RmSuspendTask(pTask, PEND_SwitchedToAsync, pSR);
|
|
|
|
RmResumeTaskAsync(
|
|
pTask,
|
|
0,
|
|
&pFTask->WorkItem,
|
|
pSR
|
|
);
|
|
}
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
{
|
|
|
|
switch(RM_PEND_CODE(pTask))
|
|
{
|
|
case PEND_ResumedAfterDelay:
|
|
{
|
|
// We've waited around for pFTask->DelayMs ms; Now
|
|
// switch to passive...
|
|
//
|
|
RmSuspendTask(pTask, PEND_SwitchedToAsync, pSR);
|
|
|
|
RmResumeTaskAsync(
|
|
pTask,
|
|
0,
|
|
&pFTask->WorkItem,
|
|
pSR
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
break;
|
|
|
|
case PEND_SwitchedToAsync:
|
|
{
|
|
//
|
|
// We should now be at PASSIVE IRQL.
|
|
// Call the completion routine either at DPC or PASSIVE irql.
|
|
//
|
|
|
|
if (pFTask->fDpc)
|
|
{
|
|
// We need to call the routine at DPC level.
|
|
//
|
|
NdisAllocateSpinLock(&pFTask->NdisLock);
|
|
NdisAcquireSpinLock(&pFTask->NdisLock);
|
|
}
|
|
|
|
// Call the completion routine.
|
|
//
|
|
pFTask->pfnCompletionCallback(pFTask);
|
|
|
|
// If required, release the lock we held earlier.
|
|
//
|
|
if (pFTask->fDpc)
|
|
{
|
|
NdisReleaseSpinLock(&pFTask->NdisLock);
|
|
}
|
|
Status = pFTask->Status;
|
|
|
|
} // end case PEND_OnStart
|
|
break;
|
|
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown pend op", pTask);
|
|
}
|
|
break;
|
|
|
|
|
|
} // end switch(RM_PEND_CODE(pTask))
|
|
|
|
} // case RM_TASKOP_PENDCOMPLETE
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
{
|
|
Status = (NDIS_STATUS) UserParam;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unexpected task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
arpDbgAllocateFakeTask(
|
|
IN PRM_OBJECT_HEADER pParentObject,
|
|
IN PFN_RM_TASK_HANDLER pfnHandler,
|
|
IN UINT Timeout,
|
|
IN const char * szDescription,
|
|
OUT PRM_TASK *ppTask,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and initializes a task of subtype FAKETASK.
|
|
|
|
Arguments:
|
|
|
|
pParentObject - Object that is to be the parent of the allocated task.
|
|
pfnHandler - The task handler for the task.
|
|
Timeout - Unused.
|
|
szDescription - Text describing this task.
|
|
ppTask - Place to store pointer to the new task.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if we could allocate and initialize the task.
|
|
NDIS_STATUS_RESOURCES otherwise
|
|
--*/
|
|
{
|
|
FAKETASK *pFTask;
|
|
NDIS_STATUS Status;
|
|
|
|
ARP_ALLOCSTRUCT(pFTask, MTAG_DBGINFO);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
*ppTask = NULL;
|
|
|
|
if (pFTask != NULL)
|
|
{
|
|
|
|
RmInitializeTask(
|
|
&(pFTask->TskHdr),
|
|
pParentObject,
|
|
pfnHandler,
|
|
&FakeTasks_StaticInfo,
|
|
szDescription,
|
|
Timeout,
|
|
pSR
|
|
);
|
|
*ppTask = &(pFTask->TskHdr);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
arpDbgFakeTaskDelete (
|
|
PRM_OBJECT_HEADER pObj,
|
|
PRM_STACK_RECORD psr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Actually free the specified task.
|
|
|
|
Arguments:
|
|
|
|
pObj - Actually the task to be freed.
|
|
|
|
--*/
|
|
{
|
|
ARP_FREE(pObj);
|
|
}
|
|
|
|
|
|
INT
|
|
arpGenRandomInt(
|
|
OUTCOME_PROBABILITY *rgOutcomes,
|
|
UINT cOutcomes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a new sample given the specified probability distribution.
|
|
|
|
|
|
Arguments:
|
|
|
|
rgOutcomes - Array of outcomes from which to select the random
|
|
sample.
|
|
cOutcomes - Number of elements in the above array.
|
|
|
|
Return Value:
|
|
|
|
Random integer
|
|
|
|
--*/
|
|
{
|
|
ULONG u, sum, partsum;
|
|
OUTCOME_PROBABILITY *pOp, *pOpEnd;
|
|
|
|
// Get a nicely-random number.
|
|
//
|
|
u = ran1x();
|
|
|
|
// Run through weights, computing the sum of weights...
|
|
//
|
|
pOp = pOpEnd = rgOutcomes;
|
|
pOpEnd += cOutcomes;
|
|
sum=0;
|
|
for(; pOp<pOpEnd; pOp++)
|
|
{
|
|
sum += pOp->Weight;
|
|
}
|
|
|
|
// It's really meaningless to pass in a pPD with zero sum of weights.
|
|
// We return 0 in this case.
|
|
//
|
|
if (sum == 0) return 0; // EARLY RETURN
|
|
|
|
// Make u range from 0..sum-1 inclusive
|
|
//
|
|
u ^= u>>16; // Get more randomness in the lower 16 bits for mod below...
|
|
u %= sum;
|
|
|
|
// Now go through the array of outcomes, computing the partial sum (partsum)
|
|
// of weigths, and picking the FIRST outcome at array position X such that
|
|
// u < partsum.
|
|
//
|
|
partsum=0;
|
|
pOp = pOpEnd = rgOutcomes;
|
|
pOpEnd += cOutcomes;
|
|
for(; pOp<pOpEnd; pOp++)
|
|
{
|
|
partsum += pOp->Weight;
|
|
if (u < partsum)
|
|
{
|
|
break; // Found it!
|
|
}
|
|
}
|
|
|
|
ASSERT(pOp<pOpEnd);
|
|
|
|
return pOp->Outcome;
|
|
}
|
|
|
|
|
|
static long g_idum;
|
|
|
|
unsigned long ran1x(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closely based on ran1() from "Numerical Recipes in C." ISBN 0 521 43108 5
|
|
(except that it returns unsigned long instead of float, and uses g_idum
|
|
instead of input arg long *idum).
|
|
|
|
Pretty uniform and uncorrelated from sample to sample; also individual bits are
|
|
pretty random. We need these properties.
|
|
|
|
Return Value:
|
|
|
|
Random unsigned integer.
|
|
|
|
--*/
|
|
{
|
|
#define IA 16807
|
|
#define IM RAN1X_MAX
|
|
#define IQ 127773
|
|
#define IR 2836
|
|
#define NTAB 32
|
|
#define NDIV (1+(IM-1)/NTAB)
|
|
|
|
int j;
|
|
long k;
|
|
static long iy=0;
|
|
static long iv[NTAB];
|
|
|
|
if (g_idum <= 0 || !iy)
|
|
{
|
|
//
|
|
// Initialization code... (I'm not really sure if iy or g_idum can
|
|
// go to zero in the course of operation, so I'm leaving this
|
|
// initialization code here instead of moving it to sranx1x).
|
|
//
|
|
|
|
if (-g_idum < 1)
|
|
{
|
|
g_idum = 1;
|
|
}
|
|
else
|
|
{
|
|
g_idum = -g_idum;
|
|
}
|
|
for (j=NTAB+7;j>=0;j--)
|
|
{
|
|
k = g_idum/IQ;
|
|
g_idum = IA*(g_idum-k*IQ)-IR*k;
|
|
if (g_idum<0)
|
|
{
|
|
g_idum += IM;
|
|
}
|
|
if (j<NTAB)
|
|
{
|
|
iv[j] = g_idum;
|
|
}
|
|
}
|
|
iy=iv[0];
|
|
}
|
|
|
|
k=g_idum/IQ;
|
|
g_idum=IA*(g_idum-k*IQ)-IR*k;
|
|
if (g_idum<0)
|
|
{
|
|
g_idum += IM;
|
|
}
|
|
j = iy/NDIV;
|
|
iy = iv[j];
|
|
iv[j] = g_idum;
|
|
|
|
// iy ranges from 1 .. (IM-1)
|
|
//
|
|
return (unsigned long) iy;
|
|
}
|
|
|
|
void
|
|
sran1x(
|
|
unsigned long seed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the seed used by ran1x.
|
|
|
|
--*/
|
|
{
|
|
g_idum = (long) seed;
|
|
|
|
//
|
|
// Make sure the seed is -ve, to trigger ran1x initialization code above.
|
|
//
|
|
|
|
if (g_idum > 0)
|
|
{
|
|
g_idum = -g_idum;
|
|
}
|
|
if (g_idum==0)
|
|
{
|
|
g_idum = -1;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
arpFakeMakeCallCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls ARP's makecall completion callback.
|
|
|
|
Arguments:
|
|
|
|
pFTask - Task in whose context this callback is to be made. The task
|
|
contains information used in calling the makecall completion
|
|
callback.
|
|
--*/
|
|
{
|
|
// Call the make call completion routine.
|
|
//
|
|
ArpCoMakeCallComplete(
|
|
pFTask->Status,
|
|
(NDIS_HANDLE) pFTask->pClientContext,
|
|
NULL,
|
|
pFTask->CallParameters
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpFakeCloseCallCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls ARP's closecall completion callback.
|
|
|
|
Arguments:
|
|
|
|
pFTask - Task in whose context this callback is to be made. The task
|
|
contains information used in calling the closecall completion
|
|
callback.
|
|
--*/
|
|
{
|
|
ArpCoCloseCallComplete(
|
|
pFTask->Status,
|
|
(NDIS_HANDLE) pFTask->pClientContext,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpFakeSendPacketsCompletionCallback(
|
|
struct _FAKETASK *pFTask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls ARP's cosendpackets completion callback.
|
|
|
|
Arguments:
|
|
|
|
pFTask - Task in whose context this callback is to be made. The task
|
|
contains information used in calling the cosendpackets completion
|
|
callback.
|
|
--*/
|
|
{
|
|
ArpCoSendComplete(
|
|
pFTask->Status,
|
|
(NDIS_HANDLE) pFTask->pClientContext,
|
|
pFTask->pNdisPacket
|
|
);
|
|
}
|
|
|
|
#endif // ARPDBG_FAKE_APIS
|