Source code of Windows XP (NT5)
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

/*++
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